michael@0: michael@0: /* michael@0: * Copyright 2006 The Android Open Source Project michael@0: * michael@0: * Use of this source code is governed by a BSD-style license that can be michael@0: * found in the LICENSE file. michael@0: */ michael@0: michael@0: michael@0: #ifndef SkString_DEFINED michael@0: #define SkString_DEFINED michael@0: michael@0: #include "SkScalar.h" michael@0: #include "SkTArray.h" michael@0: michael@0: #include michael@0: michael@0: /* Some helper functions for C strings michael@0: */ michael@0: michael@0: static bool SkStrStartsWith(const char string[], const char prefixStr[]) { michael@0: SkASSERT(string); michael@0: SkASSERT(prefixStr); michael@0: return !strncmp(string, prefixStr, strlen(prefixStr)); michael@0: } michael@0: static bool SkStrStartsWith(const char string[], const char prefixChar) { michael@0: SkASSERT(string); michael@0: return (prefixChar == *string); michael@0: } michael@0: michael@0: bool SkStrEndsWith(const char string[], const char suffixStr[]); michael@0: bool SkStrEndsWith(const char string[], const char suffixChar); michael@0: michael@0: int SkStrStartsWithOneOf(const char string[], const char prefixes[]); michael@0: michael@0: static int SkStrFind(const char string[], const char substring[]) { michael@0: const char *first = strstr(string, substring); michael@0: if (NULL == first) return -1; michael@0: return SkToS32(first - &string[0]); michael@0: } michael@0: michael@0: static bool SkStrContains(const char string[], const char substring[]) { michael@0: SkASSERT(string); michael@0: SkASSERT(substring); michael@0: return (-1 != SkStrFind(string, substring)); michael@0: } michael@0: static bool SkStrContains(const char string[], const char subchar) { michael@0: SkASSERT(string); michael@0: char tmp[2]; michael@0: tmp[0] = subchar; michael@0: tmp[1] = '\0'; michael@0: return (-1 != SkStrFind(string, tmp)); michael@0: } michael@0: michael@0: static inline char *SkStrDup(const char string[]) { michael@0: char *ret = (char *) sk_malloc_throw(strlen(string)+1); michael@0: memcpy(ret,string,strlen(string)+1); michael@0: return ret; michael@0: } michael@0: michael@0: michael@0: michael@0: #define SkStrAppendU32_MaxSize 10 michael@0: char* SkStrAppendU32(char buffer[], uint32_t); michael@0: #define SkStrAppendU64_MaxSize 20 michael@0: char* SkStrAppendU64(char buffer[], uint64_t, int minDigits); michael@0: michael@0: #define SkStrAppendS32_MaxSize (SkStrAppendU32_MaxSize + 1) michael@0: char* SkStrAppendS32(char buffer[], int32_t); michael@0: #define SkStrAppendS64_MaxSize (SkStrAppendU64_MaxSize + 1) michael@0: char* SkStrAppendS64(char buffer[], int64_t, int minDigits); michael@0: michael@0: /** michael@0: * Floats have at most 8 significant digits, so we limit our %g to that. michael@0: * However, the total string could be 15 characters: -1.2345678e-005 michael@0: * michael@0: * In theory we should only expect up to 2 digits for the exponent, but on michael@0: * some platforms we have seen 3 (as in the example above). michael@0: */ michael@0: #define SkStrAppendScalar_MaxSize 15 michael@0: michael@0: /** michael@0: * Write the scaler in decimal format into buffer, and return a pointer to michael@0: * the next char after the last one written. Note: a terminating 0 is not michael@0: * written into buffer, which must be at least SkStrAppendScalar_MaxSize. michael@0: * Thus if the caller wants to add a 0 at the end, buffer must be at least michael@0: * SkStrAppendScalar_MaxSize + 1 bytes large. michael@0: */ michael@0: #define SkStrAppendScalar SkStrAppendFloat michael@0: michael@0: char* SkStrAppendFloat(char buffer[], float); michael@0: char* SkStrAppendFixed(char buffer[], SkFixed); michael@0: michael@0: /** \class SkString michael@0: michael@0: Light weight class for managing strings. Uses reference michael@0: counting to make string assignments and copies very fast michael@0: with no extra RAM cost. Assumes UTF8 encoding. michael@0: */ michael@0: class SK_API SkString { michael@0: public: michael@0: SkString(); michael@0: explicit SkString(size_t len); michael@0: explicit SkString(const char text[]); michael@0: SkString(const char text[], size_t len); michael@0: SkString(const SkString&); michael@0: ~SkString(); michael@0: michael@0: bool isEmpty() const { return 0 == fRec->fLength; } michael@0: size_t size() const { return (size_t) fRec->fLength; } michael@0: const char* c_str() const { return fRec->data(); } michael@0: char operator[](size_t n) const { return this->c_str()[n]; } michael@0: michael@0: bool equals(const SkString&) const; michael@0: bool equals(const char text[]) const; michael@0: bool equals(const char text[], size_t len) const; michael@0: michael@0: bool startsWith(const char prefixStr[]) const { michael@0: return SkStrStartsWith(fRec->data(), prefixStr); michael@0: } michael@0: bool startsWith(const char prefixChar) const { michael@0: return SkStrStartsWith(fRec->data(), prefixChar); michael@0: } michael@0: bool endsWith(const char suffixStr[]) const { michael@0: return SkStrEndsWith(fRec->data(), suffixStr); michael@0: } michael@0: bool endsWith(const char suffixChar) const { michael@0: return SkStrEndsWith(fRec->data(), suffixChar); michael@0: } michael@0: bool contains(const char substring[]) const { michael@0: return SkStrContains(fRec->data(), substring); michael@0: } michael@0: bool contains(const char subchar) const { michael@0: return SkStrContains(fRec->data(), subchar); michael@0: } michael@0: int find(const char substring[]) const { michael@0: return SkStrFind(fRec->data(), substring); michael@0: } michael@0: michael@0: friend bool operator==(const SkString& a, const SkString& b) { michael@0: return a.equals(b); michael@0: } michael@0: friend bool operator!=(const SkString& a, const SkString& b) { michael@0: return !a.equals(b); michael@0: } michael@0: michael@0: // these methods edit the string michael@0: michael@0: SkString& operator=(const SkString&); michael@0: SkString& operator=(const char text[]); michael@0: michael@0: char* writable_str(); michael@0: char& operator[](size_t n) { return this->writable_str()[n]; } michael@0: michael@0: void reset(); michael@0: void resize(size_t len) { this->set(NULL, len); } michael@0: void set(const SkString& src) { *this = src; } michael@0: void set(const char text[]); michael@0: void set(const char text[], size_t len); michael@0: void setUTF16(const uint16_t[]); michael@0: void setUTF16(const uint16_t[], size_t len); michael@0: michael@0: void insert(size_t offset, const SkString& src) { this->insert(offset, src.c_str(), src.size()); } michael@0: void insert(size_t offset, const char text[]); michael@0: void insert(size_t offset, const char text[], size_t len); michael@0: void insertUnichar(size_t offset, SkUnichar); michael@0: void insertS32(size_t offset, int32_t value); michael@0: void insertS64(size_t offset, int64_t value, int minDigits = 0); michael@0: void insertU32(size_t offset, uint32_t value); michael@0: void insertU64(size_t offset, uint64_t value, int minDigits = 0); michael@0: void insertHex(size_t offset, uint32_t value, int minDigits = 0); michael@0: void insertScalar(size_t offset, SkScalar); michael@0: michael@0: void append(const SkString& str) { this->insert((size_t)-1, str); } michael@0: void append(const char text[]) { this->insert((size_t)-1, text); } michael@0: void append(const char text[], size_t len) { this->insert((size_t)-1, text, len); } michael@0: void appendUnichar(SkUnichar uni) { this->insertUnichar((size_t)-1, uni); } michael@0: void appendS32(int32_t value) { this->insertS32((size_t)-1, value); } michael@0: void appendS64(int64_t value, int minDigits = 0) { this->insertS64((size_t)-1, value, minDigits); } michael@0: void appendU32(uint32_t value) { this->insertU32((size_t)-1, value); } michael@0: void appendU64(uint64_t value, int minDigits = 0) { this->insertU64((size_t)-1, value, minDigits); } michael@0: void appendHex(uint32_t value, int minDigits = 0) { this->insertHex((size_t)-1, value, minDigits); } michael@0: void appendScalar(SkScalar value) { this->insertScalar((size_t)-1, value); } michael@0: michael@0: void prepend(const SkString& str) { this->insert(0, str); } michael@0: void prepend(const char text[]) { this->insert(0, text); } michael@0: void prepend(const char text[], size_t len) { this->insert(0, text, len); } michael@0: void prependUnichar(SkUnichar uni) { this->insertUnichar(0, uni); } michael@0: void prependS32(int32_t value) { this->insertS32(0, value); } michael@0: void prependS64(int32_t value, int minDigits = 0) { this->insertS64(0, value, minDigits); } michael@0: void prependHex(uint32_t value, int minDigits = 0) { this->insertHex(0, value, minDigits); } michael@0: void prependScalar(SkScalar value) { this->insertScalar((size_t)-1, value); } michael@0: michael@0: void printf(const char format[], ...) SK_PRINTF_LIKE(2, 3); michael@0: void appendf(const char format[], ...) SK_PRINTF_LIKE(2, 3); michael@0: void appendVAList(const char format[], va_list); michael@0: void prependf(const char format[], ...) SK_PRINTF_LIKE(2, 3); michael@0: michael@0: void remove(size_t offset, size_t length); michael@0: michael@0: SkString& operator+=(const SkString& s) { this->append(s); return *this; } michael@0: SkString& operator+=(const char text[]) { this->append(text); return *this; } michael@0: SkString& operator+=(const char c) { this->append(&c, 1); return *this; } michael@0: michael@0: /** michael@0: * Swap contents between this and other. This function is guaranteed michael@0: * to never fail or throw. michael@0: */ michael@0: void swap(SkString& other); michael@0: michael@0: private: michael@0: struct Rec { michael@0: public: michael@0: uint32_t fLength; // logically size_t, but we want it to stay 32bits michael@0: int32_t fRefCnt; michael@0: char fBeginningOfData; michael@0: michael@0: char* data() { return &fBeginningOfData; } michael@0: const char* data() const { return &fBeginningOfData; } michael@0: }; michael@0: Rec* fRec; michael@0: michael@0: #ifdef SK_DEBUG michael@0: const char* fStr; michael@0: void validate() const; michael@0: #else michael@0: void validate() const {} michael@0: #endif michael@0: michael@0: static const Rec gEmptyRec; michael@0: static Rec* AllocRec(const char text[], size_t len); michael@0: static Rec* RefRec(Rec*); michael@0: }; michael@0: michael@0: /// Creates a new string and writes into it using a printf()-style format. michael@0: SkString SkStringPrintf(const char* format, ...); michael@0: michael@0: // Specialized to take advantage of SkString's fast swap path. The unspecialized function is michael@0: // declared in SkTypes.h and called by SkTSort. michael@0: template <> inline void SkTSwap(SkString& a, SkString& b) { michael@0: a.swap(b); michael@0: } michael@0: michael@0: // Split str on any characters in delimiters into out. (Think, strtok with a sane API.) michael@0: void SkStrSplit(const char* str, const char* delimiters, SkTArray* out); michael@0: michael@0: #endif