SmartOS/String.cpp

1041 lines
19 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
#include <stdarg.h>
#include "String.h"
extern char* itoa(int value, char* string, int radix);
extern char* ltoa(Int64 value, char* string, int radix);
extern char* utoa(uint value, char* string, int radix);
extern char* ultoa(ulong value, char* string, int radix);
char* dtostrf(double val, char width, byte prec, char* sout);
/******************************** String ********************************/
String::String(const char* cstr)
{
init();
if (cstr) copy(cstr, strlen(cstr));
}
String::String(const String& value)
{
init();
*this = value;
}
String::String(String&& rval)
{
init();
move(rval);
}
String::String(StringHelper&& rval)
{
init();
move(rval);
}
String::String(char c)
{
init();
char buf[2];
buf[0] = c;
buf[1] = 0;
*this = buf;
}
String::String(byte value, byte radix)
{
init();
char buf[1 + 8 * sizeof(byte)];
utoa(value, buf, radix);
*this = buf;
}
String::String(int value, byte radix)
{
init();
char buf[2 + 8 * sizeof(int)];
itoa(value, buf, radix);
*this = buf;
}
String::String(uint value, byte radix)
{
init();
char buf[1 + 8 * sizeof(uint)];
utoa(value, buf, radix);
*this = buf;
}
String::String(Int64 value, byte radix)
{
init();
char buf[2 + 8 * sizeof(Int64)];
ltoa(value, buf, radix);
*this = buf;
}
String::String(ulong value, byte radix)
{
init();
char buf[1 + 8 * sizeof(ulong)];
ultoa(value, buf, radix);
*this = buf;
}
String::String(float value, byte decimalPlaces)
{
init();
char buf[33];
*this = dtostrf(value, (decimalPlaces + 2), decimalPlaces, buf);
}
String::String(double value, byte decimalPlaces)
{
init();
char buf[33];
*this = dtostrf(value, (decimalPlaces + 2), decimalPlaces, buf);
}
String::String(char* str, int length)
{
buffer = str;
capacity = length;
len = 0;
buffer[0] = 0;
}
String::~String()
{
delete buffer;
}
inline void String::init()
{
buffer = Arr;
capacity = sizeof(Arr);
len = 0;
}
void String::release()
{
delete buffer;
init();
}
bool String::CheckCapacity(uint size)
{
if (buffer && capacity >= size) return true;
auto p = new char[size + 1];
if(!p) return false;
if(len)
strncpy(p, buffer, len);
else
p[0] = 0;
delete buffer;
buffer = p;
capacity = size;
return true;
}
String& String::copy(const char* cstr, uint length)
{
if (!CheckCapacity(length))
release();
else
{
len = length;
strcpy(buffer, cstr);
}
return *this;
}
void String::move(String& rhs)
{
if (buffer) {
if (capacity >= rhs.len) {
strcpy(buffer, rhs.buffer);
len = rhs.len;
rhs.len = 0;
return;
} else {
delete buffer;
}
}
buffer = rhs.buffer;
capacity = rhs.capacity;
len = rhs.len;
rhs.buffer = NULL;
rhs.capacity = 0;
rhs.len = 0;
}
void String::SetBuffer(const void* str, int length)
{
buffer = (char*)str;
capacity = length;
len = 0;
}
String& String::operator = (const String& rhs)
{
if (this == &rhs) return *this;
if (rhs.buffer) copy(rhs.buffer, rhs.len);
else release();
return *this;
}
String& String::operator = (String&& rval)
{
if (this != &rval) move(rval);
return *this;
}
String& String::operator = (StringHelper&& rval)
{
if (this != &rval) move(rval);
return *this;
}
String& String::operator = (const char* cstr)
{
if (cstr) copy(cstr, strlen(cstr));
else release();
return *this;
}
bool String::Concat(const Object& obj)
{
return Concat(obj.ToString());
}
bool String::Concat(const String& s)
{
return Concat(s.buffer, s.len);
}
bool String::Concat(const char* cstr, uint length)
{
uint newlen = len + length;
if (!cstr) return false;
if (length == 0) return true;
if (!CheckCapacity(newlen)) return false;
strcpy(buffer + len, cstr);
len = newlen;
return true;
}
bool String::Concat(const char* cstr)
{
if (!cstr) return 0;
return Concat(cstr, strlen(cstr));
}
bool String::Concat(char c)
{
char buf[2];
buf[0] = c;
buf[1] = 0;
return Concat(buf, 1);
}
bool String::Concat(byte num, byte radix)
{
char buf[1 + 3 * sizeof(byte)];
itoa(num, buf, radix);
return Concat(buf, strlen(buf));
}
bool String::Concat(int num, byte radix)
{
char buf[2 + 3 * sizeof(int)];
itoa(num, buf, radix);
return Concat(buf, strlen(buf));
}
/*bool String::Concat(uint num, byte radix, byte width)
{
char buf[2 + 3 * sizeof(int)];
itoa(num, buf, radix);
int length = strlen(buf);
if(width)
{
int remain = width - length;
if(remain > 0)
{
// 前面补0
char cs[16];
memset(cs, '0', remain);
cs[remain] = 0;
Concat(cs, remain);
}
// 如果超长按照C#标准,让它撑大
}
return Concat(buf, length);
}*/
bool String::Concat(uint num, byte radix)
{
char buf[1 + 3 * sizeof(uint)];
utoa(num, buf, radix);
return Concat(buf, strlen(buf));
}
bool String::Concat(Int64 num, byte radix)
{
char buf[2 + 3 * sizeof(Int64)];
ltoa(num, buf, radix);
return Concat(buf, strlen(buf));
}
bool String::Concat(ulong num, byte radix)
{
char buf[1 + 3 * sizeof(ulong)];
ultoa(num, buf, radix);
return Concat(buf, strlen(buf));
}
bool String::Concat(float num)
{
char buf[20];
char* string = dtostrf(num, 4, 2, buf);
return Concat(string, strlen(string));
}
bool String::Concat(double num)
{
char buf[20];
char* string = dtostrf(num, 4, 2, buf);
return Concat(string, strlen(string));
}
StringHelper& operator + (const StringHelper& lhs, const Object& rhs)
{
auto& a = const_cast<StringHelper&>(lhs);
auto str = rhs.ToString();
if (!a.Concat(str.buffer, str.len)) a.release();
return a;
}
StringHelper& operator + (const StringHelper& lhs, const String& rhs)
{
auto& a = const_cast<StringHelper&>(lhs);
if (!a.Concat(rhs.buffer, rhs.len)) a.release();
return a;
}
StringHelper& operator + (const StringHelper& lhs, const char* cstr)
{
auto& a = const_cast<StringHelper&>(lhs);
if (!cstr || !a.Concat(cstr, strlen(cstr))) a.release();
return a;
}
StringHelper& operator + (const StringHelper& lhs, char c)
{
auto& a = const_cast<StringHelper&>(lhs);
if (!a.Concat(c)) a.release();
return a;
}
StringHelper& operator + (const StringHelper& lhs, byte num)
{
auto& a = const_cast<StringHelper&>(lhs);
if (!a.Concat(num)) a.release();
return a;
}
StringHelper& operator + (const StringHelper& lhs, int num)
{
auto& a = const_cast<StringHelper&>(lhs);
if (!a.Concat(num)) a.release();
return a;
}
StringHelper& operator + (const StringHelper& lhs, uint num)
{
auto& a = const_cast<StringHelper&>(lhs);
if (!a.Concat(num)) a.release();
return a;
}
StringHelper& operator + (const StringHelper& lhs, Int64 num)
{
auto& a = const_cast<StringHelper&>(lhs);
if (!a.Concat(num)) a.release();
return a;
}
StringHelper& operator + (const StringHelper& lhs, ulong num)
{
auto& a = const_cast<StringHelper&>(lhs);
if (!a.Concat(num)) a.release();
return a;
}
StringHelper& operator + (const StringHelper& lhs, float num)
{
auto& a = const_cast<StringHelper&>(lhs);
if (!a.Concat(num)) a.release();
return a;
}
StringHelper& operator + (const StringHelper& lhs, double num)
{
auto& a = const_cast<StringHelper&>(lhs);
if (!a.Concat(num)) a.release();
return a;
}
int String::CompareTo(const String& s) const
{
if (!buffer || !s.buffer) {
if (s.buffer && s.len > 0) return 0 - *(byte*)s.buffer;
if (buffer && len > 0) return *(byte*)buffer;
return 0;
}
return strcmp(buffer, s.buffer);
}
bool String::Equals(const String& s2) const
{
return len == s2.len && CompareTo(s2) == 0;
}
bool String::Equals(const char* cstr) const
{
if (len == 0) return cstr == NULL || *cstr == 0;
if (cstr == NULL) return buffer[0] == 0;
return strcmp(buffer, cstr) == 0;
}
bool String::EqualsIgnoreCase(const String &s2 ) const
{
if (this == &s2) return true;
if (len != s2.len) return false;
if (len == 0) return true;
const char *p1 = buffer;
const char *p2 = s2.buffer;
while (*p1) {
if (tolower(*p1++) != tolower(*p2++)) return false;
}
return true;
}
bool String::operator<(const String& rhs) const
{
return CompareTo(rhs) < 0;
}
bool String::operator>(const String& rhs) const
{
return CompareTo(rhs) > 0;
}
bool String::operator<=(const String& rhs) const
{
return CompareTo(rhs) <= 0;
}
bool String::operator>=(const String& rhs) const
{
return CompareTo(rhs) >= 0;
}
void String::SetAt(int loc, char c)
{
if (loc < len) buffer[loc] = c;
}
char& String::operator[](int index)
{
static char dummy_writable_char;
if (index >= len || !buffer) {
dummy_writable_char = 0;
return dummy_writable_char;
}
return buffer[index];
}
char String::operator[]( int index ) const
{
if (index >= len || !buffer) return 0;
return buffer[index];
}
void String::GetBytes(byte* buf, int bufsize, int index) const
{
if (!bufsize || !buf) return;
if (index >= len) {
buf[0] = 0;
return;
}
int n = bufsize - 1;
if (n > len - index) n = len - index;
strncpy((char*)buf, buffer + index, n);
buf[n] = 0;
}
ByteArray String::GetBytes() const
{
ByteArray bs;
bs.SetLength(len);
GetBytes(bs.GetBuffer(), bs.Length());
return bs;
}
ByteArray String::ToHex() const
{
ByteArray bs;
bs.SetLength(len / 2);
char cs[3];
cs[2] = 0;
byte* b = bs.GetBuffer();
char* p = buffer;
for(int i=0; i<len; i+=2)
{
cs[0] = *p++;
cs[1] = *p++;
*b++ = (byte)strtol(cs, nullptr, 16);
}
return bs;
}
// 输出对象的字符串表示方式
String& String::ToStr(String& str) const
{
// 把当前字符串复制到目标字符串后面
//str.Copy(*this, str.len);
str += *this;
return (String&)*this;
}
// 输出对象的字符串表示方式
String String::ToString() const
{
return *this;
}
// 清空已存储数据。
void String::Clear()
{
/*TArray::Clear();
_Length = 0;*/
release();
}
/*String& String::Append(char ch)
{
Copy(&ch, 1, len);
return *this;
}
String& String::Append(const char* str, int len)
{
Copy(str, len, len);
return *this;
}*/
/*char* _itoa(int value, char* str, int radix, int width = 0)
{
if (radix > 36 || radix <= 1) return 0;
// 先处理符号
uint v;
bool sign = (radix == 10 && value < 0);
if (sign)
v = -value;
else
v = (uint)value;
// 从低位数字开始,转为字符以后写入临时字符数组
char tmp[33];
char* tp = tmp;
while (v || tp == tmp)
{
int i = v % radix;
v = v / radix;
if (i < 10)
*tp++ = i + '0';
else
*tp++ = i + 'A' - 10;
}
char* sp = str;
// 修正宽度
if(width > 0)
{
width -= tp - tmp;
if (sign) width--;
while(width-- > 0) *sp++ = '0';
}
// 写入符号
if (sign) *sp++ = '-';
// 倒序写入目标字符串
while (tp > tmp)
*sp++ = *--tp;
*sp = 0;
return str;
}*/
/*// 写入整数,第二参数指定宽带,不足时补零
String& String::Append(int value, int radix, int width)
{
char ch[16];
_itoa(value, ch, radix, width);
return Append(ch);
}
String& String::Append(byte bt)
{
int k = len;
byte b = bt >> 4;
SetAt(k++, b > 9 ? ('A' + b - 10) : ('0' + b));
b = bt & 0x0F;
SetAt(k++, b > 9 ? ('A' + b - 10) : ('0' + b));
return *this;
}
String& String::Append(const ByteArray& bs)
{
bs.ToHex(*this);
return *this;
}*/
// 调试输出字符串
void String::Show(bool newLine) const
{
//if(!len) return;
// C格式字符串以0结尾
//char* p = buffer;
//if(p[len] != 0 && !IN_ROM_SECTION(p)) p[len] = 0;
if(len) debug_printf("%s", buffer);
if(newLine) debug_printf("\r\n");
}
// 格式化字符串,输出到现有字符串后面。方便我们连续格式化多个字符串
String& String::Format(const char* format, ...)
{
va_list ap;
//const char* fmt = format.buffer;
va_start(ap, format);
// 无法准确估计长度大概乘以2处理
CheckCapacity(len + (strlen(format) << 1));
//char* p = buffer;
int len2 = vsnprintf(buffer + len, capacity - len, format, ap);
len += len2;
va_end(ap);
return *this;
}
/*String& String::Concat(const Object& obj)
{
obj.ToStr(*this);
return *this;
}
String& String::Concat(const char* str, int len)
{
Copy(str, len, len);
return *this;
}*/
int String::IndexOf(const char ch, int startIndex) const
{
if(startIndex >= len) return -1;
auto p = strchr(buffer + startIndex, ch);
if(!p) return -1;
return p - buffer;
}
int String::IndexOf(const String& str, int startIndex) const
{
if(str.len == 0) return -1;
if(startIndex + str.len > len) return -1;
auto p = strstr(buffer + startIndex, str.buffer);
if(!p) return -1;
return p - buffer;
}
int String::IndexOf(const char* str, int startIndex) const
{
if(!str) return -1;
if(startIndex + strlen(str) > len) return -1;
auto p = strstr(buffer + startIndex, str);
if(!p) return -1;
return p - buffer;
}
int String::LastIndexOf(const char ch, int startIndex) const
{
if(startIndex >= len) return -1;
auto p = strrchr(buffer + startIndex, ch);
if(!p) return -1;
return p - buffer;
}
char *strrstr(const char* s, const char* str)
{
char *p;
int len = strlen(s);
for (p = (char*)s + len - 1; p >= s; p--) {
if ((*p == *str) && (memcmp(p, str, strlen(str)) == 0))
return p;
}
return NULL;
}
int String::LastIndexOf(const String& str, int startIndex) const
{
if(str.len == 0) return -1;
if(startIndex + str.len > len) return -1;
auto p = strrstr(buffer + startIndex, str.buffer);
if(!p) return -1;
return p - buffer;
}
int String::LastIndexOf(const char* str, int startIndex) const
{
if(!str) return -1;
if(startIndex + strlen(str) > len) return -1;
auto p = strrstr(buffer + startIndex, str);
if(!p) return -1;
return p - buffer;
}
bool String::StartsWith(const String& str, int startIndex) const
{
//return Sub(startIndex, str.len) == str;
if (startIndex + str.len > len || !buffer || !str.buffer) return false;
return strncmp(&buffer[startIndex], str.buffer, str.len) == 0;
}
bool String::StartsWith(const char* str, int startIndex) const
{
//return Sub(startIndex, strlen(str)) == str;
if(!str) return false;
int slen = strlen(str);
if (startIndex + slen > len || !buffer) return false;
return strncmp(&buffer[startIndex], str, slen) == 0;
}
bool String::EndsWith(const String& str) const
{
//return Sub(len - str.len, str.len) == str;
if(str.len == 0) return false;
if(str.len > len) return false;
return strncmp(&buffer[len - str.len], str.buffer, str.len) == 0;
}
bool String::EndsWith(const char* str) const
{
//return Sub(len - strlen(str), strlen(str)) == str;
if(!str) return false;
int slen = strlen(str);
if(slen > len) return false;
return strncmp(&buffer[len - slen], str, slen) == 0;
}
int String::Split(const String& str, StringItem callback)
{
if(str.Length() == 0) return 0;
int n = 0;
int p = 0;
int e = 0;
while(p < len)
{
// 找到下一个位置。如果找不到,直接移到末尾
e = IndexOf(str, p);
if(e < 0) e = len;
n++;
auto item = Substring(p, e - p);
callback(item);
// 如果在末尾,说明没有找到
if(e == len) break;
p = e + str.Length();
}
return n;
}
String String::Substring(int start, int length) const
{
String str;
//str.Copy(this, len, start);
if(len && start < len) str.copy(buffer + start, length);
return str;
}
void trim(char* buffer, int& len, bool trimBegin, bool trimEnd)
{
if (!buffer || len == 0) return;
char *begin = buffer;
if(trimBegin) while (isspace(*begin)) begin++;
char *end = buffer + len - 1;
if(trimEnd) while (isspace(*end) && end >= begin) end--;
len = end + 1 - begin;
if (begin > buffer) memcpy(buffer, begin, len);
buffer[len] = 0;
}
String& String::TrimStart()
{
/*String str;
auto ptr = buffer;
// 找到第一个不是空白字符的位置
int i = 0;
for(;i < len; i++)
{
auto ch = ptr[i];
if(ch != ' ' && ch != '\t' && ch != '\r' && ch != '\n') break;
}
str.copy(ptr + i, len - i);
return str;*/
trim(buffer, len, true, false);
return *this;
}
String& String::TrimEnd()
{
/*String str;
auto ptr = buffer;
// 找到最后一个不是空白字符的位置
int i = len - 1;
for(;i >= 0; i--)
{
auto ch = ptr[i];
if(ch != ' ' && ch != '\t' && ch != '\r' && ch != '\n') break;
}
str.copy(ptr, i + 1);
return str;*/
/*if (!buffer || len == 0) return;
char *begin = buffer;
//while (isspace(*begin)) begin++;
char *end = buffer + len - 1;
while (isspace(*end) && end >= begin) end--;
len = end + 1 - begin;
if (begin > buffer) memcpy(buffer, begin, len);
buffer[len] = 0;*/
trim(buffer, len, false, true);
return *this;
}
String& String::Trim()
{
//return TrimStart().TrimEnd();;
/*if (!buffer || len == 0) return;
char *begin = buffer;
while (isspace(*begin)) begin++;
char *end = buffer + len - 1;
while (isspace(*end) && end >= begin) end--;
len = end + 1 - begin;
if (begin > buffer) memcpy(buffer, begin, len);
buffer[len] = 0;*/
trim(buffer, len, true, true);
return *this;
}
/*String& String::operator+=(const Object& obj)
{
return this->Concat(obj);
}
String& String::operator+=(const char* str)
{
return this->Concat(str);
}
String& operator+(String& str1, const Object& obj)
{
return str1.Concat(obj);
}
String& operator+(String& str1, const char* str2)
{
return str1.Concat(str2);
}
String operator+(const char* str1, const char* str2)
{
String str(str1);
return str + str2;
}*/
/*String operator+(const char* str, const Object& obj)
{
// 要把字符串拷贝过来
String s;
s = str;
s += obj;
return s;
}*/
/*String operator+(const Object& obj, const char* str)
{
// 要把字符串拷贝过来
String s;
obj.ToStr(s);
s += str;
return s;
}*/
extern char* itoa(int value, char *string, int radix)
{
return ltoa(value, string, radix) ;
}
extern char* ltoa(Int64 value, char* string, int radix )
{
char tmp[33];
char *tp = tmp;
Int64 i;
ulong v;
int sign;
char *sp;
if ( string == NULL ) return 0 ;
if (radix > 36 || radix <= 1) return 0 ;
sign = (radix == 10 && value < 0);
if (sign)
v = -value;
else
v = (ulong)value;
while (v || tp == tmp)
{
i = v % radix;
v = v / radix;
if (i < 10)
*tp++ = i+'0';
else
*tp++ = i + 'a' - 10;
}
sp = string;
if (sign) *sp++ = '-';
while (tp > tmp)
*sp++ = *--tp;
*sp = 0;
return string;
}
extern char* utoa(uint value, char* string, int radix)
{
return ultoa(value, string, radix ) ;
}
extern char* ultoa(ulong value, char* string, int radix)
{
char tmp[33];
char *tp = tmp;
Int64 i;
ulong v = value;
char *sp;
if ( string == NULL ) return 0;
if (radix > 36 || radix <= 1) return 0;
while (v || tp == tmp)
{
i = v % radix;
v = v / radix;
if (i < 10)
*tp++ = i+'0';
else
*tp++ = i + 'a' - 10;
}
sp = string;
while (tp > tmp)
*sp++ = *--tp;
*sp = 0;
return string;
}
char *dtostrf (double val, char width, byte prec, char* sout)
{
char fmt[20];
sprintf(fmt, "%%%d.%df", width, prec);
sprintf(sout, fmt, val);
return sout;
}