123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299 |
- /*
- * Copyright 2006 The Android Open Source Project
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
- #ifndef SkString_DEFINED
- #define SkString_DEFINED
- #include "../private/SkTArray.h"
- #include "../private/SkTo.h"
- #include "SkRefCnt.h"
- #include "SkScalar.h"
- #include <atomic>
- #include <stdarg.h>
- /* Some helper functions for C strings
- */
- static bool SkStrStartsWith(const char string[], const char prefixStr[]) {
- SkASSERT(string);
- SkASSERT(prefixStr);
- return !strncmp(string, prefixStr, strlen(prefixStr));
- }
- static bool SkStrStartsWith(const char string[], const char prefixChar) {
- SkASSERT(string);
- return (prefixChar == *string);
- }
- bool SkStrEndsWith(const char string[], const char suffixStr[]);
- bool SkStrEndsWith(const char string[], const char suffixChar);
- int SkStrStartsWithOneOf(const char string[], const char prefixes[]);
- static int SkStrFind(const char string[], const char substring[]) {
- const char *first = strstr(string, substring);
- if (nullptr == first) return -1;
- return SkToInt(first - &string[0]);
- }
- static int SkStrFindLastOf(const char string[], const char subchar) {
- const char* last = strrchr(string, subchar);
- if (nullptr == last) return -1;
- return SkToInt(last - &string[0]);
- }
- static bool SkStrContains(const char string[], const char substring[]) {
- SkASSERT(string);
- SkASSERT(substring);
- return (-1 != SkStrFind(string, substring));
- }
- static bool SkStrContains(const char string[], const char subchar) {
- SkASSERT(string);
- char tmp[2];
- tmp[0] = subchar;
- tmp[1] = '\0';
- return (-1 != SkStrFind(string, tmp));
- }
- static inline char *SkStrDup(const char string[]) {
- char *ret = (char *) sk_malloc_throw(strlen(string)+1);
- memcpy(ret,string,strlen(string)+1);
- return ret;
- }
- /*
- * The SkStrAppend... methods will write into the provided buffer, assuming it is large enough.
- * Each method has an associated const (e.g. SkStrAppendU32_MaxSize) which will be the largest
- * value needed for that method's buffer.
- *
- * char storage[SkStrAppendU32_MaxSize];
- * SkStrAppendU32(storage, value);
- *
- * Note : none of the SkStrAppend... methods write a terminating 0 to their buffers. Instead,
- * the methods return the ptr to the end of the written part of the buffer. This can be used
- * to compute the length, and/or know where to write a 0 if that is desired.
- *
- * char storage[SkStrAppendU32_MaxSize + 1];
- * char* stop = SkStrAppendU32(storage, value);
- * size_t len = stop - storage;
- * *stop = 0; // valid, since storage was 1 byte larger than the max.
- */
- #define SkStrAppendU32_MaxSize 10
- char* SkStrAppendU32(char buffer[], uint32_t);
- #define SkStrAppendU64_MaxSize 20
- char* SkStrAppendU64(char buffer[], uint64_t, int minDigits);
- #define SkStrAppendS32_MaxSize (SkStrAppendU32_MaxSize + 1)
- char* SkStrAppendS32(char buffer[], int32_t);
- #define SkStrAppendS64_MaxSize (SkStrAppendU64_MaxSize + 1)
- char* SkStrAppendS64(char buffer[], int64_t, int minDigits);
- /**
- * Floats have at most 8 significant digits, so we limit our %g to that.
- * However, the total string could be 15 characters: -1.2345678e-005
- *
- * In theory we should only expect up to 2 digits for the exponent, but on
- * some platforms we have seen 3 (as in the example above).
- */
- #define SkStrAppendScalar_MaxSize 15
- /**
- * Write the scaler in decimal format into buffer, and return a pointer to
- * the next char after the last one written. Note: a terminating 0 is not
- * written into buffer, which must be at least SkStrAppendScalar_MaxSize.
- * Thus if the caller wants to add a 0 at the end, buffer must be at least
- * SkStrAppendScalar_MaxSize + 1 bytes large.
- */
- #define SkStrAppendScalar SkStrAppendFloat
- char* SkStrAppendFloat(char buffer[], float);
- /** \class SkString
- Light weight class for managing strings. Uses reference
- counting to make string assignments and copies very fast
- with no extra RAM cost. Assumes UTF8 encoding.
- */
- class SK_API SkString {
- public:
- SkString();
- explicit SkString(size_t len);
- explicit SkString(const char text[]);
- SkString(const char text[], size_t len);
- SkString(const SkString&);
- SkString(SkString&&);
- ~SkString();
- bool isEmpty() const { return 0 == fRec->fLength; }
- size_t size() const { return (size_t) fRec->fLength; }
- const char* c_str() const { return fRec->data(); }
- char operator[](size_t n) const { return this->c_str()[n]; }
- bool equals(const SkString&) const;
- bool equals(const char text[]) const;
- bool equals(const char text[], size_t len) const;
- bool startsWith(const char prefixStr[]) const {
- return SkStrStartsWith(fRec->data(), prefixStr);
- }
- bool startsWith(const char prefixChar) const {
- return SkStrStartsWith(fRec->data(), prefixChar);
- }
- bool endsWith(const char suffixStr[]) const {
- return SkStrEndsWith(fRec->data(), suffixStr);
- }
- bool endsWith(const char suffixChar) const {
- return SkStrEndsWith(fRec->data(), suffixChar);
- }
- bool contains(const char substring[]) const {
- return SkStrContains(fRec->data(), substring);
- }
- bool contains(const char subchar) const {
- return SkStrContains(fRec->data(), subchar);
- }
- int find(const char substring[]) const {
- return SkStrFind(fRec->data(), substring);
- }
- int findLastOf(const char subchar) const {
- return SkStrFindLastOf(fRec->data(), subchar);
- }
- friend bool operator==(const SkString& a, const SkString& b) {
- return a.equals(b);
- }
- friend bool operator!=(const SkString& a, const SkString& b) {
- return !a.equals(b);
- }
- // these methods edit the string
- SkString& operator=(const SkString&);
- SkString& operator=(SkString&&);
- SkString& operator=(const char text[]);
- char* writable_str();
- char& operator[](size_t n) { return this->writable_str()[n]; }
- void reset();
- /** Destructive resize, does not preserve contents. */
- void resize(size_t len) { this->set(nullptr, len); }
- void set(const SkString& src) { *this = src; }
- void set(const char text[]);
- void set(const char text[], size_t len);
- void insert(size_t offset, const SkString& src) { this->insert(offset, src.c_str(), src.size()); }
- void insert(size_t offset, const char text[]);
- void insert(size_t offset, const char text[], size_t len);
- void insertUnichar(size_t offset, SkUnichar);
- void insertS32(size_t offset, int32_t value);
- void insertS64(size_t offset, int64_t value, int minDigits = 0);
- void insertU32(size_t offset, uint32_t value);
- void insertU64(size_t offset, uint64_t value, int minDigits = 0);
- void insertHex(size_t offset, uint32_t value, int minDigits = 0);
- void insertScalar(size_t offset, SkScalar);
- void append(const SkString& str) { this->insert((size_t)-1, str); }
- void append(const char text[]) { this->insert((size_t)-1, text); }
- void append(const char text[], size_t len) { this->insert((size_t)-1, text, len); }
- void appendUnichar(SkUnichar uni) { this->insertUnichar((size_t)-1, uni); }
- void appendS32(int32_t value) { this->insertS32((size_t)-1, value); }
- void appendS64(int64_t value, int minDigits = 0) { this->insertS64((size_t)-1, value, minDigits); }
- void appendU32(uint32_t value) { this->insertU32((size_t)-1, value); }
- void appendU64(uint64_t value, int minDigits = 0) { this->insertU64((size_t)-1, value, minDigits); }
- void appendHex(uint32_t value, int minDigits = 0) { this->insertHex((size_t)-1, value, minDigits); }
- void appendScalar(SkScalar value) { this->insertScalar((size_t)-1, value); }
- void prepend(const SkString& str) { this->insert(0, str); }
- void prepend(const char text[]) { this->insert(0, text); }
- void prepend(const char text[], size_t len) { this->insert(0, text, len); }
- void prependUnichar(SkUnichar uni) { this->insertUnichar(0, uni); }
- void prependS32(int32_t value) { this->insertS32(0, value); }
- void prependS64(int32_t value, int minDigits = 0) { this->insertS64(0, value, minDigits); }
- void prependHex(uint32_t value, int minDigits = 0) { this->insertHex(0, value, minDigits); }
- void prependScalar(SkScalar value) { this->insertScalar((size_t)-1, value); }
- void printf(const char format[], ...) SK_PRINTF_LIKE(2, 3);
- void appendf(const char format[], ...) SK_PRINTF_LIKE(2, 3);
- void appendVAList(const char format[], va_list);
- void prependf(const char format[], ...) SK_PRINTF_LIKE(2, 3);
- void prependVAList(const char format[], va_list);
- void remove(size_t offset, size_t length);
- SkString& operator+=(const SkString& s) { this->append(s); return *this; }
- SkString& operator+=(const char text[]) { this->append(text); return *this; }
- SkString& operator+=(const char c) { this->append(&c, 1); return *this; }
- /**
- * Swap contents between this and other. This function is guaranteed
- * to never fail or throw.
- */
- void swap(SkString& other);
- private:
- struct Rec {
- public:
- constexpr Rec(uint32_t len, int32_t refCnt)
- : fLength(len), fRefCnt(refCnt), fBeginningOfData(0)
- { }
- static sk_sp<Rec> Make(const char text[], size_t len);
- uint32_t fLength; // logically size_t, but we want it to stay 32bits
- mutable std::atomic<int32_t> fRefCnt;
- char fBeginningOfData;
- char* data() { return &fBeginningOfData; }
- const char* data() const { return &fBeginningOfData; }
- void ref() const;
- void unref() const;
- bool unique() const;
- private:
- // Ensure the unsized delete is called.
- void operator delete(void* p) { ::operator delete(p); }
- };
- sk_sp<Rec> fRec;
- #ifdef SK_DEBUG
- void validate() const;
- #else
- void validate() const {}
- #endif
- static const Rec gEmptyRec;
- };
- /// Creates a new string and writes into it using a printf()-style format.
- SkString SkStringPrintf(const char* format, ...);
- /// This makes it easier to write a caller as a VAR_ARGS function where the format string is
- /// optional.
- static inline SkString SkStringPrintf() { return SkString(); }
- static inline void swap(SkString& a, SkString& b) {
- a.swap(b);
- }
- enum SkStrSplitMode {
- // Strictly return all results. If the input is ",," and the separator is ',' this will return
- // an array of three empty strings.
- kStrict_SkStrSplitMode,
- // Only nonempty results will be added to the results. Multiple separators will be
- // coalesced. Separators at the beginning and end of the input will be ignored. If the input is
- // ",," and the separator is ',', this will return an empty vector.
- kCoalesce_SkStrSplitMode
- };
- // Split str on any characters in delimiters into out. (Think, strtok with a sane API.)
- void SkStrSplit(const char* str, const char* delimiters, SkStrSplitMode splitMode,
- SkTArray<SkString>* out);
- inline void SkStrSplit(const char* str, const char* delimiters, SkTArray<SkString>* out) {
- SkStrSplit(str, delimiters, kCoalesce_SkStrSplitMode, out);
- }
- #endif
|