template typename AString::Data *AString::Alloc(int alloc) { // LOG("Alloc " << alloc); alloc = (HeapRoundUp((max(alloc, 5) + 1) * sizeof(T) + sizeof(Data)) - sizeof(Data)) / sizeof(T) - 1; // LOG("Rounded Alloc " << alloc << ": " << (alloc + 1) * sizeof(T) + sizeof(Data)); Data *newdata = (Data *) new byte[sizeof(Data) + sizeof(T) * (alloc + 1)]; newdata->alloc = alloc; newdata->length = 0; AtomicWrite(newdata->refcount, 1); return newdata; } template typename AString::Data *AString::Clone(const typename AString::Data *data, int newalloc) { Data *newdata = Alloc(newalloc); newdata->length = min(data->length, newalloc); memcpy(newdata->GetPtr(), data->GetPtr(), sizeof(T) * newdata->length); newdata->GetPtr()[newdata->length] = 0; return newdata; } template T *AString::CreateEmpty(typename AString::Data *data) { AtomicInc(data->refcount); return (T *)(data + 1); } template T *AString::Create(int len) { if(!len) return S::CreateNull(); Data *n = Alloc(len); n->length = len; T *p = (T *)(n + 1); *(p + len) = 0; return p; } template T *AString::Create(const T *data, int len) { if(!len) return S::CreateNull(); T *ptr = Create(len); memcpy(ptr, data, sizeof(T) * len); ptr[len] = 0; return ptr; } template void AString::Cat(const T *s, int len) { Chk(); Data *d = GetData(ptr); if(AtomicRead(d->refcount) == 1 && d->length + len <= d->alloc) { memcpy(ptr + d->length, s, sizeof(T) * len); d->length += len; ptr[d->length] = 0; } else { Data *nd = Clone(d, d->length + max(d->length, len)); ptr = nd->GetPtr(); memcpy(ptr + d->length, s, sizeof(T) * len); d->Release(); nd->length += len; ptr[nd->length] = 0; } } template void AString::Cat(int c) { Chk(); Data *d = GetData(ptr); if(AtomicRead(d->refcount) != 1 || d->length >= d->alloc) { Data *nd = Clone(d, d->length + max(d->length, 1)); ptr = nd->GetPtr(); d->Release(); d = nd; } ptr[d->length++] = c; ptr[d->length] = 0; } template void AString::Cat(int c, int count) { Chk(); Data *d = GetData(ptr); if(AtomicRead(d->refcount) != 1 || d->length + count > d->alloc) { Data *nd = Clone(d, d->length + max(d->length, count)); ptr = nd->GetPtr(); d->Release(); d = nd; } Fill(ptr + d->length, ptr + d->length + count, (T)c); d->length += count; ptr[d->length] = 0; } template void AString::Insert(int at, const T *s, int len) { Chk(); ASSERT(at >= 0 && at <= GetLength()); Data *d = GetData(ptr); if(AtomicRead(d->refcount) == 1 && d->length + len <= d->alloc && !(s >= ptr && s < ptr + d->length)) { memmove(ptr + at + len, ptr + at, sizeof(T) * (d->length - at + 1)); memcpy(ptr + at, s, sizeof(T) * len); d->length += len; } else { Data *nd = Alloc(d->length + max(d->length, len)); T *nptr = nd->GetPtr(); memcpy(nptr, ptr, sizeof(T) * at); memcpy(nptr + at, s, sizeof(T) * len); memcpy(nptr + at + len, ptr + at, sizeof(T) * (d->length - at + 1)); ptr = nd->GetPtr(); nd->length += d->length + len; d->Release(); } } template void AString::Insert(int at, int c) { T x = c; Insert(at, &x, 1); } template void AString::Remove(int at, int count) { Chk(); ASSERT(at >= 0 && at + count <= GetLength() && count >= 0); Data *d = GetData(ptr); if(AtomicRead(d->refcount) != 1) { Data *nd = Clone(d, d->length + max(d->length, count)); ptr = nd->GetPtr(); d->Release(); d = nd; } memmove(ptr + at, ptr + at + count, sizeof(T) * (d->length - at - count + 1)); d->length -= count; } template void AString::Trim(int at) { Chk(); ASSERT(at <= GetLength()); if(at >= GetLength()) return; Data *d = GetData(ptr); if(AtomicRead(d->refcount) != 1) { Data *nd = Clone(d, at); ptr = nd->GetPtr(); d->Release(); d = nd; } d->length = at; ptr[d->length] = 0; } template void AString::Clear() { Chk(); Release(); ptr = S::CreateNull(); } template void AString::Shrink() { Chk(); Data *d = GetData(ptr); Data *nd = Clone(d, d->length); ptr = nd->GetPtr(); d->Release(); } template void AString::Reserve(int len) { Chk(); Data *d = GetData(ptr); if(len < d->alloc) return; Data *nd = Clone(d, len); ptr = nd->GetPtr(); d->Release(); } template T *AString::GetBuffer(int len) { ASSERT(len >= 0); Data *d = GetData(ptr); if(AtomicRead(d->refcount) != 1 || len >= d->alloc) { Data *nd = Clone(d, len); d->Release(); d = nd; ptr = d->GetPtr(); } #ifdef _DEBUG AtomicWrite(d->refcount, 0); #endif return ptr; } template void AString::ReleaseBuffer(int len) { Data *d = GetData(ptr); if(len < 0) len = strlen__(ptr); ASSERT(len <= d->alloc && d->refcount == 0); ptr[len] = 0; d->length = len; #ifdef _DEBUG AtomicWrite(d->refcount, 1); #endif } template void AString::Assign(const AString& s) { Chk(); s.Retain(); Release(); ptr = s.ptr; } template void AString::Assign(const T *s, int len) { Chk(); T *q = Create(s, len); Release(); ptr = q; } template void AString::DeepAssign(const AString& s) { Chk(); T *q = Create(s.ptr, s.GetLength()); Release(); ptr = q; } template void AString::Set(int i, int chr) { ASSERT(i >= 0 && i < GetLength()); Data *d = GetData(ptr); if(AtomicRead(d->refcount) != 1) { Data *nd = Clone(d, d->length + max(d->length, GetCount())); ptr = nd->GetPtr(); d->Release(); d = nd; } ptr[i] = chr; } template T *AString::Mid(int from, int count) const { Chk(); 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; if(from == 0 && count == l) { Retain(); return ptr; } else return Create(ptr + from, count); } template T *AString::Mid(int from) const { Chk(); return Mid(from, GetLength() - from); } template T *AString::Right(int count) const { Chk(); return Mid(GetLength() - count); } template T *AString::Left(int count) const { Chk(); return Mid(0, count); } template int AString::Find(int chr, int from) const { ASSERT(from >= 0 && from <= GetLength()); const T *e = End(); for(const T *s = ptr + from; s < e; s++) if(*s == chr) return s - ptr; return -1; } template int AString::ReverseFind(int chr, int from) const { ASSERT(from >= 0 && from <= GetLength()); if(from < GetLength()) for(const T *s = ptr + from; s >= ptr; s--) if(*s == chr) return s - ptr; return -1; } template int AString::ReverseFind(int chr) const { return GetCount() ? ReverseFind(chr, GetCount() - 1) : -1; } template int AString::Find(int len, const T *s, int from) const { ASSERT(from >= 0 && from <= GetLength()); const T *p = ptr + from; int l = GetLength() - len - from; if(l < 0) return -1; const T *e = p + l; len *= sizeof(T); while(p <= e) { if(memcmp(s, p, len) == 0) return p - ptr; p++; } return -1; } template bool AString::StartsWith(const T *s, int len) const { if(len > GetLength()) return false; return memcmp(s, ptr, len * sizeof(T)) == 0; } template bool AString::EndsWith(const T *s, int len) const { int l = GetLength(); if(len > l) return false; return memcmp(s, ptr + l - len, len * sizeof(T)) == 0; } template int AString::Find(const T *s, int from) const { return Find(strlen(s), s, from); } template bool AString::IsEqual(const T *p, int len) const { if(len != GetLength()) return false; if(len == 0 || p == ptr) return true; return memcmp(ptr, p, len * sizeof(T)) == 0; } template AString::AString(int chr, int count) { ptr = Create(count); Fill(ptr, ptr + count, (T)chr); } template void AStringBuffer::Init(int len) { begin = S::Create(len); Reads(); } template void AStringBuffer::Init(S& text, int alloc) { typename S::Data *d = S::GetData(text.ptr); if(AtomicRead(d->refcount) != 1 || d->alloc < alloc) { typename S::Data *nd = S::Clone(d, alloc); d->Release(); begin = nd->GetPtr(); } else begin = text.ptr; text.ptr = S::CreateNull(); Reads(); } template AStringBuffer::AStringBuffer() { begin = S::CreateNull(); Reads(); } template void AStringBuffer::Clear() { Free(); begin = S::CreateNull(); Reads(); } template void AStringBuffer::Realloc(int newalloc) { typename S::Data *d = S::GetData(begin); d->length = end - begin; typename S::Data *nd = S::Clone(d, newalloc); d->Release(); begin = nd->GetPtr(); Reads(); } template void AStringBuffer::Expand() { typename S::Data *d = S::GetData(begin); Realloc(max(8, 2 * (int)(intptr_t)(alloc - begin))); } template void AStringBuffer::Expand(int len) { typename S::Data *d = S::GetData(begin); Realloc(max(8, max((int)(intptr_t)(alloc - begin + len), 2 * (int)(intptr_t)(alloc - begin)))); } template void AStringBuffer::Reserve(int len) { if((len -= (int)(intptr_t)(alloc - begin)) > 0) Expand(len); } template T *AStringBuffer::SetLength(int len) { if(alloc - begin < len) Realloc(len); end = begin + len; return begin; } template T *AStringBuffer::Get() { int l = GetLength(); begin[l] = 0; S::GetData(begin)->length = l; T *p = begin; begin = S::CreateNull(); Reads(); return p; } template void AStringBuffer::Set(S& s) { Free(); Init(s, s.GetLength()); } template AStringBuffer::~AStringBuffer() { Free(); }