diff options
Diffstat (limited to 'source/core')
| -rw-r--r-- | source/core/core.natvis | 4 | ||||
| -rw-r--r-- | source/core/slang-io.cpp | 45 | ||||
| -rw-r--r-- | source/core/slang-string.cpp | 251 | ||||
| -rw-r--r-- | source/core/slang-string.h | 658 | ||||
| -rw-r--r-- | source/core/smart-pointer.h | 593 | ||||
| -rw-r--r-- | source/core/stream.h | 2 | ||||
| -rw-r--r-- | source/core/text-io.cpp | 6 | ||||
| -rw-r--r-- | source/core/text-io.h | 4 |
8 files changed, 757 insertions, 806 deletions
diff --git a/source/core/core.natvis b/source/core/core.natvis index 19c6db395..3d9ac702e 100644 --- a/source/core/core.natvis +++ b/source/core/core.natvis @@ -3,8 +3,8 @@ <AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010"> <Type Name="Slang::String"> - <DisplayString>{buffer.pointer,s}</DisplayString> - <StringView>buffer.pointer,s</StringView> + <DisplayString>{((char*) (buffer.pointer+1)),s}</DisplayString> + <StringView>((char*) (buffer.pointer+1)),s</StringView> </Type> <Type Name="Slang::ArrayView<*>"> diff --git a/source/core/slang-io.cpp b/source/core/slang-io.cpp index dc2793fc4..684fed0a1 100644 --- a/source/core/slang-io.cpp +++ b/source/core/slang-io.cpp @@ -40,24 +40,46 @@ namespace Slang sb.Append(newExt); return sb.ProduceString(); } + + static UInt findLastSeparator(String const& path) + { + UInt slashPos = path.LastIndexOf('/'); + UInt backslashPos = path.LastIndexOf('\\'); + + if (slashPos == -1) return backslashPos; + if (backslashPos == -1) return slashPos; + + UInt pos = slashPos; + if (backslashPos > slashPos) + pos = backslashPos; + + return pos; + } + String Path::GetFileName(const String & path) { - int pos = path.LastIndexOf('/'); - pos = Math::Max(path.LastIndexOf('\\'), pos) + 1; - return path.SubString(pos, path.Length()-pos); + UInt pos = findLastSeparator(path); + if (pos != -1) + { + pos = pos + 1; + return path.SubString(pos, path.Length() - pos); + } + else + { + return path; + } } String Path::GetFileNameWithoutEXT(const String & path) { - int pos = path.LastIndexOf('/'); - pos = Math::Max(path.LastIndexOf('\\'), pos) + 1; - int dotPos = path.LastIndexOf('.'); - if (dotPos <= pos) - dotPos = path.Length(); - return path.SubString(pos, dotPos - pos); + String fileName = GetFileName(path); + int dotPos = fileName.LastIndexOf('.'); + if (dotPos == -1) + return fileName; + return fileName.SubString(0, dotPos); } String Path::GetFileExt(const String & path) { - int dotPos = path.LastIndexOf('.'); + UInt dotPos = path.LastIndexOf('.'); if (dotPos != -1) return path.SubString(dotPos+1, path.Length()-dotPos-1); else @@ -65,8 +87,7 @@ namespace Slang } String Path::GetDirectoryName(const String & path) { - int pos = path.LastIndexOf('/'); - pos = Math::Max(path.LastIndexOf('\\'), pos); + UInt pos = findLastSeparator(path); if (pos != -1) return path.SubString(0, pos); else 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); + } } 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; } }; diff --git a/source/core/smart-pointer.h b/source/core/smart-pointer.h index d307e4e13..c31cdefe0 100644 --- a/source/core/smart-pointer.h +++ b/source/core/smart-pointer.h @@ -3,462 +3,191 @@ #include "type-traits.h" +#include <assert.h> + namespace Slang { - class RefPtrDefaultDestructor - { - public: - template<typename T> - void operator ()(T * ptr) - { - delete ptr; - } - }; - - class RefPtrArrayDestructor - { - public: - template<typename T> - void operator() (T * ptr) - { - delete [] ptr; - } - }; + // TODO: Need to centralize these typedefs + typedef uintptr_t UInt; + + // Base class for all reference-counted objects + class RefObject + { + private: + UInt referenceCount; + + public: + RefObject() + : referenceCount(0) + {} + + RefObject(const RefObject &) + : referenceCount(0) + {} + + virtual ~RefObject() + {} + + void addReference() + { + referenceCount++; + } + + void releaseReference() + { + assert(referenceCount != 0); + if(--referenceCount == 0) + { + delete this; + } + } + + bool isUniquelyReferenced() + { + assert(referenceCount != 0); + return referenceCount == 1; + } + }; + + inline void addReference(RefObject* obj) + { + if(obj) obj->addReference(); + } + + inline void releaseReference(RefObject* obj) + { + if(obj) obj->releaseReference(); + } + + // "Smart" pointer to a reference-counted object + template<typename T> + struct RefPtr + { + RefPtr() + : pointer(0) + {} + + RefPtr(T* p) + : pointer(p) + { + addReference(p); + } + + RefPtr(RefPtr<T> const& p) + : pointer(p.pointer) + { + addReference(p.pointer); + } + + RefPtr(RefPtr<T>&& p) + : pointer(p.pointer) + { + p.pointer = 0; + } + + template <typename U> + RefPtr(RefPtr<U> const& p, + typename EnableIf<IsConvertible<T*, U*>::Value, void>::type * = 0) + : pointer((U*) p) + { + addReference((U*) p); + } + +#if 0 + void operator=(T* p) + { + T* old = pointer; + addReference(p); + pointer = p; + releaseReference(old); + } +#endif + + void operator=(RefPtr<T> const& p) + { + T* old = pointer; + addReference(p.pointer); + pointer = p.pointer; + releaseReference(old); + } + + void operator=(RefPtr<T>&& p) + { + T* old = pointer; + pointer = p.pointer; + p.pointer = old; + } + + template <typename U> + typename EnableIf<IsConvertible<T*, U*>::value, void>::type + operator=(RefPtr<U> const& ptr) + { + T* old = pointer; + addReference(p.pointer); + pointer = p.pointer; + releaseReference(old); + } - class ReferenceCounted - { - template<typename T, bool b, typename Destructor> - friend class RefPtrImpl; - private: - int _refCount = 0; - public: - ReferenceCounted() {} - ReferenceCounted(const ReferenceCounted &) + int GetHashCode() { - _refCount = 0; + return (int)(long long)(void*)pointer; } - }; - - class RefObject : public ReferenceCounted - { - public: - virtual ~RefObject() - {} - }; + bool operator==(const T * ptr) const + { + return pointer == ptr; + } - template<typename T, bool HasBuiltInCounter, typename Destructor> - class RefPtrImpl - { - }; + bool operator!=(const T * ptr) const + { + return pointer != ptr; + } - template<typename T, typename Destructor = RefPtrDefaultDestructor> - using RefPtr = RefPtrImpl<T, IsBaseOf<ReferenceCounted, T>::Value, Destructor>; - - template<typename T, typename Destructor> - class RefPtrImpl<T, 0, Destructor> - { - template<typename T1, bool b, typename Destructor1> - friend class RefPtrImpl; - private: - T * pointer; - int * refCount; - - public: - RefPtrImpl() - { - pointer = 0; - refCount = 0; - } - RefPtrImpl(T * ptr) - : pointer(0), refCount(0) + bool operator==(RefPtr<T> const& ptr) const { - this->operator=(ptr); - } - RefPtrImpl(const RefPtrImpl<T, 0, Destructor> & ptr) - : pointer(0), refCount(0) - { - this->operator=(ptr); - } - RefPtrImpl(RefPtrImpl<T, 0, Destructor> && str) - : pointer(0), refCount(0) - { - this->operator=(static_cast<RefPtrImpl<T, 0, Destructor> &&>(str)); + return pointer == ptr.pointer; } - template <typename U> - RefPtrImpl(const RefPtrImpl<U, 0, Destructor>& ptr, - typename EnableIf<IsConvertible<T*, U*>::Value, void>::type * = 0) - : pointer(0), refCount(0) + bool operator!=(RefPtr<T> const& ptr) const { - pointer = ptr.pointer; - if (ptr) - { - refCount = ptr.refCount; - (*refCount)++; - } - else - refCount = 0; + return pointer != ptr.pointer; } - template <typename U> - typename EnableIf<IsConvertible<T*, U*>::value, RefPtrImpl<T, 0, Destructor>>::type& - operator=(const RefPtrImpl<U,0,Destructor> & ptr) - { - Unreference(); - - pointer = ptr; - if (ptr) - { - refCount = ptr.refCount; - (*refCount)++; - } - else - refCount = 0; - return *this; - } + template<typename U> + RefPtr<U> As() const + { + RefPtr<U> result(dynamic_cast<U*>(pointer)); + return result; + } - RefPtrImpl<T, 0, Destructor>& operator=(const RefPtrImpl<T, 0, Destructor> & ptr) - { - Unreference(); - pointer = ptr.pointer; - if (ptr) - { - refCount = ptr.refCount; - (*refCount)++; - } - else - refCount = 0; - return *this; - } + ~RefPtr() + { + releaseReference(pointer); + } - RefPtrImpl<T, 0, Destructor>& operator=(T * ptr) - { - if (ptr != pointer) - { - Unreference(); - - pointer = ptr; - if (ptr) - { - refCount = new int; - (*refCount) = 1; - } - else - refCount = 0; - } - return *this; - } - int GetHashCode() - { - return (int)(long long)(void*)pointer; - } - bool operator == (const T * ptr) const - { - return pointer == ptr; - } - bool operator != (const T * ptr) const - { - return pointer != ptr; - } - template<typename U> - bool operator == (const RefPtr<U, Destructor> & ptr) const - { - return pointer == ptr.pointer; - } - template<typename U> - bool operator != (const RefPtr<U, Destructor> & ptr) const - { - return pointer != ptr.pointer; - } - template<typename U> - RefPtrImpl<U, 0, Destructor> As() const - { - RefPtrImpl<U, 0, Destructor> result; - if (pointer) - { - result.pointer = dynamic_cast<U*>(pointer); - if (result.pointer) - { - result.refCount = refCount; - (*refCount)++; - } - } - return result; - } + T& operator*() const + { + return *pointer; + } - T* operator +(int offset) const - { - return pointer+offset; - } - T& operator [](int idx) const - { - return *(pointer + idx); - } - RefPtrImpl<T, 0, Destructor>& operator=(RefPtrImpl<T, 0, Destructor> && ptr) - { - if(ptr.pointer != pointer) - { - Unreference(); - pointer = ptr.pointer; - refCount = ptr.refCount; - ptr.pointer = 0; - ptr.refCount = 0; - } - return *this; - } - T* Release() - { - if(pointer) - { - if((*refCount) > 1) - { - (*refCount)--; - } - else - { - delete refCount; - } - } - auto rs = pointer; - refCount = 0; - pointer = 0; - return rs; - } - ~RefPtrImpl() - { - Unreference(); - } + T* operator->() const + { + return pointer; + } - void Unreference() - { - if(pointer) - { - if((*refCount) > 1) - { - (*refCount)--; - } - else - { - Destructor destructor; - destructor(pointer); - delete refCount; - } - } - } - T & operator *() const - { - return *pointer; - } - T * operator->() const - { - return pointer; - } T * Ptr() const { return pointer; } - public: - explicit operator bool() const - { - if (pointer) - return true; - else - return false; - } - }; - - - template<typename T, typename Destructor> - class RefPtrImpl<T, 1, Destructor> - { - template<typename T1, bool b, typename Destructor1> - friend class RefPtrImpl; - - private: - T * pointer; - public: - RefPtrImpl() - { - pointer = 0; - } - RefPtrImpl(T * ptr) - : pointer(0) - { - this->operator=(ptr); - } - RefPtrImpl(const RefPtrImpl<T, 1, Destructor> & ptr) - : pointer(0) - { - this->operator=(ptr); - } - RefPtrImpl(RefPtrImpl<T, 1, Destructor> && str) - : pointer(0) - { - this->operator=(static_cast<RefPtrImpl<T, 1, Destructor> &&>(str)); - } - template <typename U> - RefPtrImpl(const RefPtrImpl<U, 1, Destructor>& ptr, - typename EnableIf<IsConvertible<T*, U*>::Value, void>::type * = 0) - : pointer(0) - { - pointer = ptr.pointer; - if (ptr) - { - ptr->_refCount++; - } - } - template <typename U> - typename EnableIf<IsConvertible<T*, U*>::value, RefPtrImpl<T, 1, Destructor>&>::type - operator=(const RefPtrImpl<U, 1, Destructor> & ptr) - { - Unreference(); - - pointer = ptr.pointer; - if (ptr) - { - ptr->_refCount++; - } - return *this; - } - RefPtrImpl<T, 1, Destructor>& operator=(T * ptr) - { - if (ptr != pointer) - { - Unreference(); - - pointer = ptr; - if (ptr) - { - ptr->_refCount++; - } - } - return *this; - } - RefPtrImpl<T, 1, Destructor>& operator=(const RefPtrImpl<T, 1, Destructor> & ptr) - { - // Note: It is possible that the object this pointer references owns - // (directly or indirectly) the storage for the argument `ptr`. If - // that is the case and the `Unreference()` call below frees this - // object, then the argument would become invalid. - // - // We copy the pointer value out of the argument first, in order - // to protected against this case. - T* ptrPointer = ptr.pointer; - if (ptrPointer != pointer) - { - if (ptrPointer) - ptrPointer->_refCount++; - Unreference(); - pointer = ptrPointer; - } - return *this; - } - int GetHashCode() - { - return (int)(long long)(void*)pointer; - } - bool operator == (const T * ptr) const - { - return pointer == ptr; - } - bool operator != (const T * ptr) const - { - return pointer != ptr; - } - template<typename U> - bool operator == (const RefPtr<U, Destructor> & ptr) const - { - return pointer == ptr.pointer; - } - template<typename U> - bool operator != (const RefPtr<U, Destructor> & ptr) const - { - return pointer != ptr.pointer; - } - template<typename U> - RefPtrImpl<U, 1, Destructor> As() const - { - RefPtrImpl<U, 1, Destructor> result; - if (pointer) - { - result.pointer = dynamic_cast<U*>(pointer); - if (result.pointer) - { - result.pointer->_refCount++; - } - } - return result; - } - T* operator +(int offset) const - { - return pointer + offset; - } - T& operator [](int idx) const - { - return *(pointer + idx); - } - RefPtrImpl<T, 1, Destructor>& operator=(RefPtrImpl<T, 1, Destructor> && ptr) - { - if (ptr.pointer != pointer) - { - Unreference(); - pointer = ptr.pointer; - ptr.pointer = nullptr; - } - return *this; - } - T* Release() - { - if (pointer) - { - pointer->_refCount--; - } - auto rs = pointer; - pointer = 0; - return rs; - } - ~RefPtrImpl() - { - Unreference(); - } + operator T*() const + { + return pointer; + } - void Unreference() - { - if (pointer) - { - if (pointer->_refCount > 1) - { - pointer->_refCount--; - } - else - { - Destructor destructor; - destructor(pointer); - } - } - } - T & operator *() const - { - return *pointer; - } - T * operator->() const - { - return pointer; - } - T * Ptr() const - { - return pointer; - } - public: - explicit operator bool() const - { - if (pointer) - return true; - else - return false; - } + private: + T* pointer; + }; } diff --git a/source/core/stream.h b/source/core/stream.h index 0f5991cb7..9a8ea8366 100644 --- a/source/core/stream.h +++ b/source/core/stream.h @@ -32,7 +32,7 @@ namespace Slang Start, End, Current }; - class Stream + class Stream : public RefObject { public: virtual ~Stream() {} diff --git a/source/core/text-io.cpp b/source/core/text-io.cpp index 3e5013cf3..7815d7422 100644 --- a/source/core/text-io.cpp +++ b/source/core/text-io.cpp @@ -28,7 +28,7 @@ namespace Slang public: virtual void GetBytes(List<char> & result, const String & str) override { - int ptr = 0; + UInt ptr = 0; while (ptr < str.Length()) { int codePoint = GetUnicodePointFromUTF8([&](int) @@ -66,7 +66,7 @@ namespace Slang {} virtual void GetBytes(List<char> & result, const String & str) override { - int ptr = 0; + UInt ptr = 0; while (ptr < str.Length()) { int codePoint = GetUnicodePointFromUTF8([&](int) @@ -156,7 +156,7 @@ namespace Slang #else newLine = "\n"; #endif - for (int i = 0; i < str.Length(); i++) + for (UInt i = 0; i < str.Length(); i++) { if (str[i] == '\r') sb << newLine; diff --git a/source/core/text-io.h b/source/core/text-io.h index acdaf0b9d..9519d51f1 100644 --- a/source/core/text-io.h +++ b/source/core/text-io.h @@ -263,7 +263,7 @@ namespace Slang } void ReleaseStream() { - stream.Release(); + stream = 0; } }; @@ -308,7 +308,7 @@ namespace Slang } void ReleaseStream() { - stream.Release(); + stream = 0; } }; } |
