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