Line data Source code
1 :
2 : /*
3 : * Copyright 2006 The Android Open Source Project
4 : *
5 : * Use of this source code is governed by a BSD-style license that can be
6 : * found in the LICENSE file.
7 : */
8 :
9 :
10 : #ifndef SkString_DEFINED
11 : #define SkString_DEFINED
12 :
13 : #include "../private/SkTArray.h"
14 : #include "SkScalar.h"
15 :
16 : #include <stdarg.h>
17 :
18 : /* Some helper functions for C strings
19 : */
20 :
21 0 : static bool SkStrStartsWith(const char string[], const char prefixStr[]) {
22 0 : SkASSERT(string);
23 0 : SkASSERT(prefixStr);
24 0 : return !strncmp(string, prefixStr, strlen(prefixStr));
25 : }
26 0 : static bool SkStrStartsWith(const char string[], const char prefixChar) {
27 0 : SkASSERT(string);
28 0 : return (prefixChar == *string);
29 : }
30 :
31 : bool SkStrEndsWith(const char string[], const char suffixStr[]);
32 : bool SkStrEndsWith(const char string[], const char suffixChar);
33 :
34 : int SkStrStartsWithOneOf(const char string[], const char prefixes[]);
35 :
36 0 : static int SkStrFind(const char string[], const char substring[]) {
37 0 : const char *first = strstr(string, substring);
38 0 : if (NULL == first) return -1;
39 0 : return SkToInt(first - &string[0]);
40 : }
41 :
42 0 : static int SkStrFindLastOf(const char string[], const char subchar) {
43 0 : const char* last = strrchr(string, subchar);
44 0 : if (NULL == last) return -1;
45 0 : return SkToInt(last - &string[0]);
46 : }
47 :
48 0 : static bool SkStrContains(const char string[], const char substring[]) {
49 0 : SkASSERT(string);
50 0 : SkASSERT(substring);
51 0 : return (-1 != SkStrFind(string, substring));
52 : }
53 0 : static bool SkStrContains(const char string[], const char subchar) {
54 0 : SkASSERT(string);
55 : char tmp[2];
56 0 : tmp[0] = subchar;
57 0 : tmp[1] = '\0';
58 0 : return (-1 != SkStrFind(string, tmp));
59 : }
60 :
61 : static inline char *SkStrDup(const char string[]) {
62 : char *ret = (char *) sk_malloc_throw(strlen(string)+1);
63 : memcpy(ret,string,strlen(string)+1);
64 : return ret;
65 : }
66 :
67 : /*
68 : * The SkStrAppend... methods will write into the provided buffer, assuming it is large enough.
69 : * Each method has an associated const (e.g. SkStrAppendU32_MaxSize) which will be the largest
70 : * value needed for that method's buffer.
71 : *
72 : * char storage[SkStrAppendU32_MaxSize];
73 : * SkStrAppendU32(storage, value);
74 : *
75 : * Note : none of the SkStrAppend... methods write a terminating 0 to their buffers. Instead,
76 : * the methods return the ptr to the end of the written part of the buffer. This can be used
77 : * to compute the length, and/or know where to write a 0 if that is desired.
78 : *
79 : * char storage[SkStrAppendU32_MaxSize + 1];
80 : * char* stop = SkStrAppendU32(storage, value);
81 : * size_t len = stop - storage;
82 : * *stop = 0; // valid, since storage was 1 byte larger than the max.
83 : */
84 :
85 : #define SkStrAppendU32_MaxSize 10
86 : char* SkStrAppendU32(char buffer[], uint32_t);
87 : #define SkStrAppendU64_MaxSize 20
88 : char* SkStrAppendU64(char buffer[], uint64_t, int minDigits);
89 :
90 : #define SkStrAppendS32_MaxSize (SkStrAppendU32_MaxSize + 1)
91 : char* SkStrAppendS32(char buffer[], int32_t);
92 : #define SkStrAppendS64_MaxSize (SkStrAppendU64_MaxSize + 1)
93 : char* SkStrAppendS64(char buffer[], int64_t, int minDigits);
94 :
95 : /**
96 : * Floats have at most 8 significant digits, so we limit our %g to that.
97 : * However, the total string could be 15 characters: -1.2345678e-005
98 : *
99 : * In theory we should only expect up to 2 digits for the exponent, but on
100 : * some platforms we have seen 3 (as in the example above).
101 : */
102 : #define SkStrAppendScalar_MaxSize 15
103 :
104 : /**
105 : * Write the scaler in decimal format into buffer, and return a pointer to
106 : * the next char after the last one written. Note: a terminating 0 is not
107 : * written into buffer, which must be at least SkStrAppendScalar_MaxSize.
108 : * Thus if the caller wants to add a 0 at the end, buffer must be at least
109 : * SkStrAppendScalar_MaxSize + 1 bytes large.
110 : */
111 : #define SkStrAppendScalar SkStrAppendFloat
112 :
113 : char* SkStrAppendFloat(char buffer[], float);
114 :
115 : /** \class SkString
116 :
117 : Light weight class for managing strings. Uses reference
118 : counting to make string assignments and copies very fast
119 : with no extra RAM cost. Assumes UTF8 encoding.
120 : */
121 : class SK_API SkString {
122 : public:
123 : SkString();
124 : explicit SkString(size_t len);
125 : explicit SkString(const char text[]);
126 : SkString(const char text[], size_t len);
127 : SkString(const SkString&);
128 : SkString(SkString&&);
129 : ~SkString();
130 :
131 0 : bool isEmpty() const { return 0 == fRec->fLength; }
132 0 : size_t size() const { return (size_t) fRec->fLength; }
133 0 : const char* c_str() const { return fRec->data(); }
134 0 : char operator[](size_t n) const { return this->c_str()[n]; }
135 :
136 : bool equals(const SkString&) const;
137 : bool equals(const char text[]) const;
138 : bool equals(const char text[], size_t len) const;
139 :
140 : bool startsWith(const char prefixStr[]) const {
141 : return SkStrStartsWith(fRec->data(), prefixStr);
142 : }
143 : bool startsWith(const char prefixChar) const {
144 : return SkStrStartsWith(fRec->data(), prefixChar);
145 : }
146 0 : bool endsWith(const char suffixStr[]) const {
147 0 : return SkStrEndsWith(fRec->data(), suffixStr);
148 : }
149 0 : bool endsWith(const char suffixChar) const {
150 0 : return SkStrEndsWith(fRec->data(), suffixChar);
151 : }
152 : bool contains(const char substring[]) const {
153 : return SkStrContains(fRec->data(), substring);
154 : }
155 0 : bool contains(const char subchar) const {
156 0 : return SkStrContains(fRec->data(), subchar);
157 : }
158 : int find(const char substring[]) const {
159 : return SkStrFind(fRec->data(), substring);
160 : }
161 0 : int findLastOf(const char subchar) const {
162 0 : return SkStrFindLastOf(fRec->data(), subchar);
163 : }
164 :
165 0 : friend bool operator==(const SkString& a, const SkString& b) {
166 0 : return a.equals(b);
167 : }
168 : friend bool operator!=(const SkString& a, const SkString& b) {
169 : return !a.equals(b);
170 : }
171 :
172 : // these methods edit the string
173 :
174 : SkString& operator=(const SkString&);
175 : SkString& operator=(SkString&&);
176 : SkString& operator=(const char text[]);
177 :
178 : char* writable_str();
179 0 : char& operator[](size_t n) { return this->writable_str()[n]; }
180 :
181 : void reset();
182 : /** Destructive resize, does not preserve contents. */
183 0 : void resize(size_t len) { this->set(NULL, len); }
184 : void set(const SkString& src) { *this = src; }
185 : void set(const char text[]);
186 : void set(const char text[], size_t len);
187 : void setUTF16(const uint16_t[]);
188 : void setUTF16(const uint16_t[], size_t len);
189 :
190 0 : void insert(size_t offset, const SkString& src) { this->insert(offset, src.c_str(), src.size()); }
191 : void insert(size_t offset, const char text[]);
192 : void insert(size_t offset, const char text[], size_t len);
193 : void insertUnichar(size_t offset, SkUnichar);
194 : void insertS32(size_t offset, int32_t value);
195 : void insertS64(size_t offset, int64_t value, int minDigits = 0);
196 : void insertU32(size_t offset, uint32_t value);
197 : void insertU64(size_t offset, uint64_t value, int minDigits = 0);
198 : void insertHex(size_t offset, uint32_t value, int minDigits = 0);
199 : void insertScalar(size_t offset, SkScalar);
200 :
201 0 : void append(const SkString& str) { this->insert((size_t)-1, str); }
202 0 : void append(const char text[]) { this->insert((size_t)-1, text); }
203 0 : void append(const char text[], size_t len) { this->insert((size_t)-1, text, len); }
204 0 : void appendUnichar(SkUnichar uni) { this->insertUnichar((size_t)-1, uni); }
205 0 : void appendS32(int32_t value) { this->insertS32((size_t)-1, value); }
206 : void appendS64(int64_t value, int minDigits = 0) { this->insertS64((size_t)-1, value, minDigits); }
207 0 : void appendU32(uint32_t value) { this->insertU32((size_t)-1, value); }
208 : void appendU64(uint64_t value, int minDigits = 0) { this->insertU64((size_t)-1, value, minDigits); }
209 0 : void appendHex(uint32_t value, int minDigits = 0) { this->insertHex((size_t)-1, value, minDigits); }
210 0 : void appendScalar(SkScalar value) { this->insertScalar((size_t)-1, value); }
211 :
212 : void prepend(const SkString& str) { this->insert(0, str); }
213 : void prepend(const char text[]) { this->insert(0, text); }
214 0 : void prepend(const char text[], size_t len) { this->insert(0, text, len); }
215 : void prependUnichar(SkUnichar uni) { this->insertUnichar(0, uni); }
216 : void prependS32(int32_t value) { this->insertS32(0, value); }
217 : void prependS64(int32_t value, int minDigits = 0) { this->insertS64(0, value, minDigits); }
218 : void prependHex(uint32_t value, int minDigits = 0) { this->insertHex(0, value, minDigits); }
219 : void prependScalar(SkScalar value) { this->insertScalar((size_t)-1, value); }
220 :
221 : void printf(const char format[], ...) SK_PRINTF_LIKE(2, 3);
222 : void appendf(const char format[], ...) SK_PRINTF_LIKE(2, 3);
223 : void appendVAList(const char format[], va_list);
224 : void prependf(const char format[], ...) SK_PRINTF_LIKE(2, 3);
225 : void prependVAList(const char format[], va_list);
226 :
227 : void remove(size_t offset, size_t length);
228 :
229 0 : SkString& operator+=(const SkString& s) { this->append(s); return *this; }
230 0 : SkString& operator+=(const char text[]) { this->append(text); return *this; }
231 0 : SkString& operator+=(const char c) { this->append(&c, 1); return *this; }
232 :
233 : /**
234 : * Swap contents between this and other. This function is guaranteed
235 : * to never fail or throw.
236 : */
237 : void swap(SkString& other);
238 :
239 : private:
240 : struct Rec {
241 : public:
242 : uint32_t fLength; // logically size_t, but we want it to stay 32bits
243 : int32_t fRefCnt;
244 : char fBeginningOfData;
245 :
246 0 : char* data() { return &fBeginningOfData; }
247 0 : const char* data() const { return &fBeginningOfData; }
248 : };
249 : Rec* fRec;
250 :
251 : #ifdef SK_DEBUG
252 : void validate() const;
253 : #else
254 : void validate() const {}
255 : #endif
256 :
257 : static const Rec gEmptyRec;
258 : static Rec* AllocRec(const char text[], size_t len);
259 : static Rec* RefRec(Rec*);
260 : };
261 :
262 : /// Creates a new string and writes into it using a printf()-style format.
263 : SkString SkStringPrintf(const char* format, ...);
264 :
265 : // Specialized to take advantage of SkString's fast swap path. The unspecialized function is
266 : // declared in SkTypes.h and called by SkTSort.
267 0 : template <> inline void SkTSwap(SkString& a, SkString& b) {
268 0 : a.swap(b);
269 0 : }
270 :
271 : enum SkStrSplitMode {
272 : // Strictly return all results. If the input is ",," and the separator is ',' this will return
273 : // an array of three empty strings.
274 : kStrict_SkStrSplitMode,
275 :
276 : // Only nonempty results will be added to the results. Multiple separators will be
277 : // coalesced. Separators at the beginning and end of the input will be ignored. If the input is
278 : // ",," and the separator is ',', this will return an empty vector.
279 : kCoalesce_SkStrSplitMode
280 : };
281 :
282 : // Split str on any characters in delimiters into out. (Think, strtok with a sane API.)
283 : void SkStrSplit(const char* str, const char* delimiters, SkStrSplitMode splitMode,
284 : SkTArray<SkString>* out);
285 : inline void SkStrSplit(const char* str, const char* delimiters, SkTArray<SkString>* out) {
286 : SkStrSplit(str, delimiters, kCoalesce_SkStrSplitMode, out);
287 : }
288 :
289 : #endif
|