summaryrefslogtreecommitdiffstats
path: root/source/core/slang-string.h
diff options
context:
space:
mode:
authorTim Foley <tfoley@nvidia.com>2017-06-29 11:50:55 -0700
committerTim Foley <tfoley@nvidia.com>2017-06-29 13:18:32 -0700
commitf4d900dfb64d95f121dd8565dd269be061ef8509 (patch)
treee9aad4ff9a6111d828ae2e4b217dc8145cda56dd /source/core/slang-string.h
parent16613ed981fc5dc38966f5108e85b1aee36ef92f (diff)
Overhaul `RefPtr` and `String`
- `RefPtr` no longer tries to have distinct cases for interal-vs-external reference counts. Instead we always require an internal reference count. - Types the used `RefPtr` but weren't `RefObject` were made to inherit `RefObject` - The `ReferenceCounted` base class was removed, so that only `RefObject` remains - Implicit conversion from `RefPtr<T>` to `T*` added - This created some complicates for other types that relied on implicit conversions, so this isn't a net cleanup right now - The main type that got messed up by the above was `String`, which previously held a `RefPtr<char, ...>`. This change thus *also* includes a major overhaul of `String`: - `String` now holds all its data via indirection, using a `StringRepresentation` that is a `RefObject`. This object holds a length, capacity, and directly stores the character data in its allocation. This means that `sizeof(String)==sizeof(void*)` - It is now possible to directly mutate a `String` by appending to its representation (we just need to ensure it has a reference count of `1`, possibly by cloning it). This means that `StringBuilder` is now basically just an idomatic use of `String` - A couple operations that just return sub-ranges of a `String` now return `StringSlice` to avoid allocation when it isn't needed. This required more work. - Indices into strings changed from `int` to `UInt` (which is pointer-sized). This had a bunch of follow-on changes because the value `-1` sometimes needs to be special-cased in code that uses indices. Further cleanups are probably needed here.
Diffstat (limited to 'source/core/slang-string.h')
-rw-r--r--source/core/slang-string.h658
1 files changed, 362 insertions, 296 deletions
diff --git a/source/core/slang-string.h b/source/core/slang-string.h
index 448b351aa..8294d4bc3 100644
--- a/source/core/slang-string.h
+++ b/source/core/slang-string.h
@@ -8,6 +8,8 @@
#include "hash.h"
#include "secure-crt.h"
+#include <new>
+
namespace Slang
{
class _EndLine
@@ -58,35 +60,182 @@ namespace Slang
return (((unsigned char)ch) & 0xC0) == 0x80;
}
+ // A `StringRepresentation` provides the backing storage for
+ // all reference-counted string-related types.
+ class StringRepresentation : public RefObject
+ {
+ public:
+ UInt length;
+ UInt capacity;
+
+ UInt getLength()
+ {
+ return length;
+ }
+
+ char* getData()
+ {
+ return (char*) (this + 1);
+ }
+
+ static StringRepresentation* createWithCapacityAndLength(UInt capacity, UInt length)
+ {
+ assert(capacity >= length);
+ void* allocation = operator new(sizeof(StringRepresentation) + capacity + 1);
+ StringRepresentation* obj = new(allocation) StringRepresentation();
+ obj->capacity = capacity;
+ obj->length = length;
+ obj->getData()[length] = 0;
+ return obj;
+ }
+
+ static StringRepresentation* createWithCapacity(UInt capacity)
+ {
+ return createWithCapacityAndLength(capacity, 0);
+ }
+
+ static StringRepresentation* createWithLength(UInt length)
+ {
+ return createWithCapacityAndLength(length, length);
+ }
+
+ StringRepresentation* cloneWithCapacity(UInt newCapacity)
+ {
+ StringRepresentation* newObj = createWithCapacityAndLength(newCapacity, length);
+ memcpy(getData(), newObj->getData(), length + 1);
+ return newObj;
+ }
+
+ StringRepresentation* clone()
+ {
+ return cloneWithCapacity(length);
+ }
+
+ StringRepresentation* ensureCapacity(UInt required)
+ {
+ if (capacity >= required) return this;
+
+ UInt newCapacity = capacity;
+ if (!newCapacity) newCapacity = 16; // TODO: figure out good value for minimum capacity
+
+ while (newCapacity < required)
+ {
+ newCapacity = 2 * newCapacity;
+ }
+
+ return cloneWithCapacity(newCapacity);
+ }
+ };
+
+ class String;
+
+ struct UnownedStringSlice
+ {
+ public:
+
+ char const* begin() const
+ {
+ return beginData;
+ }
+
+ char const* end() const
+ {
+ return endData;
+ }
+
+ private:
+ char const* beginData;
+ char const* endData;
+ };
+
+ struct StringSlice
+ {
+ public:
+ StringSlice();
+
+ StringSlice(String const& str, UInt beginIndex, UInt endIndex);
+
+ UInt getLength() const
+ {
+ return endIndex - beginIndex;
+ }
+
+ char const* begin() const
+ {
+ return representation ? representation->getData() + beginIndex : "";
+ }
+
+ char const* end() const
+ {
+ return begin() + getLength();
+ }
+
+ private:
+ RefPtr<StringRepresentation> representation;
+ UInt beginIndex;
+ UInt endIndex;
+
+ friend class String;
+
+ StringSlice(RefPtr<StringRepresentation> const& representation, UInt beginIndex, UInt endIndex)
+ : representation(representation)
+ , beginIndex(beginIndex)
+ , endIndex(endIndex)
+ {}
+ };
+
+ /// String as expected by underlying platform APIs
+ class OSString
+ {
+ public:
+ OSString();
+ OSString(wchar_t* begin, wchar_t* end);
+ ~OSString();
+
+ operator wchar_t const*() const
+ {
+ return begin();
+ }
+
+ wchar_t const* begin() const;
+ wchar_t const* end() const;
+
+ private:
+ wchar_t* beginData;
+ wchar_t* endData;
+ };
+
/*!
@brief Represents a UTF-8 encoded string.
*/
class String
{
+ friend struct StringSlice;
friend class StringBuilder;
private:
- RefPtr<char, RefPtrArrayDestructor> buffer;
- wchar_t * wcharBuffer = nullptr;
- int length = 0;
- void Free()
- {
- if (buffer)
- buffer = 0;
- if (wcharBuffer)
- delete[] wcharBuffer;
- buffer = 0;
- wcharBuffer = 0;
- length = 0;
- }
- public:
- static String FromBuffer(RefPtr<char, RefPtrArrayDestructor> buffer, int len)
- {
- String rs;
- rs.buffer = buffer;
- rs.length = len;
- return rs;
- }
+
+
+ char* getData() const
+ {
+ return buffer ? buffer->getData() : "";
+ }
+
+ UInt getLength() const
+ {
+ return buffer ? buffer->getLength() : 0;
+ }
+
+ void ensureUniqueStorageWithCapacity(UInt capacity);
+ char* prepareForAppend(UInt count);
+
+ RefPtr<StringRepresentation> buffer;
+
+ String(StringRepresentation* buffer)
+ : buffer(buffer)
+ {}
+
+ public:
static String FromWString(const wchar_t * wstr);
static String FromWString(const wchar_t * wstr, const wchar_t * wend);
static String FromWChar(const wchar_t ch);
@@ -94,409 +243,376 @@ namespace Slang
String()
{
}
+
const char * begin() const
{
- return buffer.Ptr();
+ return getData();
}
const char * end() const
{
- return buffer.Ptr() + length;
+ return getData() + getLength();
}
+
+ void append(int value, int radix = 10);
+ void append(unsigned int value, int radix = 10);
+ void append(long long value, int radix = 10);
+ void append(float val, const char * format = "%g");
+ void append(double val, const char * format = "%g");
+
+ void append(char const* str);
+ void append(const char* textBegin, char const* textEnd);
+ void append(char chr);
+ void append(String const& str);
+ void append(StringSlice const& slice);
+
String(int val, int radix = 10)
{
- buffer = new char[33];
- length = IntToAscii(buffer.Ptr(), val, radix);
- ReverseInternalAscii(buffer.Ptr(), length);
+ append(val, radix);
+#if 0
+ buffer = StringRepresentation::createWithLength(33);
+ buffer->length = IntToAscii(getData(), val, radix);
+ ReverseInternalAscii(getData(), getLength());
+#endif
}
String(unsigned int val, int radix = 10)
{
- buffer = new char[33];
- length = IntToAscii(buffer.Ptr(), val, radix);
- ReverseInternalAscii(buffer.Ptr(), length);
+ append(val, radix);
+#if 0
+ buffer = StringRepresentation::createWithLength(33);
+ buffer->length = IntToAscii(getData(), val, radix);
+ ReverseInternalAscii(getData(), getLength());
+#endif
}
String(long long val, int radix = 10)
{
- buffer = new char[65];
- length = IntToAscii(buffer.Ptr(), val, radix);
- ReverseInternalAscii(buffer.Ptr(), length);
+ append(val, radix);
+#if 0
+ buffer = StringRepresentation::createWithLength(65);
+ buffer->length = IntToAscii(getData(), val, radix);
+ ReverseInternalAscii(getData(), getLength());
+#endif
}
String(float val, const char * format = "%g")
{
- buffer = new char[128];
- sprintf_s(buffer.Ptr(), 128, format, val);
- length = (int)strnlen_s(buffer.Ptr(), 128);
+ append(val, format);
+#if 0
+ buffer = StringRepresentation::createWithLength(128);
+ sprintf_s(getData(), 128, format, val);
+ buffer->length = (int)strnlen_s(begin(), 128);
+#endif
}
String(double val, const char * format = "%g")
{
- buffer = new char[128];
- sprintf_s(buffer.Ptr(), 128, format, val);
- length = (int)strnlen_s(buffer.Ptr(), 128);
+ append(val, format);
+#if 0
+ buffer = StringRepresentation::createWithLength(128);
+ sprintf_s(getData(), 128, format, val);
+ buffer->length = (int)strnlen_s(begin(), 128);
+#endif
}
String(const char * str)
{
+ append(str);
+#if 0
if (str)
{
- length = (int)strlen(str);
- buffer = new char[length + 1];
- memcpy(buffer.Ptr(), str, length + 1);
+ buffer = StringRepresentation::createWithLength(strlen(str));
+ memcpy(buffer.Ptr(), str, getLength() + 1);
}
+#endif
}
String(const char* textBegin, char const* textEnd)
{
+ append(textBegin, textEnd);
+#if 0
if (textBegin != textEnd)
{
- length = (int)(textEnd - textBegin);
- buffer = new char[length + 1];
- memcpy(buffer.Ptr(), textBegin, length + 1);
- buffer.Ptr()[length] = 0;
+ buffer = StringRepresentation::createWithLength(textEnd - textBegin);
+ memcpy(buffer.Ptr(), textBegin, getLength());
+ buffer->getData()[getLength()] = 0;
}
+#endif
}
String(char chr)
{
+ append(chr);
+#if 0
if (chr)
{
- length = 1;
- buffer = new char[2];
- buffer[0] = chr;
- buffer[1] = '\0';
+ buffer = StringRepresentation::createWithLength(1);
+ buffer->getData()[0] = chr;
+ buffer->getData()[1] = 0;
}
+#endif
}
- String(const String & str)
+ String(String const& str)
{
+ buffer = str.buffer;
+#if 0
this->operator=(str);
+#endif
}
String(String&& other)
{
- this->operator=(static_cast<String&&>(other));
+ buffer = _Move(other.buffer);
}
+
+ String(StringSlice const& slice)
+ {
+ append(slice);
+ }
+
~String()
{
- Free();
+ buffer = 0;
}
+
String & operator=(const String & str)
{
- if (str.buffer == buffer)
- return *this;
- Free();
- if (str.buffer)
- {
- length = str.length;
- buffer = str.buffer;
- wcharBuffer = 0;
- }
+ buffer = str.buffer;
return *this;
}
String & operator=(String&& other)
{
- if (this != &other)
- {
- Free();
- buffer = _Move(other.buffer);
- length = other.length;
- wcharBuffer = other.wcharBuffer;
- other.buffer = 0;
- other.length = 0;
- other.wcharBuffer = 0;
- }
- return *this;
+ buffer = _Move(other.buffer);
+ return *this;
}
- char operator[](int id) const
+ char operator[](UInt id) const
{
#if _DEBUG
- if (id < 0 || id >= length)
+ if (id < 0 || id >= getLength())
throw "Operator[]: index out of range.";
#endif
- return buffer.Ptr()[id];
+ return begin()[id];
}
- friend String StringConcat(const char * lhs, int leftLen, const char * rhs, int rightLen);
friend String operator+(const char*op1, const String & op2);
friend String operator+(const String & op1, const char * op2);
friend String operator+(const String & op1, const String & op2);
- String TrimStart() const
+ StringSlice TrimStart() const
{
if (!buffer)
- return *this;
- int startIndex = 0;
- while (startIndex < length &&
- (buffer[startIndex] == ' ' || buffer[startIndex] == '\t' || buffer[startIndex] == '\r' || buffer[startIndex] == '\n'))
+ return StringSlice();
+ UInt startIndex = 0;
+ while (startIndex < getLength() &&
+ (getData()[startIndex] == ' ' || getData()[startIndex] == '\t' || getData()[startIndex] == '\r' || getData()[startIndex] == '\n'))
startIndex++;
- return String(buffer + startIndex);
+ return StringSlice(buffer, startIndex, getLength());
}
- String TrimEnd() const
+ StringSlice TrimEnd() const
{
if (!buffer)
- return *this;
+ return StringSlice();
- int endIndex = length - 1;
- while (endIndex >= 0 &&
- (buffer[endIndex] == ' ' || buffer[endIndex] == '\t' || buffer[endIndex] == '\r' || buffer[endIndex] == '\n'))
+ UInt endIndex = getLength();
+ while (endIndex > 0 &&
+ (getData()[endIndex-1] == ' ' || getData()[endIndex-1] == '\t' || getData()[endIndex-1] == '\r' || getData()[endIndex-1] == '\n'))
endIndex--;
- String res;
- res.length = endIndex + 1;
- res.buffer = new char[endIndex + 2];
- strncpy_s(res.buffer.Ptr(), endIndex + 2, buffer.Ptr(), endIndex + 1);
- return res;
+
+ return StringSlice(buffer, 0, endIndex);
}
- String Trim() const
+ StringSlice Trim() const
{
if (!buffer)
- return *this;
+ return StringSlice();
- int startIndex = 0;
- while (startIndex < length &&
- (buffer[startIndex] == ' ' || buffer[startIndex] == '\t'))
+ UInt startIndex = 0;
+ while (startIndex < getLength() &&
+ (getData()[startIndex] == ' ' || getData()[startIndex] == '\t'))
startIndex++;
- int endIndex = length - 1;
- while (endIndex >= startIndex &&
- (buffer[endIndex] == ' ' || buffer[endIndex] == '\t'))
+ UInt endIndex = getLength();
+ while (endIndex > startIndex &&
+ (getData()[endIndex-1] == ' ' || getData()[endIndex-1] == '\t'))
endIndex--;
- String res;
- res.length = endIndex - startIndex + 1;
- res.buffer = new char[res.length + 1];
- memcpy(res.buffer.Ptr(), buffer + startIndex, res.length);
- res.buffer[res.length] = '\0';
- return res;
+ return StringSlice(buffer, startIndex, endIndex);
}
- String SubString(int id, int len) const
+ StringSlice SubString(UInt id, UInt len) const
{
if (len == 0)
- return "";
- if (id + len > length)
- len = length - id;
+ return StringSlice();
+
+ if (id + len > getLength())
+ len = getLength() - id;
#if _DEBUG
- if (id < 0 || id >= length || (id + len) > length)
+ if (id < 0 || id >= getLength() || (id + len) > getLength())
throw "SubString: index out of range.";
if (len < 0)
throw "SubString: length less than zero.";
#endif
- String res;
- res.buffer = new char[len + 1];
- res.length = len;
- strncpy_s(res.buffer.Ptr(), len + 1, buffer + id, len);
- res.buffer[len] = 0;
- return res;
+ return StringSlice(buffer, id, id + len);
}
- const char * Buffer() const
+ char const* Buffer() const
{
- if (buffer)
- return buffer.Ptr();
- else
- return "";
+ return getData();
}
- const wchar_t * ToWString(int * len = 0) const;
+ OSString ToWString(int* len = 0) const;
bool Equals(const String & str, bool caseSensitive = true)
{
- if (!buffer)
- return (str.buffer == 0);
if (caseSensitive)
- return (strcmp(buffer.Ptr(), str.buffer.Ptr()) == 0);
+ return (strcmp(begin(), str.begin()) == 0);
else
{
#ifdef _MSC_VER
- return (_stricmp(buffer.Ptr(), str.buffer.Ptr()) == 0);
+ return (_stricmp(begin(), str.begin()) == 0);
#else
- return (strcasecmp(buffer.Ptr(), str.buffer.Ptr()) == 0);
+ return (strcasecmp(begin(), str.begin()) == 0);
#endif
}
}
bool operator==(const char * strbuffer) const
{
- if (!buffer)
- return (strbuffer == 0 || strcmp(strbuffer, "") == 0);
- if (!strbuffer)
- return buffer == nullptr || strcmp(buffer.Ptr(), "") == 0;
- return (strcmp(buffer.Ptr(), strbuffer) == 0);
+ return (strcmp(begin(), strbuffer) == 0);
}
bool operator==(const String & str) const
{
- if (!buffer)
- return (str.buffer == 0 || strcmp(str.buffer.Ptr(), "") == 0);
- if (!str.buffer)
- return buffer == nullptr || strcmp(buffer.Ptr(), "") == 0;
- return (strcmp(buffer.Ptr(), str.buffer.Ptr()) == 0);
+ return (strcmp(begin(), str.begin()) == 0);
}
bool operator!=(const char * strbuffer) const
{
- if (!buffer)
- return (strbuffer != 0 && strcmp(strbuffer, "") != 0);
- if (strbuffer == 0)
- return length != 0;
- return (strcmp(buffer.Ptr(), strbuffer) != 0);
+ return (strcmp(begin(), strbuffer) != 0);
}
bool operator!=(const String & str) const
{
- if (!buffer)
- return (str.buffer != 0 && strcmp(str.buffer.Ptr(), "") != 0);
- if (str.buffer.Ptr() == 0)
- return length != 0;
- return (strcmp(buffer.Ptr(), str.buffer.Ptr()) != 0);
+ return (strcmp(begin(), str.begin()) != 0);
}
bool operator>(const String & str) const
{
- if (!buffer)
- return false;
- if (!str.buffer)
- return buffer.Ptr() != nullptr && length != 0;
- return (strcmp(buffer.Ptr(), str.buffer.Ptr()) > 0);
+ return (strcmp(begin(), str.begin()) > 0);
}
bool operator<(const String & str) const
{
- if (!buffer)
- return (str.buffer != 0);
- if (!str.buffer)
- return false;
- return (strcmp(buffer.Ptr(), str.buffer.Ptr()) < 0);
+ return (strcmp(begin(), str.begin()) < 0);
}
bool operator>=(const String & str) const
{
- if (!buffer)
- return (str.buffer == 0);
- if (!str.buffer)
- return length == 0;
- int res = strcmp(buffer.Ptr(), str.buffer.Ptr());
- return (res > 0 || res == 0);
+ return (strcmp(begin(), str.begin()) >= 0);
}
bool operator<=(const String & str) const
{
- if (!buffer)
- return true;
- if (!str.buffer)
- return length > 0;
- int res = strcmp(buffer.Ptr(), str.buffer.Ptr());
- return (res < 0 || res == 0);
+ return (strcmp(begin(), str.begin()) <= 0);
}
String ToUpper() const
{
- if (!buffer)
- return *this;
- String res;
- res.length = length;
- res.buffer = new char[length + 1];
- for (int i = 0; i <= length; i++)
- res.buffer[i] = (buffer[i] >= 'a' && buffer[i] <= 'z') ?
- (buffer[i] - 'a' + 'A') : buffer[i];
- return res;
+ String result;
+ for (auto c : *this)
+ {
+ int d = (c >= 'a' && c <= 'z') ? (c - ('a' - 'A')) : c;
+ result.append(d);
+ }
+ return result;
}
String ToLower() const
{
- if (!buffer)
- return *this;
- String res;
- res.length = length;
- res.buffer = new char[length + 1];
- for (int i = 0; i <= length; i++)
- res.buffer[i] = (buffer[i] >= 'A' && buffer[i] <= 'Z') ?
- (buffer[i] - 'A' + 'a') : buffer[i];
- return res;
+ String result;
+ for (auto c : *this)
+ {
+ int d = (c >= 'A' && c <= 'Z') ? (c - ('A' - 'a')) : c;
+ result.append(d);
+ }
+ return result;
}
- int Length() const
+ UInt Length() const
{
- return length;
+ return getLength();
}
- int IndexOf(const char * str, int id) const // String str
+ UInt IndexOf(const char * str, UInt id) const // String str
{
- if (!buffer)
- return -1;
- if (id < 0 || id >= length)
- return -1;
- auto findRs = strstr(buffer + id, str);
- int res = findRs ? (int)(findRs - buffer.Ptr()) : -1;
- if (res >= 0)
- return res;
- else
- return -1;
+ if (id < 0 || id >= getLength())
+ return UInt(-1);
+ auto findRs = strstr(begin() + id, str);
+ UInt res = findRs ? findRs - begin() : -1;
+ return res;
}
- int IndexOf(const String & str, int id) const
+ UInt IndexOf(const String & str, UInt id) const
{
- return IndexOf(str.buffer.Ptr(), id);
+ return IndexOf(str.begin(), id);
}
- int IndexOf(const char * str) const
+ UInt IndexOf(const char * str) const
{
return IndexOf(str, 0);
}
- int IndexOf(const String & str) const
+ UInt IndexOf(const String & str) const
{
- return IndexOf(str.buffer.Ptr(), 0);
+ return IndexOf(str.begin(), 0);
}
- int IndexOf(char ch, int id) const
+ UInt IndexOf(char ch, UInt id) const
{
#if _DEBUG
- if (id < 0 || id >= length)
+ if (id < 0 || id >= getLength())
throw "SubString: index out of range.";
#endif
if (!buffer)
- return -1;
- for (int i = id; i < length; i++)
- if (buffer[i] == ch)
+ return UInt(-1);
+ for (UInt i = id; i < getLength(); i++)
+ if (getData()[i] == ch)
return i;
- return -1;
+ return UInt(-1);
}
- int IndexOf(char ch) const
+ UInt IndexOf(char ch) const
{
return IndexOf(ch, 0);
}
- int LastIndexOf(char ch) const
+ UInt LastIndexOf(char ch) const
{
- for (int i = length - 1; i >= 0; i--)
- if (buffer[i] == ch)
- return i;
- return -1;
+ for (UInt i = getLength(); i > 0; i--)
+ if (getData()[i-1] == ch)
+ return i-1;
+ return UInt(-1);
}
bool StartsWith(const char * str) const // String str
{
if (!buffer)
return false;
- int strLen = (int)strlen(str);
- if (strLen > length)
+ UInt strLen = strlen(str);
+ if (strLen > getLength())
return false;
- for (int i = 0; i < strLen; i++)
- if (str[i] != buffer[i])
+ for (UInt i = 0; i < strLen; i++)
+ if (str[i] != getData()[i])
return false;
return true;
}
bool StartsWith(const String & str) const
{
- return StartsWith(str.buffer.Ptr());
+ return StartsWith(str.begin());
}
- bool EndsWith(char * str) const // String str
+ bool EndsWith(char const * str) const // String str
{
if (!buffer)
return false;
- int strLen = (int)strlen(str);
- if (strLen > length)
+ UInt strLen = strlen(str);
+ if (strLen > getLength())
return false;
- for (int i = strLen - 1; i >= 0; i--)
- if (str[i] != buffer[length - strLen + i])
+ for (UInt i = strLen; i > 0; i--)
+ if (str[i-1] != getData()[getLength() - strLen + i-1])
return false;
return true;
}
bool EndsWith(const String & str) const
{
- return EndsWith(str.buffer.Ptr());
+ return EndsWith(str.begin());
}
bool Contains(const char * str) const // String str
@@ -508,52 +624,27 @@ namespace Slang
bool Contains(const String & str) const
{
- return Contains(str.buffer.Ptr());
+ return Contains(str.begin());
}
int GetHashCode() const
{
- return Slang::GetHashCode((const char*)buffer.Ptr());
+ return Slang::GetHashCode((const char*)begin());
}
- String PadLeft(char ch, int length);
- String PadRight(char ch, int length);
- String ReplaceAll(String src, String dst) const;
};
- class StringBuilder
+ class StringBuilder : public String
{
private:
- char * buffer;
- int length;
- int bufferSize;
- static const int InitialSize = 512;
+ static const int InitialSize = 1024;
public:
- StringBuilder(int bufferSize = 1024)
- :buffer(0), length(0), bufferSize(0)
- {
- buffer = new char[InitialSize]; // new a larger buffer
- buffer[0] = '\0';
- length = 0;
- bufferSize = InitialSize;
- }
- ~StringBuilder()
+ explicit StringBuilder(int bufferSize = InitialSize)
{
- if (buffer)
- delete[] buffer;
+ ensureUniqueStorageWithCapacity(bufferSize);
}
void EnsureCapacity(int size)
{
- if (bufferSize < size)
- {
- char * newBuffer = new char[size + 1];
- if (buffer)
- {
- strcpy_s(newBuffer, size + 1, buffer);
- delete[] buffer;
- }
- buffer = newBuffer;
- bufferSize = size;
- }
+ ensureUniqueStorageWithCapacity(size);
}
StringBuilder & operator << (char ch)
{
@@ -649,31 +740,10 @@ namespace Slang
}
void Append(const char * str, int strLen)
{
- int newLength = length + strLen;
- if (bufferSize < newLength + 1)
- {
- int newBufferSize = InitialSize;
- while (newBufferSize < newLength + 1)
- newBufferSize <<= 1;
- char * newBuffer = new char[newBufferSize];
- if (buffer)
- {
- memcpy(newBuffer, buffer, length);
- delete[] buffer;
- }
- memcpy(newBuffer + length, str, strLen);
- newBuffer[newLength] = '\0';
- buffer = newBuffer;
- bufferSize = newBufferSize;
- }
- else
- {
- memcpy(buffer + length, str, strLen);
- buffer[newLength] = '\0';
- }
- length = newLength;
+ append(str, str + strLen);
}
+#if 0
int Capacity()
{
return bufferSize;
@@ -688,24 +758,19 @@ namespace Slang
{
return length;
}
+#endif
String ToString()
{
- return String(buffer);
+ return *this;
}
String ProduceString()
{
- String rs;
- rs.buffer = buffer;
- rs.length = length;
- buffer = 0;
- bufferSize = 0;
- length = 0;
- return rs;
-
+ return *this;
}
+#if 0
String GetSubString(int start, int count)
{
String rs;
@@ -715,7 +780,9 @@ namespace Slang
rs.buffer[count] = 0;
return rs;
}
+#endif
+#if 0
void Remove(int id, int len)
{
#if _DEBUG
@@ -729,12 +796,11 @@ namespace Slang
buffer[i - actualDelLength] = buffer[i];
length -= actualDelLength;
}
+#endif
void Clear()
{
- length = 0;
- if (buffer)
- buffer[0] = 0;
+ buffer = 0;
}
};