mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-05-16 06:05:58 -06:00
416 lines
8.1 KiB
C++
416 lines
8.1 KiB
C++
template <class B>
|
|
force_inline
|
|
void AString<B>::Insert(int pos, const char *s)
|
|
{
|
|
Insert(pos, s, strlen__(s));
|
|
}
|
|
|
|
template <class B>
|
|
void AString<B>::Cat(int c, int count)
|
|
{
|
|
tchar *s = B::Insert(GetLength(), count, NULL);
|
|
while(count--)
|
|
*s++ = c;
|
|
}
|
|
|
|
template <class B>
|
|
force_inline
|
|
void AString<B>::Cat(const tchar *s)
|
|
{
|
|
Cat(s, strlen__(s));
|
|
}
|
|
|
|
template <class B>
|
|
int AString<B>::Compare(const tchar *b) const
|
|
{
|
|
const tchar *a = B::Begin();
|
|
const tchar *ae = End();
|
|
for(;;) {
|
|
if(a >= ae)
|
|
return *b == 0 ? 0 : -1;
|
|
if(*b == 0)
|
|
return 1;
|
|
int q = cmpval__(*a++) - cmpval__(*b++);
|
|
if(q)
|
|
return q;
|
|
}
|
|
}
|
|
|
|
template <class B>
|
|
typename AString<B>::String AString<B>::Mid(int from, int count) const
|
|
{
|
|
int l = GetLength();
|
|
if(from > l) from = l;
|
|
if(from < 0) from = 0;
|
|
if(count < 0)
|
|
count = 0;
|
|
if(from + count > l)
|
|
count = l - from;
|
|
return String(B::Begin() + from, count);
|
|
}
|
|
|
|
template <class B>
|
|
int AString<B>::Find(int chr, int from) const
|
|
{
|
|
ASSERT(from >= 0 && from <= GetLength());
|
|
const tchar *e = End();
|
|
const tchar *ptr = B::Begin();
|
|
for(const tchar *s = ptr + from; s < e; s++)
|
|
if(*s == chr)
|
|
return (int)(s - ptr);
|
|
return -1;
|
|
}
|
|
|
|
template <class B>
|
|
int AString<B>::ReverseFind(int chr, int from) const
|
|
{
|
|
ASSERT(from >= 0 && from <= GetLength());
|
|
if(from < GetLength()) {
|
|
const tchar *ptr = B::Begin();
|
|
for(const tchar *s = ptr + from; s >= ptr; s--)
|
|
if(*s == chr)
|
|
return (int)(s - ptr);
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
template <class B>
|
|
int AString<B>::ReverseFind(int len, const tchar *s, int from) const
|
|
{
|
|
ASSERT(from >= 0 && from <= GetLength());
|
|
if(from < GetLength()) {
|
|
const tchar *ptr = B::Begin();
|
|
const tchar *p = ptr + from - len + 1;
|
|
len *= sizeof(tchar);
|
|
while(p >= ptr) {
|
|
if(*s == *p && memcmp(s, p, len) == 0)
|
|
return (int)(p - ptr);
|
|
p--;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
template <class B>
|
|
int AString<B>::ReverseFindAfter(int len, const tchar *s, int from) const
|
|
{
|
|
int q = ReverseFind(len, s, from);
|
|
return q >= 0 ? q + len : -1;
|
|
}
|
|
|
|
template <class B>
|
|
void AString<B>::Replace(const tchar *find, int findlen, const tchar *replace, int replacelen)
|
|
{
|
|
if(findlen == 0)
|
|
return;
|
|
String r;
|
|
int i = 0;
|
|
const tchar *p = B::Begin();
|
|
for(;;) {
|
|
int j = Find(findlen, find, i);
|
|
if(j < 0)
|
|
break;
|
|
r.Cat(p + i, j - i);
|
|
r.Cat(replace, replacelen);
|
|
i = j + findlen;
|
|
}
|
|
r.Cat(p + i, B::GetCount() - i);
|
|
B::Free();
|
|
B::Set0(r);
|
|
}
|
|
|
|
template <class B>
|
|
int AString<B>::ReverseFind(const tchar *s, int from) const
|
|
{
|
|
return ReverseFind(strlen__(s), s, from);
|
|
}
|
|
|
|
template <class B>
|
|
int AString<B>::ReverseFindAfter(const tchar *s, int from) const
|
|
{
|
|
return ReverseFindAfter(strlen__(s), s, from);
|
|
}
|
|
|
|
template <class B>
|
|
int AString<B>::ReverseFind(int chr) const
|
|
{
|
|
return B::GetCount() ? ReverseFind(chr, B::GetCount() - 1) : -1;
|
|
}
|
|
|
|
template <class B>
|
|
void AString<B>::Replace(const String& find, const String& replace)
|
|
{
|
|
Replace(~find, find.GetCount(), ~replace, replace.GetCount());
|
|
}
|
|
|
|
template <class B>
|
|
force_inline
|
|
void AString<B>::Replace(const tchar *find, const tchar *replace)
|
|
{
|
|
Replace(find, (int)strlen__(find), replace, (int)strlen__(replace));
|
|
}
|
|
|
|
template <class B>
|
|
force_inline
|
|
void AString<B>::Replace(const String& find, const tchar *replace)
|
|
{
|
|
Replace(~find, find.GetCount(), replace, (int)strlen__(replace));
|
|
}
|
|
|
|
template <class B>
|
|
force_inline
|
|
void AString<B>::Replace(const tchar *find, const String& replace)
|
|
{
|
|
Replace(find, (int)strlen__(find), ~replace, replace.GetCount());
|
|
}
|
|
|
|
template <class B>
|
|
bool AString<B>::StartsWith(const tchar *s, int len) const
|
|
{
|
|
if(len > GetLength()) return false;
|
|
return memcmp(s, B::Begin(), len * sizeof(tchar)) == 0;
|
|
}
|
|
|
|
template <class B>
|
|
force_inline
|
|
bool AString<B>::StartsWith(const tchar *s) const
|
|
{
|
|
return StartsWith(s, strlen__(s));
|
|
}
|
|
|
|
template <class B>
|
|
bool AString<B>::EndsWith(const tchar *s, int len) const
|
|
{
|
|
int l = GetLength();
|
|
if(len > l) return false;
|
|
return memcmp(s, B::Begin() + l - len, len * sizeof(tchar)) == 0;
|
|
}
|
|
|
|
template <class B>
|
|
force_inline
|
|
bool AString<B>::EndsWith(const tchar *s) const
|
|
{
|
|
return EndsWith(s, strlen__(s));
|
|
}
|
|
|
|
template <class B>
|
|
int AString<B>::FindFirstOf(int len, const tchar *s, int from) const
|
|
{
|
|
ASSERT(from >= 0 && from <= GetLength());
|
|
const tchar *ptr = B::Begin();
|
|
const tchar *e = B::End();
|
|
const tchar *se = s + len;
|
|
if(len == 1) {
|
|
tchar c1 = s[0];
|
|
for(const tchar *bs = ptr + from; bs < e; bs++) {
|
|
if(*bs == c1)
|
|
return (int)(bs - ptr);
|
|
}
|
|
return -1;
|
|
}
|
|
if(len == 2) {
|
|
tchar c1 = s[0];
|
|
tchar c2 = s[1];
|
|
for(const tchar *bs = ptr + from; bs < e; bs++) {
|
|
tchar ch = *bs;
|
|
if(ch == c1 || ch == c2)
|
|
return (int)(bs - ptr);
|
|
}
|
|
return -1;
|
|
}
|
|
if(len == 3) {
|
|
tchar c1 = s[0];
|
|
tchar c2 = s[1];
|
|
tchar c3 = s[2];
|
|
for(const tchar *bs = ptr + from; bs < e; bs++) {
|
|
tchar ch = *bs;
|
|
if(ch == c1 || ch == c2 || ch == c3)
|
|
return (int)(bs - ptr);
|
|
}
|
|
return -1;
|
|
}
|
|
if(len == 4) {
|
|
tchar c1 = s[0];
|
|
tchar c2 = s[1];
|
|
tchar c3 = s[2];
|
|
tchar c4 = s[3];
|
|
for(const tchar *bs = ptr + from; bs < e; bs++) {
|
|
tchar ch = *bs;
|
|
if(ch == c1 || ch == c2 || ch == c3 || ch == c4)
|
|
return (int)(bs - ptr);
|
|
}
|
|
return -1;
|
|
}
|
|
for(const tchar *bs = ptr + from; bs < e; bs++)
|
|
for(const tchar *ss = s; ss < se; ss++)
|
|
if(*bs == *ss)
|
|
return (int)(bs - ptr);
|
|
return -1;
|
|
}
|
|
|
|
force_inline
|
|
void String0::Set(const char *s, int len)
|
|
{
|
|
Clear();
|
|
if(len <= 14) {
|
|
memcpy8(chr, s, len);
|
|
SLen() = len;
|
|
Dsyn();
|
|
return;
|
|
}
|
|
SetL(s, len);
|
|
Dsyn();
|
|
}
|
|
|
|
force_inline
|
|
void String0::Set0(const char *s, int len)
|
|
{
|
|
Zero();
|
|
if(len <= 14) {
|
|
SLen() = len;
|
|
memcpy8(chr, s, len);
|
|
Dsyn();
|
|
return;
|
|
}
|
|
SetL(s, len);
|
|
Dsyn();
|
|
}
|
|
|
|
inline
|
|
bool String0::IsEqual(const char *s) const
|
|
{ // This is optimized for comparison with string literals...
|
|
size_t len = strlen(s);
|
|
const void *p;
|
|
if(IsSmall()) {
|
|
if(len > 14 || len != (size_t)chr[SLEN]) return false; // len > 14 fixes issue with GCC warning, might improves performance too
|
|
p = chr;
|
|
}
|
|
else {
|
|
if(len != (size_t)w[LLEN]) return false;
|
|
p = ptr;
|
|
}
|
|
return memcmp(p, s, len) == 0; // compiler is happy to optimize memcmp out with up to 64bit comparisons for literals...
|
|
}
|
|
|
|
inline
|
|
int String0::Compare(const String0& s) const
|
|
{
|
|
#ifdef CPU_LE
|
|
if((chr[KIND] | s.chr[KIND]) == 0) { // both strings are small, len is the MSB
|
|
#ifdef CPU_64
|
|
uint64 a = SwapEndian64(q[0]);
|
|
uint64 b = SwapEndian64(s.q[0]);
|
|
if(a != b)
|
|
return a < b ? -1 : 1;
|
|
a = SwapEndian64(q[1]);
|
|
b = SwapEndian64(s.q[1]);
|
|
return a == b ? 0 : a < b ? -1 : 1;
|
|
#else
|
|
uint64 a = SwapEndian32(w[0]);
|
|
uint64 b = SwapEndian32(s.w[0]);
|
|
if(a != b)
|
|
return a < b ? -1 : 1;
|
|
a = SwapEndian32(w[1]);
|
|
b = SwapEndian32(s.w[1]);
|
|
if(a != b)
|
|
return a < b ? -1 : 1;
|
|
a = SwapEndian32(w[2]);
|
|
b = SwapEndian32(s.w[2]);
|
|
if(a != b)
|
|
return a < b ? -1 : 1;
|
|
a = SwapEndian32(w[3]);
|
|
b = SwapEndian32(s.w[3]);
|
|
return a == b ? 0 : a < b ? -1 : 1;
|
|
#endif
|
|
}
|
|
#endif
|
|
return CompareL(s);
|
|
}
|
|
|
|
force_inline
|
|
String& String::operator=(const char *s)
|
|
{
|
|
AssignLen(s, strlen__(s));
|
|
return *this;
|
|
}
|
|
|
|
force_inline
|
|
String::String(const char *s)
|
|
{
|
|
String0::Set0(s, strlen__(s));
|
|
}
|
|
|
|
force_inline
|
|
void String0::Swap(String0& b)
|
|
{
|
|
qword a0 = q[0]; // Explicit code (instead of Swap) seems to emit some SSE2 code with CLANG
|
|
qword a1 = q[1];
|
|
qword b0 = b.q[0];
|
|
qword b1 = b.q[1];
|
|
q[0] = b0;
|
|
q[1] = b1;
|
|
b.q[0] = a0;
|
|
b.q[1] = a1;
|
|
Dsyn(); b.Dsyn();
|
|
}
|
|
|
|
template <class Maker>
|
|
inline
|
|
String String::Make(int alloc, Maker m)
|
|
{
|
|
String s;
|
|
if(alloc <= 14) {
|
|
int len = m(s.chr);
|
|
ASSERT(len <= alloc);
|
|
s.SLen() = len;
|
|
s.Dsyn();
|
|
}
|
|
else {
|
|
if(alloc < 32) {
|
|
s.chr[KIND] = MEDIUM;
|
|
s.ptr = (char *)MemoryAlloc32();
|
|
}
|
|
else
|
|
s.ptr = s.Alloc(alloc, s.chr[KIND]);
|
|
int len = m(s.ptr);
|
|
ASSERT(len <= alloc);
|
|
s.ptr[len] = 0;
|
|
s.LLen() = len;
|
|
s.SLen() = 15;
|
|
if(alloc >= 32 && alloc > 2 * len)
|
|
s.Shrink();
|
|
}
|
|
return s;
|
|
}
|
|
|
|
force_inline
|
|
void StringBuffer::Strlen()
|
|
{
|
|
SetLength((int)strlen__(pbegin));
|
|
}
|
|
|
|
inline
|
|
void StringBuffer::Cat(const char *s, int l)
|
|
{
|
|
if(pend + l > limit)
|
|
ReallocL(s, l);
|
|
else {
|
|
memcpy8(pend, s, l);
|
|
pend += l;
|
|
}
|
|
}
|
|
|
|
inline
|
|
void StringBuffer::Cat(int c, int l)
|
|
{
|
|
if(pend + l > limit)
|
|
ReallocL(NULL, l);
|
|
memset8(pend, c, l);
|
|
pend += l;
|
|
}
|
|
|
|
force_inline
|
|
void StringBuffer::Cat(const char *s)
|
|
{
|
|
Cat(s, (int)strlen__(s));
|
|
}
|