]> git.saurik.com Git - wxWidgets.git/blobdiff - src/stc/scintilla/include/SString.h
Fix [ 1574240 ] wx.RadioButton doesn't navigate correctly
[wxWidgets.git] / src / stc / scintilla / include / SString.h
index 3c7ccc33a51622610aef1b261992b201fc655602..38a206ccf2240224ce1dbdd3236c727ab54babc9 100644 (file)
@@ -2,7 +2,7 @@
 /** @file SString.h
  ** A simple string class.
  **/
-// Copyright 1998-2001 by Neil Hodgson <neilh@scintilla.org>
+// Copyright 1998-2004 by Neil Hodgson <neilh@scintilla.org>
 // The License.txt file describes the conditions under which this software may be distributed.
 
 #ifndef SSTRING_H
@@ -18,100 +18,148 @@ bool EqualCaseInsensitive(const char *a, const char *b);
 // An SString may contain embedded nul characters.
 
 /**
- * @brief A simple string class.
- *
- * Hold the length of the string for quick operations,
- * can have a buffer bigger than the string to avoid too many memory allocations and copies.
- * May have embedded zeroes as a result of @a substitute, but relies too heavily on C string
- * functions to allow reliable manipulations of these strings, other than simple appends, etc.
- **/
-class SString {
+ * Base class from which the two other classes (SBuffer & SString)
+ * are derived.
+ */
+class SContainer {
 public:
        /** Type of string lengths (sizes) and positions (indexes). */
        typedef size_t lenpos_t;
        /** Out of bounds value indicating that the string argument should be measured. */
        enum { measure_length=0xffffffffU};
 
-private:
+protected:
        char *s;                                ///< The C string
        lenpos_t sSize;                 ///< The size of the buffer, less 1: ie. the maximum size of the string
-       lenpos_t sLen;                  ///< The size of the string in s
-       lenpos_t sizeGrowth;    ///< Minimum growth size when appending strings
-       enum { sizeGrowthDefault = 64 };
-       bool grow(lenpos_t lenNew) {
-               while (sizeGrowth * 6 < lenNew) {
-                       sizeGrowth *= 2;
-               }
-               char *sNew = new char[lenNew + sizeGrowth + 1];
-               if (sNew) {
-                       if (s) {
-                               memcpy(sNew, s, sLen);
-                               delete []s;
-                       }
-                       s = sNew;
-                       s[sLen] = '\0';
-                       sSize = lenNew + sizeGrowth;
+
+       SContainer() : s(0), sSize(0) {}
+       ~SContainer() {
+               delete []s;     // Suppose it was allocated using StringAllocate
+               s = 0;
+               sSize = 0;
+       }
+       /** Size of buffer. */
+       lenpos_t size() const {
+               if (s) {
+                       return sSize;
+               } else {
+                       return 0;
                }
-               return sNew != 0;
        }
+public:
+       /**
+        * Allocate uninitialized memory big enough to fit a string of the given length.
+        * @return the pointer to the new string
+        */
+       static char *StringAllocate(lenpos_t len);
+       /**
+        * Duplicate a buffer/C string.
+        * Allocate memory of the given size, or big enough to fit the string if length isn't given;
+        * then copy the given string in the allocated memory.
+        * @return the pointer to the new string
+        */
+       static char *StringAllocate(
+               const char *s,                  ///< The string to duplicate
+               lenpos_t len=measure_length);   ///< The length of memory to allocate. Optional.
+};
 
-       SString &assign(const char *sOther, lenpos_t sSize_=measure_length) {
-               if (!sOther) {
-                       sSize_ = 0;
-               } else if (sSize_ == measure_length) {
-                       sSize_ = strlen(sOther);
-               }
-               if (sSize > 0 && sSize_ <= sSize) {     // Does not allocate new buffer if the current is big enough
-                       if (s && sSize_) {
-                               memcpy(s, sOther, sSize_);
-                       }
-                       s[sSize_] = '\0';
-                       sLen = sSize_;
+
+/**
+ * @brief A string buffer class.
+ *
+ * Main use is to ask an API the length of a string it can provide,
+ * then to allocate a buffer of the given size, and to provide this buffer
+ * to the API to put the string.
+ * This class is intended to be shortlived, to be transformed as SString
+ * as soon as it holds the string, so it has little members.
+ * Note: we assume the buffer is filled by the API. If the length can be shorter,
+ * we should set sLen to strlen(sb.ptr()) in related SString constructor and assignment.
+ */
+class SBuffer : protected SContainer {
+public:
+       SBuffer(lenpos_t len) {
+               s = StringAllocate(len);
+               if (s) {
+                       *s = '\0';
+               sSize = len;
                } else {
+                       sSize = 0;
+               }
+       }
+private:
+       /// Copy constructor
+       // Here only to be on the safe size, user should avoid returning SBuffer values.
+       SBuffer(const SBuffer &source) : SContainer() {
+               s = StringAllocate(source.s, source.sSize);
+               sSize = (s) ? source.sSize : 0;
+       }
+       /// Default assignment operator
+       // Same here, shouldn't be used
+       SBuffer &operator=(const SBuffer &source) {
+               if (this != &source) {
                        delete []s;
-                       s = StringAllocate(sOther, sSize_);
-                       if (s) {
-                               sSize = sSize_; // Allow buffer bigger than real string, thus providing space to grow
-                               sLen = strlen(s);
-                       } else {
-                               sSize = sLen = 0;
-                       }
+                       s = StringAllocate(source.s, source.sSize);
+                       sSize = (s) ? source.sSize : 0;
                }
                return *this;
        }
-
 public:
-       SString() : s(0), sSize(0), sLen(0), sizeGrowth(sizeGrowthDefault) {
+       /** Provide direct read/write access to buffer. */
+       char *ptr() {
+           return s;
        }
-       SString(const SString &source) : sizeGrowth(sizeGrowthDefault) {
-               s = StringAllocate(source.s);
-               sSize = sLen = (s) ? strlen(s) : 0;
+       /** Ownership of the buffer have been taken, so release it. */
+       void reset() {
+               s = 0;
+               sSize = 0;
+       }
+       /** Size of buffer. */
+       lenpos_t size() const {
+               return SContainer::size();
+       }
+};
+
+
+/**
+ * @brief A simple string class.
+ *
+ * Hold the length of the string for quick operations,
+ * can have a buffer bigger than the string to avoid too many memory allocations and copies.
+ * May have embedded zeroes as a result of @a substitute, but relies too heavily on C string
+ * functions to allow reliable manipulations of these strings, other than simple appends, etc.
+ */
+class SString : protected SContainer {
+       lenpos_t sLen;                  ///< The size of the string in s
+       lenpos_t sizeGrowth;    ///< Minimum growth size when appending strings
+       enum { sizeGrowthDefault = 64 };
+
+       bool grow(lenpos_t lenNew);
+       SString &assign(const char *sOther, lenpos_t sSize_=measure_length);
+
+public:
+       SString() : sLen(0), sizeGrowth(sizeGrowthDefault) {}
+       SString(const SString &source) : SContainer(), sizeGrowth(sizeGrowthDefault) {
+               s = StringAllocate(source.s, source.sLen);
+               sSize = sLen = (s) ? source.sLen : 0;
        }
        SString(const char *s_) : sizeGrowth(sizeGrowthDefault) {
                s = StringAllocate(s_);
                sSize = sLen = (s) ? strlen(s) : 0;
        }
+       SString(SBuffer &buf) : sizeGrowth(sizeGrowthDefault) {
+               s = buf.ptr();
+               sSize = sLen = buf.size();
+               // Consumes the given buffer!
+               buf.reset();
+       }
        SString(const char *s_, lenpos_t first, lenpos_t last) : sizeGrowth(sizeGrowthDefault) {
                // note: expects the "last" argument to point one beyond the range end (a la STL iterators)
                s = StringAllocate(s_ + first, last - first);
-               sSize = sLen = (s) ? strlen(s) : 0;
-       }
-       SString(int i) : sizeGrowth(sizeGrowthDefault) {
-               char number[32];
-               sprintf(number, "%0d", i);
-               s = StringAllocate(number);
-               sSize = sLen = (s) ? strlen(s) : 0;
-       }
-       SString(double d, int precision) : sizeGrowth(sizeGrowthDefault) {
-               char number[32];
-               sprintf(number, "%.*f", precision, d);
-               s = StringAllocate(number);
-               sSize = sLen = (s) ? strlen(s) : 0;
+               sSize = sLen = (s) ? last - first : 0;
        }
+       SString(int i);
+       SString(double d, int precision);
        ~SString() {
-               delete []s;
-               s = 0;
-               sSize = 0;
                sLen = 0;
        }
        void clear() {
@@ -122,58 +170,41 @@ public:
        }
        /** Size of buffer. */
        lenpos_t size() const {
-               if (s)
-                       return sSize;
-               else
-                       return 0;
+               return SContainer::size();
        }
        /** Size of string in buffer. */
        lenpos_t length() const {
                return sLen;
        }
+       /** Read access to a character of the string. */
+       char operator[](lenpos_t i) const {
+               return (s && i < sSize) ? s[i] : '\0';
+       }
        SString &operator=(const char *source) {
                return assign(source);
        }
        SString &operator=(const SString &source) {
                if (this != &source) {
-                       assign(source.c_str());
+                       assign(source.s, source.sLen);
                }
                return *this;
        }
-       bool operator==(const SString &sOther) const {
-               if ((s == 0) && (sOther.s == 0))
-                       return true;
-               if ((s == 0) || (sOther.s == 0))
-                       return false;
-               return strcmp(s, sOther.s) == 0;
-       }
+       bool operator==(const SString &sOther) const;
        bool operator!=(const SString &sOther) const {
                return !operator==(sOther);
        }
-       bool operator==(const char *sOther) const {
-               if ((s == 0) && (sOther == 0))
-                       return true;
-               if ((s == 0) || (sOther == 0))
-                       return false;
-               return strcmp(s, sOther) == 0;
-       }
+       bool operator==(const char *sOther) const;
        bool operator!=(const char *sOther) const {
                return !operator==(sOther);
        }
-       bool contains(char ch) {
-               if (s && *s)
-                       return strchr(s, ch) != 0;
-               else
-                       return false;
+       bool contains(char ch) const {
+               return (s && *s) ? strchr(s, ch) != 0 : false;
        }
        void setsizegrowth(lenpos_t sizeGrowth_) {
                sizeGrowth = sizeGrowth_;
        }
        const char *c_str() const {
-               if (s)
-                       return s;
-               else
-                       return "";
+               return s ? s : "";
        }
        /** Give ownership of buffer to caller which must use delete[] to free buffer. */
        char *detach() {
@@ -183,62 +214,15 @@ public:
                sLen = 0;
                return sRet;
        }
-       char operator[](lenpos_t i) const {
-               if (s && i < sSize)     // Or < sLen? Depends on the use, both are OK
-                       return s[i];
-               else
-                       return '\0';
-       }
-       SString substr(lenpos_t subPos, lenpos_t subLen=measure_length) const {
-               if (subPos >= sLen) {
-                       return SString();                                       // return a null string if start index is out of bounds
-               }
-               if ((subLen == measure_length) || (subPos + subLen > sLen)) {
-                       subLen = sLen - subPos;         // can't substr past end of source string
-               }
-               return SString(s, subPos, subPos + subLen);
-       }
-       SString &lowercase(lenpos_t subPos = 0, lenpos_t subLen=measure_length) {
-               if ((subLen == measure_length) || (subPos + subLen > sLen)) {
-                       subLen = sLen - subPos;         // don't apply past end of string
-               }
-               for (lenpos_t i = subPos; i < subPos + subLen; i++) {
-                       if (s[i] < 'A' || s[i] > 'Z')
-                               continue;
-                       else
-                               s[i] = static_cast<char>(s[i] - 'A' + 'a');
-               }
-               return *this;
-       }
-       SString &append(const char *sOther, lenpos_t sLenOther=measure_length, char sep = '\0') {
-               if (!sOther) {
-                       return *this;
-               }
-               if (sLenOther == measure_length) {
-                       sLenOther = strlen(sOther);
-               }
-               int lenSep = 0;
-               if (sLen && sep) {      // Only add a separator if not empty
-                       lenSep = 1;
-               }
-               lenpos_t lenNew = sLen + sLenOther + lenSep;
-               // Conservative about growing the buffer: don't do it, unless really needed
-               if ((lenNew + 1 < sSize) || (grow(lenNew))) {
-                       if (lenSep) {
-                               s[sLen] = sep;
-                               sLen++;
-                       }
-                       memcpy(&s[sLen], sOther, sLenOther);
-                       sLen += sLenOther;
-                       s[sLen] = '\0';
-               }
-               return *this;
-       }
+       SString substr(lenpos_t subPos, lenpos_t subLen=measure_length) const;
+       SString &lowercase(lenpos_t subPos = 0, lenpos_t subLen=measure_length);
+       SString &uppercase(lenpos_t subPos = 0, lenpos_t subLen=measure_length);
+       SString &append(const char *sOther, lenpos_t sLenOther=measure_length, char sep = '\0');
        SString &operator+=(const char *sOther) {
                return append(sOther, static_cast<lenpos_t>(measure_length));
        }
        SString &operator+=(const SString &sOther) {
-               return append(sOther.s, sOther.sSize);
+               return append(sOther.s, sOther.sLen);
        }
        SString &operator+=(char ch) {
                return append(&ch, 1);
@@ -246,121 +230,40 @@ public:
        SString &appendwithseparator(const char *sOther, char sep) {
                return append(sOther, strlen(sOther), sep);
        }
-       SString &insert(lenpos_t pos, const char *sOther, lenpos_t sLenOther=measure_length) {
-               if (!sOther) {
-                       return *this;
-               }
-               if (sLenOther == measure_length) {
-                       sLenOther = strlen(sOther);
-               }
-               lenpos_t lenNew = sLen + sLenOther;
-               // Conservative about growing the buffer: don't do it, unless really needed
-               if ((lenNew + 1 < sSize) || grow(lenNew)) {
-                       lenpos_t moveChars = sLen - pos + 1;
-                       for (lenpos_t i = moveChars; i > 0; i--) {
-                               s[pos + sLenOther + i - 1] = s[pos + i - 1];
-                       }
-                       memcpy(s + pos, sOther, sLenOther);
-                       sLen = lenNew;
-               }
-               return *this;
-       }
-       /** Remove @a len characters from the @a pos position, included.
+       SString &insert(lenpos_t pos, const char *sOther, lenpos_t sLenOther=measure_length);
+
+       /**
+        * Remove @a len characters from the @a pos position, included.
         * Characters at pos + len and beyond replace characters at pos.
         * If @a len is 0, or greater than the length of the string
         * starting at @a pos, the string is just truncated at @a pos.
         */
-       void remove(lenpos_t pos, lenpos_t len) {
-               if (len < 1 || pos + len >= sLen) {
-                       s[pos] = '\0';
-                       sLen = pos;
-               } else {
-                       for (lenpos_t i = pos; i < sLen - len + 1; i++) {
-                               s[i] = s[i+len];
-                       }
-                       sLen -= len;
-               }
-       }
+       void remove(lenpos_t pos, lenpos_t len);
+
        SString &change(lenpos_t pos, char ch) {
-               if (pos >= sLen) {                                      // character changed must be in string bounds
-                       return *this;
+               if (pos < sLen) {                                       // character changed must be in string bounds
+                       *(s + pos) = ch;
                }
-               *(s + pos) = ch;
                return *this;
        }
        /** Read an integral numeric value from the string. */
        int value() const {
-               if (s)
-                       return atoi(s);
-               else
-                       return 0;
-       }
-       int search(const char *sFind, lenpos_t start=0) const {
-               if (start < sLen) {
-                       const char *sFound = strstr(s + start, sFind);
-                       if (sFound) {
-                               return sFound - s;
-                       }
-               }
-               return -1;
+               return s ? atoi(s) : 0;
        }
-       bool contains(const char *sFind) {
+       bool startswith(const char *prefix);
+       bool endswith(const char *suffix);
+       int search(const char *sFind, lenpos_t start=0) const;
+       bool contains(const char *sFind) const {
                return search(sFind) >= 0;
        }
-       int substitute(char chFind, char chReplace) {
-               int c = 0;
-               char *t = s;
-               while (t) {
-                       t = strchr(t, chFind);
-                       if (t) {
-                               *t = chReplace;
-                               t++;
-                               c++;
-                       }
-               }
-               return c;
-       }
-       int substitute(const char *sFind, const char *sReplace) {
-               int c = 0;
-               lenpos_t lenFind = strlen(sFind);
-               lenpos_t lenReplace = strlen(sReplace);
-               int posFound = search(sFind);
-               while (posFound >= 0) {
-                       remove(posFound, lenFind);
-                       insert(posFound, sReplace, lenReplace);
-                       posFound = search(sFind, posFound + lenReplace);
-                       c++;
-               }
-               return c;
-       }
+       int substitute(char chFind, char chReplace);
+       int substitute(const char *sFind, const char *sReplace);
        int remove(const char *sFind) {
                return substitute(sFind, "");
        }
-       /**
-        * Duplicate a C string.
-        * Allocate memory of the given size, or big enough to fit the string if length isn't given;
-        * then copy the given string in the allocated memory.
-        * @return the pointer to the new string
-        */
-       static char *StringAllocate(
-               const char *s,                  ///< The string to duplicate
-               lenpos_t len=measure_length)    ///< The length of memory to allocate. Optional.
-       {
-               if (s == 0) {
-                       return 0;
-               }
-               if (len == measure_length) {
-                       len = strlen(s);
-               }
-               char *sNew = new char[len + 1];
-               if (sNew) {
-                       memcpy(sNew, s, len);
-                       sNew[len] = '\0';
-               }
-               return sNew;
-       }
 };
 
+
 /**
  * Duplicate a C string.
  * Allocate memory of the given size, or big enough to fit the string if length isn't given;
@@ -369,13 +272,9 @@ public:
  */
 inline char *StringDup(
        const char *s,                  ///< The string to duplicate
-        /* gcc 2.96 doesn't seem to like this syntax: gives
-           'non-local function uses anonymous type'
-           SString::lenpos_t len=SString::measure_length)      ///< The length of memory to allocate. Optional.
-        */
-        SString::lenpos_t len=0xffffffffU)     ///< The length of memory to allocate. Optional.
+       SContainer::lenpos_t len=SContainer::measure_length)    ///< The length of memory to allocate. Optional.
 {
-       return SString::StringAllocate(s, len);
+       return SContainer::StringAllocate(s, len);
 }
 
 #endif