SkString.h revision 1c80e99dd5b23ebc3f10c768857a21887ab9f090
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#include "SkRefCnt.h"
16
17#include <atomic>
18#include <stdarg.h>
19
20/*  Some helper functions for C strings
21*/
22
23static bool SkStrStartsWith(const char string[], const char prefixStr[]) {
24    SkASSERT(string);
25    SkASSERT(prefixStr);
26    return !strncmp(string, prefixStr, strlen(prefixStr));
27}
28static bool SkStrStartsWith(const char string[], const char prefixChar) {
29    SkASSERT(string);
30    return (prefixChar == *string);
31}
32
33bool SkStrEndsWith(const char string[], const char suffixStr[]);
34bool SkStrEndsWith(const char string[], const char suffixChar);
35
36int SkStrStartsWithOneOf(const char string[], const char prefixes[]);
37
38static 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
44static 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
50static bool SkStrContains(const char string[], const char substring[]) {
51    SkASSERT(string);
52    SkASSERT(substring);
53    return (-1 != SkStrFind(string, substring));
54}
55static 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
63static 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
88char*   SkStrAppendU32(char buffer[], uint32_t);
89#define SkStrAppendU64_MaxSize  20
90char*   SkStrAppendU64(char buffer[], uint64_t, int minDigits);
91
92#define SkStrAppendS32_MaxSize  (SkStrAppendU32_MaxSize + 1)
93char*   SkStrAppendS32(char buffer[], int32_t);
94#define SkStrAppendS64_MaxSize  (SkStrAppendU64_MaxSize + 1)
95char*   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
115char* 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*/
123class SK_API SkString {
124public:
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    void setUTF16(const uint16_t[]);
190    void setUTF16(const uint16_t[], size_t len);
191
192    void insert(size_t offset, const SkString& src) { this->insert(offset, src.c_str(), src.size()); }
193    void insert(size_t offset, const char text[]);
194    void insert(size_t offset, const char text[], size_t len);
195    void insertUnichar(size_t offset, SkUnichar);
196    void insertS32(size_t offset, int32_t value);
197    void insertS64(size_t offset, int64_t value, int minDigits = 0);
198    void insertU32(size_t offset, uint32_t value);
199    void insertU64(size_t offset, uint64_t value, int minDigits = 0);
200    void insertHex(size_t offset, uint32_t value, int minDigits = 0);
201    void insertScalar(size_t offset, SkScalar);
202
203    void append(const SkString& str) { this->insert((size_t)-1, str); }
204    void append(const char text[]) { this->insert((size_t)-1, text); }
205    void append(const char text[], size_t len) { this->insert((size_t)-1, text, len); }
206    void appendUnichar(SkUnichar uni) { this->insertUnichar((size_t)-1, uni); }
207    void appendS32(int32_t value) { this->insertS32((size_t)-1, value); }
208    void appendS64(int64_t value, int minDigits = 0) { this->insertS64((size_t)-1, value, minDigits); }
209    void appendU32(uint32_t value) { this->insertU32((size_t)-1, value); }
210    void appendU64(uint64_t value, int minDigits = 0) { this->insertU64((size_t)-1, value, minDigits); }
211    void appendHex(uint32_t value, int minDigits = 0) { this->insertHex((size_t)-1, value, minDigits); }
212    void appendScalar(SkScalar value) { this->insertScalar((size_t)-1, value); }
213
214    void prepend(const SkString& str) { this->insert(0, str); }
215    void prepend(const char text[]) { this->insert(0, text); }
216    void prepend(const char text[], size_t len) { this->insert(0, text, len); }
217    void prependUnichar(SkUnichar uni) { this->insertUnichar(0, uni); }
218    void prependS32(int32_t value) { this->insertS32(0, value); }
219    void prependS64(int32_t value, int minDigits = 0) { this->insertS64(0, value, minDigits); }
220    void prependHex(uint32_t value, int minDigits = 0) { this->insertHex(0, value, minDigits); }
221    void prependScalar(SkScalar value) { this->insertScalar((size_t)-1, value); }
222
223    void printf(const char format[], ...) SK_PRINTF_LIKE(2, 3);
224    void appendf(const char format[], ...) SK_PRINTF_LIKE(2, 3);
225    void appendVAList(const char format[], va_list);
226    void prependf(const char format[], ...) SK_PRINTF_LIKE(2, 3);
227    void prependVAList(const char format[], va_list);
228
229    void remove(size_t offset, size_t length);
230
231    SkString& operator+=(const SkString& s) { this->append(s); return *this; }
232    SkString& operator+=(const char text[]) { this->append(text); return *this; }
233    SkString& operator+=(const char c) { this->append(&c, 1); return *this; }
234
235    /**
236     *  Swap contents between this and other. This function is guaranteed
237     *  to never fail or throw.
238     */
239    void swap(SkString& other);
240
241private:
242    struct Rec {
243    public:
244        constexpr Rec(uint32_t len, int32_t refCnt)
245            : fLength(len), fRefCnt(refCnt), fBeginningOfData(0)
246        { }
247        static sk_sp<Rec> Make(const char text[], size_t len);
248        uint32_t    fLength; // logically size_t, but we want it to stay 32bits
249        mutable std::atomic<int32_t> fRefCnt;
250        char        fBeginningOfData;
251
252        char* data() { return &fBeginningOfData; }
253        const char* data() const { return &fBeginningOfData; }
254
255        void ref() const;
256        void unref() const;
257        bool unique() const;
258    private:
259        // Ensure the unsized delete is called.
260        void operator delete(void* p) { ::operator delete(p); }
261    };
262    sk_sp<Rec> fRec;
263
264#ifdef SK_DEBUG
265    void validate() const;
266#else
267    void validate() const {}
268#endif
269
270    static const Rec gEmptyRec;
271};
272
273/// Creates a new string and writes into it using a printf()-style format.
274SkString SkStringPrintf(const char* format, ...);
275/// This makes it easier to write a caller as a VAR_ARGS function where the format string is
276/// optional.
277static inline SkString SkStringPrintf() { return SkString(); }
278
279// Specialized to take advantage of SkString's fast swap path. The unspecialized function is
280// declared in SkTypes.h and called by SkTSort.
281template <> inline void SkTSwap(SkString& a, SkString& b) {
282    a.swap(b);
283}
284
285enum SkStrSplitMode {
286    // Strictly return all results. If the input is ",," and the separator is ',' this will return
287    // an array of three empty strings.
288    kStrict_SkStrSplitMode,
289
290    // Only nonempty results will be added to the results. Multiple separators will be
291    // coalesced. Separators at the beginning and end of the input will be ignored.  If the input is
292    // ",," and the separator is ',', this will return an empty vector.
293    kCoalesce_SkStrSplitMode
294};
295
296// Split str on any characters in delimiters into out.  (Think, strtok with a sane API.)
297void SkStrSplit(const char* str, const char* delimiters, SkStrSplitMode splitMode,
298                SkTArray<SkString>* out);
299inline void SkStrSplit(const char* str, const char* delimiters, SkTArray<SkString>* out) {
300    SkStrSplit(str, delimiters, kCoalesce_SkStrSplitMode, out);
301}
302
303#endif
304