#include "wobject/xstring.hpp"
|
#include "platform/nstring.hpp"
|
#include "platform/nmemory.hpp"
|
#include "system/itemalloc.hpp"
|
#include "win32/win.hpp"
|
#include <vector>
|
//#include <new.h>
|
|
template<class T>
|
class KStringBlock
|
{
|
private:
|
static const unsigned int kShouldFree = 0x1;
|
static const unsigned int kShouldSysFree = 0x2;
|
static const unsigned int kUTF16 = 0x4;
|
static const unsigned int kUTF8 = 0x8;
|
static const unsigned int kACP = 0x10;
|
private:
|
union
|
{
|
T* m_val;
|
T m_buff[16];
|
};
|
int m_len;
|
int m_ref;
|
unsigned int flag;
|
public:
|
void AddRef()
|
{
|
m_ref++;
|
}
|
void Release()
|
{
|
m_ref--;
|
if (m_ref == 0)
|
{
|
if (flag & kShouldSysFree)
|
::SysFreeString((BSTR)m_val);
|
else if (flag & kShouldFree)
|
{
|
if(m_len>=16)free(m_val,m_len);
|
}
|
|
this->~KStringBlock();
|
MyAllocer().free(this);
|
}
|
}
|
public:
|
const T* str()
|
{
|
return (m_len<16 && (flag & kShouldSysFree)==0)? (const T*)m_buff : (const T*)m_val;
|
}
|
private:
|
KStringBlock() :m_val(nullptr), m_len(0), m_ref(1), flag(0) {}
|
KStringBlock(wchar_t* val, bool shouldfree, bool shouldsysfree)
|
:m_val(val), m_len(val ? (int)nstring::length(val) : 0), m_ref(1), flag(kUTF16 | (shouldfree ? kShouldFree : 0) | (shouldsysfree ? kShouldSysFree : 0))
|
{
|
|
}
|
KStringBlock(char* val, bool shouldfree, bool shouldsysfree)
|
:m_val(val), m_len(val ? (int)nstring::length(val) : 0), m_ref(1), flag(kACP | (shouldfree ? kShouldFree : 0) | (shouldsysfree ? kShouldSysFree : 0))
|
{
|
|
}
|
|
~KStringBlock()
|
{
|
}
|
|
void initial()
|
{
|
m_val =nullptr;
|
m_len = 0;
|
m_ref=1;
|
flag = kShouldFree | kUTF16;
|
}
|
public:
|
static ItemAlloc<T[32], 4096>* stringBlock32;
|
static ItemAlloc<T[64], 4096>* stringBlock64;
|
static ItemAlloc<T[128], 4096>* stringBlock128;
|
static ItemAlloc<T[256], 4096>* stringBlock256;
|
static ItemAlloc<KStringBlock<T>, 4096>* stringBlockMgr;
|
public:
|
static ItemAlloc<KStringBlock<T>, 4096>& MyAllocer()
|
{
|
//static ItemAlloc<KStringBlock<T>, 4096> stringBlockMgr;
|
//ItemAlloc<KStringBlock<T>, 4096>* stringBlockMgr=new (ItemAlloc<KStringBlock<T>, 4096>);
|
if(!stringBlockMgr)stringBlockMgr=new ItemAlloc<KStringBlock<T>, 4096>();
|
return *stringBlockMgr;
|
}
|
|
static KStringBlock<wchar_t>* make()
|
{
|
KStringBlock<wchar_t> * p = MyAllocer().alloc();
|
p->initial();
|
|
return p;
|
}
|
|
static KStringBlock<char>* make(char* value, bool shouldSysFree)
|
{
|
if(!value)return nullptr;
|
int len = nstring::length(value);
|
|
KStringBlock<char> * p = MyAllocer().alloc();
|
//p = new (p) KStringBlock<char>();
|
p->initial();
|
p->flag = kACP | kShouldFree;
|
p->m_len = len;
|
if(shouldSysFree)
|
{
|
m_val = value;
|
if(shouldSysFree) p->flag |= kShouldSysFree;
|
}else
|
{
|
if(len<16)
|
nstring::cpy(m_buff,value);
|
else
|
{
|
m_val = p->alloc(m_len+1);
|
nstring::cpy(m_val,value);
|
}
|
}
|
return p;
|
}
|
|
static KStringBlock<wchar_t>* make(wchar_t* value, bool shouldSysFree)
|
{
|
if(!value)return nullptr;
|
int len = nstring::length(value);
|
|
KStringBlock<wchar_t> * p = MyAllocer().alloc();
|
//p = new (p) KStringBlock<wchar_t>();
|
p->initial();
|
p->flag = kUTF16 | kShouldFree;
|
p->m_len =len;
|
if(shouldSysFree)
|
{
|
p->m_val = value;
|
if(shouldSysFree) p->flag |= kShouldSysFree;
|
}else
|
{
|
if(len<16)
|
nstring::cpy(p->m_buff,value);
|
else
|
{
|
p->m_val = p->alloc(p->m_len+1);
|
nstring::cpy(p->m_val,value);
|
}
|
}
|
return p;
|
}
|
|
static KStringBlock<wchar_t>* make(int value)
|
{
|
int len = 15;
|
|
KStringBlock<wchar_t> * p = MyAllocer().alloc();
|
//p = new (p) KStringBlock<wchar_t>();
|
p->initial();
|
p->flag = kUTF16 | kShouldFree;
|
p->m_len = len;
|
nstring::toWStr(value,p->alloc(p->m_len+1),p->m_len+1);
|
return p;
|
}
|
static KStringBlock<wchar_t>* make(double value)
|
{
|
int len = 31;
|
|
KStringBlock<wchar_t> * p = MyAllocer().alloc();
|
//p = new (p) KStringBlock<wchar_t>();
|
p->initial();
|
p->flag = kUTF16 | kShouldFree;
|
p->m_len = len;
|
p->m_val = p->alloc(p->m_len + 1);
|
nstring::toWStr(value,p->m_val,p->m_len+1);
|
return p;
|
}
|
|
static KStringBlock<wchar_t>* make(LPARAM value)
|
{
|
int len = 31;
|
|
KStringBlock<wchar_t> * p = MyAllocer().alloc();
|
//p = new (p) KStringBlock<wchar_t>();
|
p->initial();
|
p->flag = kUTF16 | kShouldFree;
|
p->m_len = len;
|
p->m_val = p->alloc(p->m_len + 1);
|
nstring::toWStr(value,p->m_val,p->m_len+1);
|
return p;
|
}
|
public:
|
int length()
|
{
|
return this->m_len;
|
}
|
|
T* sure(int size)
|
{
|
if(size <=0) return nullptr;
|
m_len = size - 1;
|
if(size < 16) return m_buff;
|
m_val = this->alloc(size);
|
return m_val;
|
}
|
private:
|
T* alloc(int size)
|
{
|
if(size <= 16) return m_buff;
|
if(size <=32)
|
{
|
if(!stringBlock32)stringBlock32 = new ItemAlloc<wchar_t[32], 4096>;
|
return (T*)stringBlock32->alloc();
|
}
|
if(size <=64)
|
{
|
if(!stringBlock64)stringBlock64 = new ItemAlloc<wchar_t[64], 4096>;
|
return (T*)stringBlock64->alloc();
|
}
|
if(size <=128)
|
{
|
if(!stringBlock128)stringBlock128 = new ItemAlloc<wchar_t[128], 4096>;
|
return (T*)stringBlock128->alloc();
|
}
|
if(size <=256)
|
{
|
if(!stringBlock256)stringBlock256 = new ItemAlloc<wchar_t[256], 4096>;
|
return (T*)stringBlock256->alloc();
|
}
|
return new T[size];
|
}
|
void free(T* p, int size)
|
{
|
if(!p) return;
|
if(p==m_buff) return;
|
if(size <32)return stringBlock32->free(p);
|
if(size <64)return stringBlock64->free(p);
|
if(size <128)return stringBlock128->free(p);
|
if(size <256)return stringBlock256->free(p);
|
return delete p;
|
}
|
};
|
|
template<> ItemAlloc<wchar_t[32], 4096>* KStringBlock<wchar_t>::stringBlock32 = 0;
|
template<> ItemAlloc<wchar_t[64], 4096>* KStringBlock<wchar_t>::stringBlock64 = 0;
|
template<> ItemAlloc<wchar_t[128], 4096>* KStringBlock<wchar_t>::stringBlock128 = 0;
|
template<> ItemAlloc<wchar_t[256], 4096>* KStringBlock<wchar_t>::stringBlock256 = 0;
|
template<> ItemAlloc<KStringBlock<wchar_t>, 4096>* KStringBlock<wchar_t>::stringBlockMgr = 0;
|
|
xstring::xstring() :data(nullptr)
|
{
|
|
}
|
xstring::xstring(const xstring& rhs):data(rhs.data)
|
{
|
if(rhs.data)((KStringBlock<wchar_t>*)rhs.data)->AddRef();
|
}
|
|
|
xstring::xstring(wchar_t* val, bool shouldSysFree) :data(KStringBlock<wchar_t>::make(val,shouldSysFree))
|
{
|
|
}
|
xstring::xstring(const wchar_t* val, bool shouldSysFree):data(KStringBlock<wchar_t>::make((wchar_t*)val,shouldSysFree))
|
{
|
|
}
|
|
xstring::xstring(int val):data((KStringBlock<wchar_t>::make(val)))
|
{
|
|
}
|
xstring::xstring(LPARAM val, bool bdata) :data(bdata?(void*)val:(KStringBlock<wchar_t>::make(val)))
|
{
|
if (bdata)
|
{
|
((KStringBlock<wchar_t>*)data)->AddRef();
|
}
|
}
|
|
xstring::xstring(double val):data((KStringBlock<wchar_t>::make(val)))
|
{
|
|
}
|
|
|
xstring::~xstring()
|
{
|
if(data) ((KStringBlock<wchar_t>*)data)->Release();
|
}
|
xstring& xstring::operator =(const xstring& rhs)
|
{
|
if (data)((KStringBlock<wchar_t>*)data)->Release();
|
if (rhs.data)
|
{
|
((KStringBlock<wchar_t>*)rhs.data)->AddRef();
|
data = rhs.data;
|
}
|
else
|
data = nullptr;
|
return *this;
|
}
|
xstring& xstring::operator =(const wchar_t* rhs)
|
{
|
if (data)((KStringBlock<wchar_t>*)data)->Release();
|
data = KStringBlock<wchar_t>::make((wchar_t*)rhs,false);
|
return *this;
|
}
|
|
bool xstring::isEmpty()
|
{
|
if(!data) return true;
|
const wchar_t* str = ((KStringBlock<wchar_t>*)data)->str();
|
if(!str)return true;
|
if(str[0]==0)return true;
|
return false;
|
}
|
|
bool xstring::operator ==(const wchar_t* rhs)
|
{
|
bool rhsEmpty = !rhs || rhs[0]==0;
|
if(rhsEmpty && isEmpty()) return true;
|
if(rhsEmpty != isEmpty()) return false;
|
return nstring::cmp(c_str(),rhs)==0;
|
}
|
|
bool xstring::operator >=(const wchar_t* rhs)
|
{
|
bool rhsEmpty = !rhs || rhs[0]==0;
|
if(rhsEmpty) return true;
|
if(isEmpty()) return false;
|
return nstring::cmp(c_str(),rhs)>=0;
|
}
|
bool xstring::operator >(const wchar_t* rhs)
|
{
|
bool rhsEmpty = !rhs || rhs[0]==0;
|
if(rhsEmpty) return isEmpty()?false:true;
|
if(isEmpty())return false;
|
return nstring::cmp(c_str(),rhs)>0;
|
}
|
|
bool xstring::operator <=(const wchar_t* rhs)
|
{
|
return !this->operator >(rhs);
|
}
|
|
bool xstring::operator <(const wchar_t* rhs)
|
{
|
return !this->operator >=(rhs);
|
}
|
bool xstring::operator !=(const wchar_t* rhs)
|
{
|
return !operator ==(rhs);
|
}
|
|
bool xstring::operator ==(const xstring& rhs)
|
{
|
return operator==(rhs.c_str());
|
}
|
bool xstring::operator >=(const xstring& rhs)
|
{
|
return operator>=(rhs.c_str());
|
}
|
bool xstring::operator >(const xstring& rhs)
|
{
|
return operator>(rhs.c_str());
|
}
|
bool xstring::operator <=(const xstring& rhs)
|
{
|
return operator<=(rhs.c_str());
|
}
|
bool xstring::operator <(const xstring& rhs)
|
{
|
return operator<(rhs.c_str());
|
}
|
bool xstring::operator !=(const xstring& rhs)
|
{
|
return operator!=(rhs.c_str());
|
}
|
|
xstring::operator bool()
|
{
|
return !this->isEmpty();
|
}
|
|
const wchar_t* xstring::c_str(bool bclone) const{
|
if(!data) return nullptr;
|
const wchar_t* val = ((KStringBlock<wchar_t>*)data)->str();
|
return bclone ? nstring::clone(val) : val;
|
}
|
|
int xstring::length()
|
{
|
if(!data) return 0;
|
if (c_str())return nstring::length(c_str());
|
return 0;
|
//return ((KStringBlock<wchar_t>*)data)->length();
|
}
|
|
wchar_t xstring::at(int index)
|
{
|
if(index < 0) return 0;
|
if(isEmpty()) return 0;
|
if(index >= length()) return 0;
|
return c_str()[index];
|
}
|
|
xstring xstring::concat(xstring && rhs)
|
{
|
return concat(rhs.c_str());
|
}
|
|
xstring xstring::concat(const wchar_t* rhs)
|
{
|
if(!rhs) return *this;
|
|
xstring xs;
|
KStringBlock<wchar_t>* pdata = KStringBlock<wchar_t>::make();
|
xs.data = pdata;
|
int len = length()+nstring::length(rhs);
|
wchar_t* buffer = pdata->sure(len+1);
|
if(length())nstring::cpy(buffer,c_str());
|
if(rhs)nstring::cpy(buffer +length(), rhs);
|
return xs;
|
}
|
|
xstring xstring::operator +(const wchar_t* rhs)
|
{
|
return concat(rhs);
|
}
|
|
xstring xstring::operator +(xstring rhs)
|
{
|
return concat(rhs.c_str());
|
}
|
|
int xstring::find(const xstring & str)
|
{
|
return find(str.c_str());
|
}
|
|
int xstring::find(const wchar_t* str)
|
{
|
if (!str)return -1;
|
if (!data)return -1;
|
const wchar_t* p = nstring::str(c_str(), str);
|
if(!p) return -1;
|
return p - c_str();
|
}
|
|
int xstring::find(const wchar_t* str,int pos)
|
{
|
if (!str)return -1;
|
if (!data)return -1;
|
if(pos >= nstring::length(c_str()))return -1;
|
const wchar_t* p = nstring::str(c_str()+pos, str);
|
if(!p) return -1;
|
return p - c_str();
|
}
|
|
wchar_t* xstring::sure(int len)
|
{
|
KStringBlock<wchar_t>* pdata = KStringBlock<wchar_t>::make();
|
this->data = pdata;
|
return pdata->sure(len);
|
}
|
|
xstring xstring::mid(int start, int len)
|
{
|
if (!data) return xstring();
|
if (nstring::length(c_str()) < start) return xstring();
|
len = start + len > nstring::length(c_str()) ? nstring::length(c_str()) - start : len;
|
|
xstring xs;
|
wchar_t* buffer = xs.sure(len+1);
|
nstring::ncpy(buffer, c_str() + start, len);
|
buffer[len] = 0;
|
return xs;
|
}
|
|
xstring xstring::left(int len)
|
{
|
if(!data) return xstring();
|
if(len<1) return xstring();
|
if(len > nstring::length(c_str())) len = nstring::length(c_str());
|
xstring xs;
|
wchar_t* buffer = xs.sure(len+1);
|
nstring::ncpy(buffer,c_str(),len);
|
buffer[len] = 0;
|
return xs;
|
}
|
|
xstring xstring::right(int len)
|
{
|
if (!data) return xstring();
|
if (len < 1) return xstring();
|
if (len > nstring::length(c_str())) len = nstring::length(c_str());
|
xstring xs;
|
wchar_t* buffer = xs.sure(len + 1);
|
nstring::ncpy(buffer, c_str() + (nstring::length(c_str()) - len), len);
|
buffer[len] = 0;
|
return xs;
|
}
|
|
|
int xstring::toInt()
|
{
|
if (!data)return 0;
|
return nstring::toInt((wchar_t*)c_str());
|
}
|
|
__int64 xstring::toInt64()
|
{
|
if (!data)return 0;
|
return nstring::toInt64((wchar_t*)c_str());
|
}
|
double xstring::toDouble()
|
{
|
return nstring::toDouble((wchar_t*)c_str());
|
}
|
xstring xstring::toUpper()
|
{
|
return nstring::toUpper((wchar_t*)c_str());
|
}
|
xstring xstring::toLower()
|
{
|
return nstring::toLower((wchar_t*)c_str());
|
}
|
|
xstring& xstring::operator +=(const wchar_t* rhs)
|
{
|
xstring xs = *this;
|
*this = xs + rhs;
|
return *this;
|
}
|
|
xstring& xstring::operator +=(xstring rhs)
|
{
|
return operator +=(rhs.c_str());
|
}
|
|
xstring xstring::trim()
|
{
|
xstring xs(c_str());
|
return xstring(nstring::trim_((wchar_t*)c_str(), (wchar_t*)xs.c_str()));
|
}
|
xstring xstring::rtrim()
|
{
|
xstring xs(c_str());
|
return xstring(nstring::rtrim_((wchar_t*)c_str(), (wchar_t*)xs.c_str()));
|
}
|
xstring xstring::ltrim()
|
{
|
xstring xs(c_str());
|
return xstring(nstring::ltrim_((wchar_t*)c_str(), (wchar_t*)xs.c_str()));
|
}
|
|
bool xstring::isNumber()
|
{
|
const wchar_t* val = c_str();
|
int len = length();
|
int i = 0;
|
int cnt = 0;
|
int e = 0;
|
bool hasNumber = false;
|
for (i = 0; i < len; i++)
|
{
|
wchar_t ch = val[i] & 0xff;
|
if (ch >= L'0' && ch <= L'9')
|
{
|
hasNumber = true;
|
continue;
|
}
|
else if (ch == L'e' || ch == L'E')
|
{
|
if (e == 0 && hasNumber)
|
{
|
e = 1;
|
hasNumber = false;
|
continue;
|
}
|
else
|
return false;
|
}
|
else if (ch == L'-')
|
{
|
if (hasNumber) return false;
|
hasNumber = true;
|
continue;
|
}
|
else if (ch == L'.')
|
{
|
if (cnt == 1) return false;
|
if (e) return false;
|
cnt = 1;
|
continue;
|
}
|
else if (ch == ' ')continue;
|
break;
|
}
|
if (i == len) return true;
|
return false;
|
}
|
|
xstring xstring::replace(const wchar_t* from, const wchar_t* to)
|
{
|
return replace(from, to, 0);
|
}
|
xstring xstring::replace(const wchar_t* from, const wchar_t* to, int pos)
|
{
|
const wchar_t* pstr = c_str();
|
if (!pstr) return 0;
|
if (!from[0]) return pstr;
|
if (pos < 1) pos = 0;
|
|
int len = (int)nstring::length(from);
|
if (len < 0) return pstr;
|
|
std::vector<int> arpos;
|
const wchar_t* ptext = pstr;
|
ptext = wcsstr(ptext + pos, from);
|
if (!ptext) return pstr;
|
while (ptext)
|
{
|
arpos.push_back((int)(ptext - pstr));
|
ptext = wcsstr(ptext + len, from);
|
}
|
|
int tolen = (int)wcslen(to);
|
int inc = ((int)arpos.size()) * (tolen - len);
|
|
int nlen = (int)wcslen(pstr) + inc + 1;
|
int start = 0;
|
int end = 0;
|
|
wchar_t* p = new wchar_t[nlen];
|
memset(p, 0, nlen * 2);
|
wchar_t* np = p;
|
arpos.push_back((int)wcslen(pstr));
|
for (int i = 0; i < (int)arpos.size(); i++)
|
{
|
end = arpos[i];
|
if (end - start > 0)
|
{
|
wcsncpy_s(np, end - start + 1, pstr + start, end - start);
|
np += end - start;
|
}
|
if (i != (int)arpos.size() - 1)
|
{
|
if (tolen)
|
{
|
wcsncpy_s(np, tolen + 1, to, tolen);
|
np += tolen;
|
}
|
}
|
start = end + len;
|
}
|
return p;
|
}
|
|
|
xstring operator +(const wchar_t* lhs, const xstring& rhs)
|
{
|
return xstring(lhs).concat(rhs.c_str());
|
}
|