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