From fcf83dbf9effab3bd98bad2b83b2468b7eb05cfd Mon Sep 17 00:00:00 2001 From: Tim Foley Date: Fri, 9 Jun 2017 11:34:21 -0700 Subject: Initial import of code. --- source/core/slang-string.h | 740 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 740 insertions(+) create mode 100644 source/core/slang-string.h (limited to 'source/core/slang-string.h') diff --git a/source/core/slang-string.h b/source/core/slang-string.h new file mode 100644 index 000000000..3eb99e8e3 --- /dev/null +++ b/source/core/slang-string.h @@ -0,0 +1,740 @@ +#ifndef FUNDAMENTAL_LIB_STRING_H +#define FUNDAMENTAL_LIB_STRING_H +#include +#include +#include +#include "smart-pointer.h" +#include "common.h" +#include "hash.h" +#include "secure-crt.h" + +namespace CoreLib +{ + namespace Basic + { + class _EndLine + {}; + extern _EndLine EndLine; + + // in-place reversion, works only for ascii string + inline void ReverseInternalAscii(char * buffer, int length) + { + int i, j; + char c; + for (i = 0, j = length - 1; i + inline int IntToAscii(char * buffer, IntType val, int radix) + { + int i = 0; + IntType sign; + sign = val; + if (sign < 0) + val = (IntType)(0 - val); + do + { + int digit = (val % radix); + if (digit <= 9) + buffer[i++] = (char)(digit + '0'); + else + buffer[i++] = (char)(digit - 10 + 'A'); + } while ((val /= radix) > 0); + if (sign < 0) + buffer[i++] = '-'; + buffer[i] = '\0'; + return i; + } + + inline bool IsUtf8LeadingByte(char ch) + { + return (((unsigned char)ch) & 0xC0) == 0xC0; + } + + inline bool IsUtf8ContinuationByte(char ch) + { + return (((unsigned char)ch) & 0xC0) == 0x80; + } + + /*! + @brief Represents a UTF-8 encoded string. + */ + + class String + { + friend class StringBuilder; + private: + RefPtr 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 buffer, int len) + { + String rs; + rs.buffer = buffer; + rs.length = len; + return rs; + } + 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); + static String FromUnicodePoint(unsigned int codePoint); + String() + { + } + const char * begin() const + { + return buffer.Ptr(); + } + const char * end() const + { + return buffer.Ptr() + length; + } + String(int val, int radix = 10) + { + buffer = new char[33]; + length = IntToAscii(buffer.Ptr(), val, radix); + ReverseInternalAscii(buffer.Ptr(), length); + } + String(unsigned int val, int radix = 10) + { + buffer = new char[33]; + length = IntToAscii(buffer.Ptr(), val, radix); + ReverseInternalAscii(buffer.Ptr(), length); + } + String(long long val, int radix = 10) + { + buffer = new char[65]; + length = IntToAscii(buffer.Ptr(), val, radix); + ReverseInternalAscii(buffer.Ptr(), length); + } + 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); + } + 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); + } + String(const char * str) + { + if (str) + { + length = (int)strlen(str); + buffer = new char[length + 1]; + memcpy(buffer.Ptr(), str, length + 1); + } + } + String(char chr) + { + if (chr) + { + length = 1; + buffer = new char[2]; + buffer[0] = chr; + buffer[1] = '\0'; + } + } + String(const String & str) + { + this->operator=(str); + } + String(String&& other) + { + this->operator=(static_cast(other)); + } + ~String() + { + Free(); + } + String & operator=(const String & str) + { + if (str.buffer == buffer) + return *this; + Free(); + if (str.buffer) + { + length = str.length; + buffer = str.buffer; + wcharBuffer = 0; + } + 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; + } + char operator[](int id) const + { +#if _DEBUG + if (id < 0 || id >= length) + throw "Operator[]: index out of range."; +#endif + return buffer.Ptr()[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 + { + if (!buffer) + return *this; + int startIndex = 0; + while (startIndex < length && + (buffer[startIndex] == ' ' || buffer[startIndex] == '\t' || buffer[startIndex] == '\r' || buffer[startIndex] == '\n')) + startIndex++; + return String(buffer + startIndex); + } + + String TrimEnd() const + { + if (!buffer) + return *this; + + int endIndex = length - 1; + while (endIndex >= 0 && + (buffer[endIndex] == ' ' || buffer[endIndex] == '\t' || buffer[endIndex] == '\r' || buffer[endIndex] == '\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; + } + + String Trim() const + { + if (!buffer) + return *this; + + int startIndex = 0; + while (startIndex < length && + (buffer[startIndex] == ' ' || buffer[startIndex] == '\t')) + startIndex++; + int endIndex = length - 1; + while (endIndex >= startIndex && + (buffer[endIndex] == ' ' || buffer[endIndex] == '\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; + } + + String SubString(int id, int len) const + { + if (len == 0) + return ""; + if (id + len > length) + len = length - id; +#if _DEBUG + if (id < 0 || id >= length || (id + len) > length) + 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; + } + + const char * Buffer() const + { + if (buffer) + return buffer.Ptr(); + else + return ""; + } + + const wchar_t * 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); + else + { +#ifdef _MSC_VER + return (_stricmp(buffer.Ptr(), str.buffer.Ptr()) == 0); +#else + return (strcasecmp(buffer.Ptr(), str.buffer.Ptr()) == 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); + } + + 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); + } + 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); + } + 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); + } + 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); + } + 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); + } + 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); + } + 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); + } + + 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 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; + } + + int Length() const + { + return length; + } + + int IndexOf(const char * str, int 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; + } + + int IndexOf(const String & str, int id) const + { + return IndexOf(str.buffer.Ptr(), id); + } + + int IndexOf(const char * str) const + { + return IndexOf(str, 0); + } + + int IndexOf(const String & str) const + { + return IndexOf(str.buffer.Ptr(), 0); + } + + int IndexOf(char ch, int id) const + { +#if _DEBUG + if (id < 0 || id >= length) + throw "SubString: index out of range."; +#endif + if (!buffer) + return -1; + for (int i = id; i < length; i++) + if (buffer[i] == ch) + return i; + return -1; + } + + int IndexOf(char ch) const + { + return IndexOf(ch, 0); + } + + int LastIndexOf(char ch) const + { + for (int i = length - 1; i >= 0; i--) + if (buffer[i] == ch) + return i; + return -1; + } + + bool StartsWith(const char * str) const // String str + { + if (!buffer) + return false; + int strLen = (int)strlen(str); + if (strLen > length) + return false; + for (int i = 0; i < strLen; i++) + if (str[i] != buffer[i]) + return false; + return true; + } + + bool StartsWith(const String & str) const + { + return StartsWith(str.buffer.Ptr()); + } + + bool EndsWith(char * str) const // String str + { + if (!buffer) + return false; + int strLen = (int)strlen(str); + if (strLen > length) + return false; + for (int i = strLen - 1; i >= 0; i--) + if (str[i] != buffer[length - strLen + i]) + return false; + return true; + } + + bool EndsWith(const String & str) const + { + return EndsWith(str.buffer.Ptr()); + } + + bool Contains(const char * str) const // String str + { + if (!buffer) + return false; + return (IndexOf(str) >= 0) ? true : false; + } + + bool Contains(const String & str) const + { + return Contains(str.buffer.Ptr()); + } + + int GetHashCode() const + { + return CoreLib::Basic::GetHashCode((const char*)buffer.Ptr()); + } + String PadLeft(char ch, int length); + String PadRight(char ch, int length); + String ReplaceAll(String src, String dst) const; + }; + + class StringBuilder + { + private: + char * buffer; + int length; + int bufferSize; + static const int InitialSize = 512; + 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() + { + if (buffer) + delete[] buffer; + } + 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; + } + } + StringBuilder & operator << (char ch) + { + Append(&ch, 1); + return *this; + } + StringBuilder & operator << (int val) + { + Append(val); + return *this; + } + StringBuilder & operator << (unsigned int val) + { + Append(val); + return *this; + } + StringBuilder & operator << (long long val) + { + Append(val); + return *this; + } + StringBuilder & operator << (float val) + { + Append(val); + return *this; + } + StringBuilder & operator << (double val) + { + Append(val); + return *this; + } + StringBuilder & operator << (const char * str) + { + Append(str, (int)strlen(str)); + return *this; + } + StringBuilder & operator << (const String & str) + { + Append(str); + return *this; + } + StringBuilder & operator << (const _EndLine) + { + Append('\n'); + return *this; + } + void Append(char ch) + { + Append(&ch, 1); + } + void Append(float val) + { + char buf[128]; + sprintf_s(buf, 128, "%g", val); + int len = (int)strnlen_s(buf, 128); + Append(buf, len); + } + void Append(double val) + { + char buf[128]; + sprintf_s(buf, 128, "%g", val); + int len = (int)strnlen_s(buf, 128); + Append(buf, len); + } + void Append(unsigned int value, int radix = 10) + { + char vBuffer[33]; + int len = IntToAscii(vBuffer, value, radix); + ReverseInternalAscii(vBuffer, len); + Append(vBuffer); + } + void Append(int value, int radix = 10) + { + char vBuffer[33]; + int len = IntToAscii(vBuffer, value, radix); + ReverseInternalAscii(vBuffer, len); + Append(vBuffer); + } + void Append(long long value, int radix = 10) + { + char vBuffer[65]; + int len = IntToAscii(vBuffer, value, radix); + ReverseInternalAscii(vBuffer, len); + Append(vBuffer); + } + void Append(const String & str) + { + Append(str.Buffer(), str.Length()); + } + void Append(const char * str) + { + Append(str, (int)strlen(str)); + } + 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; + } + + int Capacity() + { + return bufferSize; + } + + char * Buffer() + { + return buffer; + } + + int Length() + { + return length; + } + + String ToString() + { + return String(buffer); + } + + String ProduceString() + { + String rs; + rs.buffer = buffer; + rs.length = length; + buffer = 0; + bufferSize = 0; + length = 0; + return rs; + + } + + String GetSubString(int start, int count) + { + String rs; + rs.buffer = new char[count + 1]; + rs.length = count; + strncpy_s(rs.buffer.Ptr(), count + 1, buffer + start, count); + rs.buffer[count] = 0; + return rs; + } + + void Remove(int id, int len) + { +#if _DEBUG + if (id >= length || id < 0) + throw "Remove: Index out of range."; + if (len < 0) + throw "Remove: remove length smaller than zero."; +#endif + int actualDelLength = ((id + len) >= length) ? (length - id) : len; + for (int i = id + actualDelLength; i <= length; i++) + buffer[i - actualDelLength] = buffer[i]; + length -= actualDelLength; + } + + void Clear() + { + length = 0; + if (buffer) + buffer[0] = 0; + } + }; + + int StringToInt(const String & str, int radix = 10); + unsigned int StringToUInt(const String & str, int radix = 10); + double StringToDouble(const String & str); + float StringToFloat(const String & str); + } +} + +#endif -- cgit v1.2.3