diff options
| author | Tim Foley <tfoley@nvidia.com> | 2017-06-29 11:50:55 -0700 |
|---|---|---|
| committer | Tim Foley <tfoley@nvidia.com> | 2017-06-29 13:18:32 -0700 |
| commit | f4d900dfb64d95f121dd8565dd269be061ef8509 (patch) | |
| tree | e9aad4ff9a6111d828ae2e4b217dc8145cda56dd /source/core/slang-string.cpp | |
| parent | 16613ed981fc5dc38966f5108e85b1aee36ef92f (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.cpp')
| -rw-r--r-- | source/core/slang-string.cpp | 251 |
1 files changed, 193 insertions, 58 deletions
diff --git a/source/core/slang-string.cpp b/source/core/slang-string.cpp index b7eaadcb3..3b9bcc87f 100644 --- a/source/core/slang-string.cpp +++ b/source/core/slang-string.cpp @@ -3,42 +3,76 @@ namespace Slang { + // OSString + + OSString::OSString() + : beginData(0) + , endData(0) + {} + + OSString::OSString(wchar_t* begin, wchar_t* end) + : beginData(begin) + , endData(end) + {} + + OSString::~OSString() + { + if (beginData) + { + delete[] beginData; + } + } + + static const wchar_t kEmptyOSString[] = { 0 }; + + wchar_t const* OSString::begin() const + { + return beginData ? beginData : kEmptyOSString; + } + + wchar_t const* OSString::end() const + { + return endData ? endData : kEmptyOSString; + } + + // StringSlice + + StringSlice::StringSlice() + : representation(0) + , beginIndex(0) + , endIndex(0) + {} + + StringSlice::StringSlice(String const& str, UInt beginIndex, UInt endIndex) + : representation(str.buffer) + , beginIndex(beginIndex) + , endIndex(endIndex) + {} + + + // + _EndLine EndLine; - String StringConcat(const char * lhs, int leftLen, const char * rhs, int rightLen) - { - String res; - res.length = leftLen + rightLen; - res.buffer = new char[res.length + 1]; - strcpy_s(res.buffer.Ptr(), res.length + 1, lhs); - strcpy_s(res.buffer + leftLen, res.length + 1 - leftLen, rhs); - return res; - } - String operator+(const char * op1, const String & op2) - { - if(!op2.buffer) - return String(op1); - return StringConcat(op1, (int)strlen(op1), op2.buffer.Ptr(), op2.length); + String operator+(const char * op1, const String & op2) + { + String result(op1); + result.append(op2); + return result; } String operator+(const String & op1, const char * op2) { - if(!op1.buffer) - return String(op2); - - return StringConcat(op1.buffer.Ptr(), op1.length, op2, (int)strlen(op2)); + String result(op1); + result.append(op2); + return result; } String operator+(const String & op1, const String & op2) { - if(!op1.buffer && !op2.buffer) - return String(); - else if(!op1.buffer) - return String(op2); - else if(!op2.buffer) - return String(op1); - - return StringConcat(op1.buffer.Ptr(), op1.length, op2.buffer.Ptr(), op2.length); + String result(op1); + result.append(op2); + return result; } int StringToInt(const String & str, int radix) @@ -64,6 +98,7 @@ namespace Slang return strtof(str.Buffer(), NULL); } +#if 0 String String::ReplaceAll(String src, String dst) const { String rs = *this; @@ -77,6 +112,7 @@ namespace Slang } return rs; } +#endif String String::FromWString(const wchar_t * wstr) { @@ -113,51 +149,150 @@ namespace Slang return String(buf); } - const wchar_t * String::ToWString(int * len) const + OSString String::ToWString(int* outLength) const { if (!buffer) { - if (len) - *len = 0; - return L""; + return OSString(); } else { - if (wcharBuffer) - { - if (len) - *len = (int)wcslen(wcharBuffer); - return wcharBuffer; - } List<char> buf; Slang::Encoding::UTF16->GetBytes(buf, *this); - if (len) - *len = buf.Count() / sizeof(wchar_t); + + auto length = buf.Count() / sizeof(wchar_t); + if (outLength) + *outLength = length; + buf.Add(0); buf.Add(0); - const_cast<String*>(this)->wcharBuffer = (wchar_t*)buf.Buffer(); + + wchar_t* beginData = (wchar_t*)buf.Buffer(); + wchar_t* endData = beginData + length; + buf.ReleaseBuffer(); - return wcharBuffer; + + return OSString(beginData, endData); } } - String String::PadLeft(char ch, int pLen) - { - StringBuilder sb; - for (int i = 0; i < pLen - this->length; i++) - sb << ch; - for (int i = 0; i < this->length; i++) - sb << buffer[i]; - return sb.ProduceString(); - } + // - String String::PadRight(char ch, int pLen) - { - StringBuilder sb; - for (int i = 0; i < this->length; i++) - sb << buffer[i]; - for (int i = 0; i < pLen - this->length; i++) - sb << ch; - return sb.ProduceString(); - } + void String::ensureUniqueStorageWithCapacity(UInt requiredCapacity) + { + if (buffer && buffer->isUniquelyReferenced() && buffer->capacity >= requiredCapacity) + return; + + UInt newCapacity = buffer ? 2*buffer->capacity : 16; + if (newCapacity < requiredCapacity) + { + newCapacity = requiredCapacity; + } + + UInt length = getLength(); + StringRepresentation* newRepresentation = StringRepresentation::createWithCapacityAndLength(newCapacity, length); + + if (buffer) + { + memcpy(newRepresentation->getData(), buffer->getData(), length + 1); + } + + buffer = newRepresentation; + } + + char* String::prepareForAppend(UInt count) + { + auto oldLength = getLength(); + auto newLength = oldLength + count; + ensureUniqueStorageWithCapacity(newLength); + return getData() + oldLength; + } + + + void String::append(const char* textBegin, char const* textEnd) + { + auto oldLength = getLength(); + auto textLength = textEnd - textBegin; + + auto newLength = oldLength + textLength; + + ensureUniqueStorageWithCapacity(newLength); + + memcpy(getData() + oldLength, textBegin, textLength); + getData()[newLength] = 0; + buffer->length = newLength; + } + + void String::append(char const* str) + { + if (str) + { + append(str, str + strlen(str)); + } + } + + void String::append(char chr) + { + append(&chr, &chr + 1); + } + + void String::append(String const& str) + { + if (!buffer) + { + buffer = str.buffer; + return; + } + + append(str.begin(), str.end()); + } + + void String::append(StringSlice const& slice) + { + append(slice.begin(), slice.end()); + } + + void String::append(int value, int radix) + { + enum { kCount = 33 }; + char* data = prepareForAppend(kCount); + auto count = IntToAscii(data, value, radix); + ReverseInternalAscii(data, count); + buffer->length += count; + } + + void String::append(unsigned int value, int radix) + { + enum { kCount = 33 }; + char* data = prepareForAppend(kCount); + auto count = IntToAscii(data, value, radix); + ReverseInternalAscii(data, count); + buffer->length += count; + } + + void String::append(long long value, int radix) + { + enum { kCount = 65 }; + char* data = prepareForAppend(kCount); + auto count = IntToAscii(data, value, radix); + ReverseInternalAscii(data, count); + buffer->length += count; + } + + + void String::append(float val, const char * format) + { + enum { kCount = 128 }; + char* data = prepareForAppend(kCount); + sprintf_s(data, kCount, format, val); + buffer->length += strnlen_s(data, kCount); + } + + void String::append(double val, const char * format) + { + enum { kCount = 128 }; + char* data = prepareForAppend(kCount); + sprintf_s(data, kCount, format, val); + buffer->length += strnlen_s(data, kCount); + } } |
