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