OLD | NEW |
| (Empty) |
1 /* libs/graphics/sgl/SkString.cpp | |
2 ** | |
3 ** Copyright 2006, The Android Open Source Project | |
4 ** | |
5 ** Licensed under the Apache License, Version 2.0 (the "License"); | |
6 ** you may not use this file except in compliance with the License. | |
7 ** You may obtain a copy of the License at | |
8 ** | |
9 ** http://www.apache.org/licenses/LICENSE-2.0 | |
10 ** | |
11 ** Unless required by applicable law or agreed to in writing, software | |
12 ** distributed under the License is distributed on an "AS IS" BASIS, | |
13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
14 ** See the License for the specific language governing permissions and | |
15 ** limitations under the License. | |
16 */ | |
17 | |
18 #include "SkString.h" | |
19 #include "SkFixed.h" | |
20 #include "SkUtils.h" | |
21 #include <stdarg.h> | |
22 | |
23 bool SkStrStartsWith(const char string[], const char prefix[]) | |
24 { | |
25 SkASSERT(string); | |
26 SkASSERT(prefix); | |
27 return !strncmp(string, prefix, strlen(prefix)); | |
28 } | |
29 | |
30 bool SkStrEndsWith(const char string[], const char suffix[]) | |
31 { | |
32 SkASSERT(string); | |
33 SkASSERT(suffix); | |
34 size_t strLen = strlen(string); | |
35 size_t suffixLen = strlen(suffix); | |
36 return strLen >= suffixLen && | |
37 !strncmp(string + strLen - suffixLen, suffix, suffixLen); | |
38 } | |
39 | |
40 int SkStrStartsWithOneOf(const char string[], const char prefixes[]) | |
41 { | |
42 int index = 0; | |
43 do { | |
44 const char* limit = strchr(prefixes, '\0'); | |
45 if (!strncmp(string, prefixes, limit - prefixes)) | |
46 return index; | |
47 prefixes = limit + 1; | |
48 index++; | |
49 } while (prefixes[0]); | |
50 return -1; | |
51 } | |
52 | |
53 char* SkStrAppendS32(char string[], int32_t dec) | |
54 { | |
55 SkDEBUGCODE(char* start = string;) | |
56 | |
57 char buffer[SkStrAppendS32_MaxSize]; | |
58 char* p = buffer + sizeof(buffer); | |
59 bool neg = false; | |
60 | |
61 if (dec < 0) | |
62 { | |
63 neg = true; | |
64 dec = -dec; | |
65 } | |
66 do { | |
67 *--p = SkToU8('0' + dec % 10); | |
68 dec /= 10; | |
69 } while (dec != 0); | |
70 if (neg) | |
71 *--p = '-'; | |
72 | |
73 SkASSERT(p >= buffer); | |
74 char* stop = buffer + sizeof(buffer); | |
75 while (p < stop) | |
76 *string++ = *p++; | |
77 | |
78 SkASSERT(string - start <= SkStrAppendS32_MaxSize); | |
79 return string; | |
80 } | |
81 | |
82 char* SkStrAppendScalar(char string[], SkScalar value) | |
83 { | |
84 SkDEBUGCODE(char* start = string;) | |
85 | |
86 SkFixed x = SkScalarToFixed(value); | |
87 | |
88 if (x < 0) | |
89 { | |
90 *string++ = '-'; | |
91 x = -x; | |
92 } | |
93 | |
94 unsigned frac = x & 0xFFFF; | |
95 x >>= 16; | |
96 if (frac == 0xFFFF) // need to do this to "round up", since 65535/65536 is c
loser to 1 than to .9999 | |
97 { | |
98 x += 1; | |
99 frac = 0; | |
100 } | |
101 string = SkStrAppendS32(string, x); | |
102 | |
103 // now handle the fractional part (if any) | |
104 if (frac) | |
105 { | |
106 static const uint16_t gTens[] = { 1000, 100, 10, 1 }; | |
107 const uint16_t* tens = gTens; | |
108 | |
109 x = SkFixedRound(frac * 10000); | |
110 SkASSERT(x <= 10000); | |
111 if (x == 10000) { | |
112 x -= 1; | |
113 } | |
114 *string++ = '.'; | |
115 do { | |
116 unsigned powerOfTen = *tens++; | |
117 *string++ = SkToU8('0' + x / powerOfTen); | |
118 x %= powerOfTen; | |
119 } while (x != 0); | |
120 } | |
121 | |
122 SkASSERT(string - start <= SkStrAppendScalar_MaxSize); | |
123 return string; | |
124 } | |
125 | |
126 ////////////////////////////////////////////////////////////////////////////////
//// | |
127 | |
128 #define kMaxRefCnt_SkString SK_MaxU16 | |
129 | |
130 // the 3 values are [length] [refcnt] [terminating zero data] | |
131 const SkString::Rec SkString::gEmptyRec = { 0, 0, 0 }; | |
132 | |
133 #define SizeOfRec() (gEmptyRec.data() - (const char*)&gEmptyRec) | |
134 | |
135 SkString::Rec* SkString::AllocRec(const char text[], U16CPU len) | |
136 { | |
137 Rec* rec; | |
138 | |
139 if (len == 0) | |
140 rec = const_cast<Rec*>(&gEmptyRec); | |
141 else | |
142 { | |
143 // add 1 for terminating 0, then align4 so we can have some slop when gr
owing the string | |
144 rec = (Rec*)sk_malloc_throw(SizeOfRec() + SkAlign4(len + 1)); | |
145 rec->fLength = SkToU16(len); | |
146 rec->fRefCnt = 1; | |
147 if (text) | |
148 memcpy(rec->data(), text, len); | |
149 rec->data()[len] = 0; | |
150 } | |
151 return rec; | |
152 } | |
153 | |
154 SkString::Rec* SkString::RefRec(Rec* src) | |
155 { | |
156 if (src != &gEmptyRec) | |
157 { | |
158 if (src->fRefCnt == kMaxRefCnt_SkString) { | |
159 src = AllocRec(src->data(), src->fLength); | |
160 } else | |
161 src->fRefCnt += 1; | |
162 } | |
163 return src; | |
164 } | |
165 | |
166 #ifdef SK_DEBUG | |
167 void SkString::validate() const | |
168 { | |
169 // make sure know one has written over our global | |
170 SkASSERT(gEmptyRec.fLength == 0); | |
171 SkASSERT(gEmptyRec.fRefCnt == 0); | |
172 SkASSERT(gEmptyRec.data()[0] == 0); | |
173 | |
174 if (fRec != &gEmptyRec) | |
175 { | |
176 SkASSERT(fRec->fLength > 0); | |
177 SkASSERT(fRec->fRefCnt > 0); | |
178 SkASSERT(fRec->data()[fRec->fLength] == 0); | |
179 } | |
180 SkASSERT(fStr == c_str()); | |
181 } | |
182 #endif | |
183 | |
184 /////////////////////////////////////////////////////////////////////// | |
185 | |
186 SkString::SkString() : fRec(const_cast<Rec*>(&gEmptyRec)) { | |
187 #ifdef SK_DEBUG | |
188 fStr = fRec->data(); | |
189 #endif | |
190 } | |
191 | |
192 SkString::SkString(size_t len) | |
193 { | |
194 SkASSERT(SkToU16(len) == len); // can't handle larger than 64K | |
195 | |
196 fRec = AllocRec(NULL, (U16CPU)len); | |
197 #ifdef SK_DEBUG | |
198 fStr = fRec->data(); | |
199 #endif | |
200 } | |
201 | |
202 SkString::SkString(const char text[]) | |
203 { | |
204 size_t len = text ? strlen(text) : 0; | |
205 | |
206 fRec = AllocRec(text, (U16CPU)len); | |
207 #ifdef SK_DEBUG | |
208 fStr = fRec->data(); | |
209 #endif | |
210 } | |
211 | |
212 SkString::SkString(const char text[], size_t len) | |
213 { | |
214 fRec = AllocRec(text, (U16CPU)len); | |
215 #ifdef SK_DEBUG | |
216 fStr = fRec->data(); | |
217 #endif | |
218 } | |
219 | |
220 SkString::SkString(const SkString& src) | |
221 { | |
222 src.validate(); | |
223 | |
224 fRec = RefRec(src.fRec); | |
225 #ifdef SK_DEBUG | |
226 fStr = fRec->data(); | |
227 #endif | |
228 } | |
229 | |
230 SkString::~SkString() | |
231 { | |
232 this->validate(); | |
233 | |
234 if (fRec->fLength) | |
235 { | |
236 SkASSERT(fRec->fRefCnt > 0); | |
237 if (--fRec->fRefCnt == 0) | |
238 sk_free(fRec); | |
239 } | |
240 } | |
241 | |
242 bool SkString::equals(const SkString& src) const | |
243 { | |
244 return fRec == src.fRec || this->equals(src.c_str(), src.size()); | |
245 } | |
246 | |
247 bool SkString::equals(const char text[]) const | |
248 { | |
249 return this->equals(text, text ? strlen(text) : 0); | |
250 } | |
251 | |
252 bool SkString::equals(const char text[], size_t len) const | |
253 { | |
254 SkASSERT(len == 0 || text != NULL); | |
255 | |
256 return fRec->fLength == len && !memcmp(fRec->data(), text, len); | |
257 } | |
258 | |
259 SkString& SkString::operator=(const SkString& src) | |
260 { | |
261 this->validate(); | |
262 | |
263 if (fRec != src.fRec) | |
264 { | |
265 SkString tmp(src); | |
266 this->swap(tmp); | |
267 } | |
268 return *this; | |
269 } | |
270 | |
271 void SkString::reset() | |
272 { | |
273 this->validate(); | |
274 | |
275 if (fRec->fLength) | |
276 { | |
277 SkASSERT(fRec->fRefCnt > 0); | |
278 if (--fRec->fRefCnt == 0) | |
279 sk_free(fRec); | |
280 } | |
281 | |
282 fRec = const_cast<Rec*>(&gEmptyRec); | |
283 #ifdef SK_DEBUG | |
284 fStr = fRec->data(); | |
285 #endif | |
286 } | |
287 | |
288 char* SkString::writable_str() | |
289 { | |
290 this->validate(); | |
291 | |
292 if (fRec->fLength) | |
293 { | |
294 if (fRec->fRefCnt > 1) | |
295 { | |
296 fRec->fRefCnt -= 1; | |
297 fRec = AllocRec(fRec->data(), fRec->fLength); | |
298 #ifdef SK_DEBUG | |
299 fStr = fRec->data(); | |
300 #endif | |
301 } | |
302 } | |
303 return fRec->data(); | |
304 } | |
305 | |
306 void SkString::set(const char text[]) | |
307 { | |
308 this->set(text, text ? strlen(text) : 0); | |
309 } | |
310 | |
311 void SkString::set(const char text[], size_t len) | |
312 { | |
313 if (len == 0) | |
314 this->reset(); | |
315 else if (fRec->fRefCnt == 1 && len <= fRec->fLength) // should we resize
if len <<<< fLength, to save RAM? (e.g. len < (fLength>>1)) | |
316 { | |
317 // just use less of the buffer without allocating a smaller one | |
318 char* p = this->writable_str(); | |
319 if (text) | |
320 memcpy(p, text, len); | |
321 p[len] = 0; | |
322 fRec->fLength = SkToU16(len); | |
323 } | |
324 else if (fRec->fRefCnt == 1 && ((unsigned)fRec->fLength >> 2) == (len >> 2)) | |
325 { | |
326 // we have spare room in the current allocation, so don't alloc a larger
one | |
327 char* p = this->writable_str(); | |
328 if (text) | |
329 memcpy(p, text, len); | |
330 p[len] = 0; | |
331 fRec->fLength = SkToU16(len); | |
332 } | |
333 else | |
334 { | |
335 SkString tmp(text, len); | |
336 this->swap(tmp); | |
337 } | |
338 } | |
339 | |
340 void SkString::setUTF16(const uint16_t src[]) | |
341 { | |
342 int count = 0; | |
343 | |
344 while (src[count]) | |
345 count += 1; | |
346 setUTF16(src, count); | |
347 } | |
348 | |
349 void SkString::setUTF16(const uint16_t src[], size_t count) | |
350 { | |
351 if (count == 0) | |
352 this->reset(); | |
353 else if (count <= fRec->fLength) // should we resize if len <<<< fLength,
to save RAM? (e.g. len < (fLength>>1)) | |
354 { | |
355 if (count < fRec->fLength) | |
356 this->resize(count); | |
357 char* p = this->writable_str(); | |
358 for (size_t i = 0; i < count; i++) | |
359 p[i] = SkToU8(src[i]); | |
360 p[count] = 0; | |
361 } | |
362 else | |
363 { | |
364 SkString tmp(count); // puts a null terminator at the end of the stri
ng | |
365 char* p = tmp.writable_str(); | |
366 | |
367 for (size_t i = 0; i < count; i++) | |
368 p[i] = SkToU8(src[i]); | |
369 | |
370 this->swap(tmp); | |
371 } | |
372 } | |
373 | |
374 void SkString::insert(size_t offset, const char text[]) | |
375 { | |
376 this->insert(offset, text, text ? strlen(text) : 0); | |
377 } | |
378 | |
379 void SkString::insert(size_t offset, const char text[], size_t len) | |
380 { | |
381 if (len) | |
382 { | |
383 size_t length = fRec->fLength; | |
384 if (offset > length) | |
385 offset = length; | |
386 | |
387 /* If we're the only owner, and we have room in our allocation for the
insert, | |
388 do it in place, rather than allocating a new buffer. | |
389 | |
390 To know we have room, compare the allocated sizes | |
391 beforeAlloc = SkAlign4(length + 1) | |
392 afterAlloc = SkAligh4(length + 1 + len) | |
393 but SkAlign4(x) is (x + 3) >> 2 << 2 | |
394 which is equivalent for testing to (length + 1 + 3) >> 2 == (length
+ 1 + 3 + len) >> 2 | |
395 and we can then eliminate the +1+3 since that doesn't affec the answ
er | |
396 */ | |
397 if (fRec->fRefCnt == 1 && (length >> 2) == ((length + len) >> 2)) | |
398 { | |
399 char* dst = this->writable_str(); | |
400 | |
401 if (offset < length) | |
402 memmove(dst + offset + len, dst + offset, length - offset); | |
403 memcpy(dst + offset, text, len); | |
404 | |
405 dst[length + len] = 0; | |
406 fRec->fLength = SkToU16(length + len); | |
407 } | |
408 else | |
409 { | |
410 /* Seems we should use realloc here, since that is safe if it fails | |
411 (we have the original data), and might be faster than alloc/copy
/free. | |
412 */ | |
413 SkString tmp(fRec->fLength + len); | |
414 char* dst = tmp.writable_str(); | |
415 | |
416 if (offset > 0) | |
417 memcpy(dst, fRec->data(), offset); | |
418 memcpy(dst + offset, text, len); | |
419 if (offset < fRec->fLength) | |
420 memcpy(dst + offset + len, fRec->data() + offset, fRec->fLength
- offset); | |
421 | |
422 this->swap(tmp); | |
423 } | |
424 } | |
425 } | |
426 | |
427 void SkString::insertUnichar(size_t offset, SkUnichar uni) | |
428 { | |
429 char buffer[kMaxBytesInUTF8Sequence]; | |
430 size_t len = SkUTF8_FromUnichar(uni, buffer); | |
431 | |
432 if (len) | |
433 this->insert(offset, buffer, len); | |
434 } | |
435 | |
436 void SkString::insertS32(size_t offset, int32_t dec) | |
437 { | |
438 char buffer[SkStrAppendS32_MaxSize]; | |
439 char* stop = SkStrAppendS32(buffer, dec); | |
440 this->insert(offset, buffer, stop - buffer); | |
441 } | |
442 | |
443 void SkString::insertHex(size_t offset, uint32_t hex, int minDigits) | |
444 { | |
445 minDigits = SkPin32(minDigits, 0, 8); | |
446 | |
447 static const char gHex[] = "0123456789ABCDEF"; | |
448 | |
449 char buffer[8]; | |
450 char* p = buffer + sizeof(buffer); | |
451 | |
452 do { | |
453 *--p = gHex[hex & 0xF]; | |
454 hex >>= 4; | |
455 minDigits -= 1; | |
456 } while (hex != 0); | |
457 while (--minDigits >= 0) | |
458 *--p = '0'; | |
459 | |
460 SkASSERT(p >= buffer); | |
461 this->insert(offset, p, buffer + sizeof(buffer) - p); | |
462 } | |
463 | |
464 void SkString::insertScalar(size_t offset, SkScalar value) | |
465 { | |
466 char buffer[SkStrAppendScalar_MaxSize]; | |
467 char* stop = SkStrAppendScalar(buffer, value); | |
468 this->insert(offset, buffer, stop - buffer); | |
469 } | |
470 | |
471 /////////////////////////////////////////////////////////////////////////// | |
472 | |
473 //#include <stdarg.h> | |
474 #if defined(SK_BUILD_FOR_WIN) || defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_F
OR_UNIX) | |
475 #include <stdio.h> | |
476 #endif | |
477 | |
478 void SkString::printf(const char format[], ...) | |
479 { | |
480 static const size_t kBufferSize = 100; | |
481 | |
482 char buffer[kBufferSize + 1]; | |
483 | |
484 #ifdef SK_BUILD_FOR_WIN | |
485 va_list args; | |
486 va_start(args, format); | |
487 _vsnprintf(buffer, kBufferSize, format, args); | |
488 va_end(args); | |
489 #elif defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_UNIX) | |
490 va_list args; | |
491 va_start(args, format); | |
492 vsnprintf(buffer, kBufferSize, format, args); | |
493 va_end(args); | |
494 #else | |
495 buffer[0] = 0; | |
496 #endif | |
497 | |
498 this->set(buffer, strlen(buffer)); | |
499 } | |
500 | |
501 /////////////////////////////////////////////////////////////////////////// | |
502 | |
503 void SkString::remove(size_t offset, size_t length) | |
504 { | |
505 size_t size = this->size(); | |
506 | |
507 if (offset < size) | |
508 { | |
509 if (offset + length > size) | |
510 length = size - offset; | |
511 if (length > 0) | |
512 { | |
513 SkASSERT(size > length); | |
514 SkString tmp(size - length); | |
515 char* dst = tmp.writable_str(); | |
516 const char* src = this->c_str(); | |
517 | |
518 if (offset) | |
519 { | |
520 SkASSERT(offset <= tmp.size()); | |
521 memcpy(dst, src, offset); | |
522 } | |
523 size_t tail = size - offset - length; | |
524 SkASSERT((int32_t)tail >= 0); | |
525 if (tail) | |
526 { | |
527 // SkASSERT(offset + length <= tmp.size()); | |
528 memcpy(dst + offset, src + offset + length, tail); | |
529 } | |
530 SkASSERT(dst[tmp.size()] == 0); | |
531 this->swap(tmp); | |
532 } | |
533 } | |
534 } | |
535 | |
536 void SkString::swap(SkString& other) | |
537 { | |
538 this->validate(); | |
539 other.validate(); | |
540 | |
541 SkTSwap<Rec*>(fRec, other.fRec); | |
542 #ifdef SK_DEBUG | |
543 SkTSwap<const char*>(fStr, other.fStr); | |
544 #endif | |
545 } | |
546 | |
547 ////////////////////////////////////////////////////////////////////////////////
/ | |
548 | |
549 SkAutoUCS2::SkAutoUCS2(const char utf8[]) | |
550 { | |
551 size_t len = strlen(utf8); | |
552 fUCS2 = (uint16_t*)sk_malloc_throw((len + 1) * sizeof(uint16_t)); | |
553 | |
554 uint16_t* dst = fUCS2; | |
555 for (;;) | |
556 { | |
557 SkUnichar uni = SkUTF8_NextUnichar(&utf8); | |
558 *dst++ = SkToU16(uni); | |
559 if (uni == 0) | |
560 break; | |
561 } | |
562 fCount = (int)(dst - fUCS2); | |
563 } | |
564 | |
565 SkAutoUCS2::~SkAutoUCS2() | |
566 { | |
567 delete[] fUCS2; | |
568 } | |
569 | |
570 ////////////////////////////////////////////////////////////////////////////////
/ | |
571 ////////////////////////////////////////////////////////////////////////////////
/ | |
572 | |
573 #ifdef SK_DEBUG | |
574 | |
575 void SkString::UnitTest() | |
576 { | |
577 #ifdef SK_SUPPORT_UNITTEST | |
578 SkString a; | |
579 SkString b((size_t)0); | |
580 SkString c(""); | |
581 SkString d(NULL, 0); | |
582 | |
583 SkASSERT(a.isEmpty()); | |
584 SkASSERT(a == b && a == c && a == d); | |
585 | |
586 a.set("hello"); | |
587 b.set("hellox", 5); | |
588 c.set(a); | |
589 d.resize(5); | |
590 memcpy(d.writable_str(), "helloz", 5); | |
591 | |
592 SkASSERT(!a.isEmpty()); | |
593 SkASSERT(a.size() == 5); | |
594 SkASSERT(a == b && a == c && a == d); | |
595 SkASSERT(a.equals("hello", 5)); | |
596 SkASSERT(a.equals("hello")); | |
597 SkASSERT(!a.equals("help")); | |
598 | |
599 SkString e(a); | |
600 SkString f("hello"); | |
601 SkString g("helloz", 5); | |
602 | |
603 SkASSERT(a == e && a == f && a == g); | |
604 | |
605 b.set("world"); | |
606 c = b; | |
607 SkASSERT(a != b && a != c && b == c); | |
608 | |
609 a.append(" world"); | |
610 e.append("worldz", 5); | |
611 e.insert(5, " "); | |
612 f.set("world"); | |
613 f.prepend("hello "); | |
614 SkASSERT(a.equals("hello world") && a == e && a == f); | |
615 | |
616 a.reset(); | |
617 b.resize(0); | |
618 SkASSERT(a.isEmpty() && b.isEmpty() && a == b); | |
619 | |
620 a.set("a"); | |
621 a.set("ab"); | |
622 a.set("abc"); | |
623 a.set("abcd"); | |
624 #endif | |
625 } | |
626 | |
627 #endif | |
628 | |
OLD | NEW |