#include "RConfig.h"
#include <stdlib.h>
#include <ctype.h>
#include <list>
#include <algorithm>
#include "snprintf.h"
#include "Varargs.h"
#include "TString.h"
#include "TBuffer.h"
#include "TError.h"
#include "Bytes.h"
#include "TClass.h"
#include "TMD5.h"
#include "TObjArray.h"
#include "TObjString.h"
#include "TVirtualMutex.h"
#include "ThreadLocalStorage.h"
#if defined(R__WIN32)
#define strtoull _strtoui64
#endif
#ifdef R__GLOBALSTL
namespace std { using ::list; }
#endif
ClassImp(TString)
const UInt_t kHashShift = 5;
TString::TString()
{
Zero();
}
TString::TString(Ssiz_t ic)
{
Init(ic, 0);
}
TString::TString(const char *cs)
{
if (cs) {
Ssiz_t n = strlen(cs);
char *data = Init(n, n);
memcpy(data, cs, n);
} else
Init(0, 0);
}
TString::TString(const std::string &s)
{
Ssiz_t n = s.length();
char *data = Init(n, n);
memcpy(data, s.c_str(), n);
}
TString::TString(const char *cs, Ssiz_t n)
{
char *data = Init(n, n);
memcpy(data, cs, n);
}
void TString::InitChar(char c)
{
char *data = Init(1, 1);
data[0] = c;
}
TString::TString(char c)
{
InitChar(c);
}
TString::TString(char c, Ssiz_t n)
{
char *data = Init(n, n);
while (n--) data[n] = c;
}
TString::TString(const TString &s)
{
if (!s.IsLong())
fRep.fRaw = s.fRep.fRaw;
else {
Ssiz_t n = s.GetLongSize();
char *data = Init(n, n);
memcpy(data, s.GetLongPointer(), n);
}
}
TString::TString(const TSubString& substr)
{
Ssiz_t len = substr.IsNull() ? 0 : substr.Length();
char *data = Init(len, len);
memcpy(data, substr.Data(), len);
}
TString::TString(const char *a1, Ssiz_t n1, const char *a2, Ssiz_t n2)
{
if (!a1) n1=0;
if (!a2) n2=0;
Ssiz_t tot = n1+n2;
char *data = Init(tot, tot);
memcpy(data, a1, n1);
memcpy(data+n1, a2, n2);
}
TString::~TString()
{
UnLink();
}
char *TString::Init(Ssiz_t capacity, Ssiz_t nchar)
{
if (capacity > MaxSize()) {
Error("TString::Init", "capacity too large (%d, max = %d)", capacity, MaxSize());
capacity = MaxSize();
if (nchar > capacity)
nchar = capacity;
}
char *data;
if (capacity < kMinCap) {
SetShortSize(nchar);
data = GetShortPointer();
} else {
Ssiz_t cap = Recommend(capacity);
data = new char[cap+1];
SetLongCap(cap+1);
SetLongSize(nchar);
SetLongPointer(data);
}
data[nchar] = 0;
return data;
}
TString& TString::operator=(char c)
{
if (!c) {
UnLink();
Zero();
return *this;
}
return Replace(0, Length(), &c, 1);
}
TString& TString::operator=(const char *cs)
{
if (!cs || !*cs) {
UnLink();
Zero();
return *this;
}
return Replace(0, Length(), cs, strlen(cs));
}
TString& TString::operator=(const std::string &s)
{
if (s.length()==0) {
UnLink();
Zero();
return *this;
}
return Replace(0, Length(), s.c_str(), s.length());
}
TString& TString::operator=(const TString &rhs)
{
if (this != &rhs) {
UnLink();
if (!rhs.IsLong())
fRep.fRaw = rhs.fRep.fRaw;
else {
Ssiz_t n = rhs.GetLongSize();
char *data = Init(n, n);
memcpy(data, rhs.GetLongPointer(), n);
}
}
return *this;
}
TString& TString::operator=(const TSubString &substr)
{
Ssiz_t len = substr.IsNull() ? 0 : substr.Length();
if (!len) {
UnLink();
Zero();
return *this;
}
return Replace(0, Length(), substr.Data(), len);
}
TString& TString::Append(char c, Ssiz_t rep)
{
if (!rep) return *this;
Ssiz_t len = Length();
Ssiz_t tot = len + rep;
if (tot > MaxSize()) {
Error("TString::Append", "rep too large (%d, max = %d)", rep, MaxSize()-len);
tot = MaxSize();
rep = tot - len;
}
Ssiz_t capac = Capacity();
char *data, *p = GetPointer();
if (capac - tot >= 0) {
SetSize(tot);
data = p;
} else {
Ssiz_t cap = AdjustCapacity(capac, tot);
data = new char[cap+1];
memcpy(data, p, len);
UnLink();
SetLongCap(cap+1);
SetLongSize(tot);
SetLongPointer(data);
}
data[tot] = 0;
data += len;
while (rep--)
*data++ = c;
return *this;
}
Ssiz_t TString::Capacity(Ssiz_t nc)
{
if (nc > Length())
Clone(nc);
return Capacity();
}
int TString::CompareTo(const char *cs2, ECaseCompare cmp) const
{
if (!cs2) return 1;
const char *cs1 = Data();
Ssiz_t len = Length();
Ssiz_t i = 0;
if (cmp == kExact) {
for (; cs2[i]; ++i) {
if (i == len) return -1;
if (cs1[i] != cs2[i]) return ((cs1[i] > cs2[i]) ? 1 : -1);
}
} else {
for (; cs2[i]; ++i) {
if (i == len) return -1;
char c1 = tolower((unsigned char)cs1[i]);
char c2 = tolower((unsigned char)cs2[i]);
if (c1 != c2) return ((c1 > c2) ? 1 : -1);
}
}
return (i < len) ? 1 : 0;
}
int TString::CompareTo(const TString &str, ECaseCompare cmp) const
{
const char *s1 = Data();
const char *s2 = str.Data();
Ssiz_t len = Length();
Ssiz_t slen, sleno = str.Length();
slen = sleno;
if (len < slen) slen = len;
if (cmp == kExact) {
int result = memcmp(s1, s2, slen);
if (result != 0) return result;
} else {
Ssiz_t i = 0;
for (; i < slen; ++i) {
char c1 = tolower((unsigned char)s1[i]);
char c2 = tolower((unsigned char)s2[i]);
if (c1 != c2) return ((c1 > c2) ? 1 : -1);
}
}
slen = sleno;
if (len == slen) return 0;
return (len > slen) ? 1 : -1;
}
Int_t TString::CountChar(Int_t c) const
{
Int_t count = 0;
Int_t len = Length();
const char *data = Data();
for (Int_t n = 0; n < len; n++)
if (data[n] == c) count++;
return count;
}
TString TString::Copy() const
{
TString temp(*this);
return temp;
}
Ssiz_t TString::First(char c) const
{
const char *f = strchr(Data(), c);
return f ? f - Data() : kNPOS;
}
Ssiz_t TString::First(const char *cs) const
{
const char *f = strpbrk(Data(), cs);
return f ? f - Data() : kNPOS;
}
#ifndef R__BYTESWAP
inline static UInt_t SwapInt(UInt_t x)
{
return (((x & 0x000000ffU) << 24) | ((x & 0x0000ff00U) << 8) |
((x & 0x00ff0000U) >> 8) | ((x & 0xff000000U) >> 24));
}
#endif
inline static void Mash(UInt_t& hash, UInt_t chars)
{
hash = (chars ^
((hash << kHashShift) |
(hash >> (kBitsPerByte*sizeof(UInt_t) - kHashShift))));
}
UInt_t Hash(const char *str)
{
UInt_t len = str ? strlen(str) : 0;
UInt_t hv = len;
UInt_t i = hv*sizeof(char)/sizeof(UInt_t);
if (((ULong_t)str)%sizeof(UInt_t) == 0) {
const UInt_t *p = (const UInt_t*)str;
while (i--) {
#ifndef R__BYTESWAP
UInt_t h = *p++;
Mash(hv, SwapInt(h));
#else
Mash(hv, *p++);
#endif
}
if ((i = len*sizeof(char)%sizeof(UInt_t)) != 0) {
UInt_t h = 0;
const char* c = (const char*)p;
while (i--)
h = ((h << kBitsPerByte*sizeof(char)) | *c++);
Mash(hv, h);
}
} else {
UInt_t h;
const unsigned char *p = (const unsigned char*)str;
while (i--) {
memcpy(&h, p, sizeof(UInt_t));
#ifndef R__BYTESWAP
Mash(hv, SwapInt(h));
#else
Mash(hv, h);
#endif
p += sizeof(UInt_t);
}
if ((i = len*sizeof(char)%sizeof(UInt_t)) != 0) {
h = 0;
const char* c = (const char*)p;
while (i--)
h = ((h << kBitsPerByte*sizeof(char)) | *c++);
Mash(hv, h);
}
}
return hv;
}
UInt_t TString::HashCase() const
{
UInt_t hv = (UInt_t)Length();
UInt_t i = hv*sizeof(char)/sizeof(UInt_t);
const UInt_t *p = (const UInt_t*)Data();
{
while (i--) {
#ifndef R__BYTESWAP
UInt_t h = *p++;
Mash(hv, SwapInt(h));
#else
Mash(hv, *p++);
#endif
}
}
if ((i = Length()*sizeof(char)%sizeof(UInt_t)) != 0) {
UInt_t h = 0;
const char* c = (const char*)p;
while (i--)
h = ((h << kBitsPerByte*sizeof(char)) | *c++);
Mash(hv, h);
}
return hv;
}
UInt_t TString::HashFoldCase() const
{
UInt_t hv = (UInt_t)Length();
UInt_t i = hv;
const unsigned char *p = (const unsigned char*)Data();
while (i--) {
Mash(hv, toupper(*p));
++p;
}
return hv;
}
UInt_t TString::Hash(ECaseCompare cmp) const
{
return (cmp == kExact) ? HashCase() : HashFoldCase();
}
namespace {
#if defined(_MSC_VER)
typedef unsigned char uint8_t;
typedef unsigned long uint32_t;
typedef unsigned __int64 uint64_t;
#else // defined(_MSC_VER)
#include <stdint.h>
#endif // !defined(_MSC_VER)
#if defined(_MSC_VER)
#define FORCE_INLINE __forceinline
#include <stdlib.h>
#define ROTL64(x,y) _rotl64(x,y)
#define BIG_CONSTANT(x) (x)
#else // defined(_MSC_VER)
inline uint64_t rotl64 ( uint64_t x, int8_t r )
{
return (x << r) | (x >> (64 - r));
}
#if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) <= 40101
#define FORCE_INLINE inline
#else
#define FORCE_INLINE __attribute__((always_inline)) inline
#endif
#define ROTL64(x,y) rotl64(x,y)
#define BIG_CONSTANT(x) (x##LLU)
#endif // !defined(_MSC_VER)
FORCE_INLINE uint64_t getblock(const uint64_t* p, int i)
{
return p[i];
}
FORCE_INLINE uint64_t fmix(uint64_t k)
{
k ^= k >> 33;
k *= BIG_CONSTANT(0xff51afd7ed558ccd);
k ^= k >> 33;
k *= BIG_CONSTANT(0xc4ceb9fe1a85ec53);
k ^= k >> 33;
return k;
}
static void MurmurHash3_x64_128(const void * key, const int len,
const uint32_t seed, uint64_t out[2] )
{
const uint8_t * data = (const uint8_t*)key;
const int nblocks = len / 16;
uint64_t h1 = seed;
uint64_t h2 = seed;
uint64_t c1 = BIG_CONSTANT(0x87c37b91114253d5);
uint64_t c2 = BIG_CONSTANT(0x4cf5ad432745937f);
const uint64_t * blocks = (const uint64_t *)(data);
for(int i = 0; i < nblocks; i++)
{
uint64_t k1 = getblock(blocks,i*2+0);
uint64_t k2 = getblock(blocks,i*2+1);
k1 *= c1; k1 = ROTL64(k1,31); k1 *= c2; h1 ^= k1;
h1 = ROTL64(h1,27); h1 += h2; h1 = h1*5+0x52dce729;
k2 *= c2; k2 = ROTL64(k2,33); k2 *= c1; h2 ^= k2;
h2 = ROTL64(h2,31); h2 += h1; h2 = h2*5+0x38495ab5;
}
const uint8_t * tail = (const uint8_t*)(data + nblocks*16);
uint64_t k1 = 0;
uint64_t k2 = 0;
switch(len & 15) {
case 15: k2 ^= uint64_t(tail[14]) << 48;
case 14: k2 ^= uint64_t(tail[13]) << 40;
case 13: k2 ^= uint64_t(tail[12]) << 32;
case 12: k2 ^= uint64_t(tail[11]) << 24;
case 11: k2 ^= uint64_t(tail[10]) << 16;
case 10: k2 ^= uint64_t(tail[ 9]) << 8;
case 9: k2 ^= uint64_t(tail[ 8]) << 0;
k2 *= c2; k2 = ROTL64(k2,33); k2 *= c1; h2 ^= k2;
case 8: k1 ^= uint64_t(tail[ 7]) << 56;
case 7: k1 ^= uint64_t(tail[ 6]) << 48;
case 6: k1 ^= uint64_t(tail[ 5]) << 40;
case 5: k1 ^= uint64_t(tail[ 4]) << 32;
case 4: k1 ^= uint64_t(tail[ 3]) << 24;
case 3: k1 ^= uint64_t(tail[ 2]) << 16;
case 2: k1 ^= uint64_t(tail[ 1]) << 8;
case 1: k1 ^= uint64_t(tail[ 0]) << 0;
k1 *= c1; k1 = ROTL64(k1,31); k1 *= c2; h1 ^= k1;
};
h1 ^= len; h2 ^= len;
h1 += h2;
h2 += h1;
h1 = fmix(h1);
h2 = fmix(h2);
h1 += h2;
h2 += h1;
((uint64_t*)out)[0] = h1;
((uint64_t*)out)[1] = h2;
}
}
UInt_t TString::Hash(const void *txt, Int_t ntxt)
{
if (ntxt != sizeof(void*)) {
uint64_t buf[2] = {0};
MurmurHash3_x64_128(txt, ntxt, 0x6384BA69, buf);
return (UInt_t) buf[0];
} else {
UInt_t ret = (UInt_t)0x6384BA69;
if (((size_t)txt) % sizeof(void*)) {
UInt_t* itxt = (UInt_t*)txt;
ret ^= itxt[0];
if (sizeof(void*) > sizeof(UInt_t)) {
ret ^= itxt[1];
}
} else {
const unsigned char* ctxt = (const unsigned char*) txt;
for (unsigned int i = 0; i < 4; ++i) {
ret ^= ctxt[i] << (i * 8);
}
if (sizeof(void*) > sizeof(UInt_t)) {
ctxt += 4;
for (unsigned int i = 0; i < 4; ++i) {
ret ^= ctxt[i] << (i * 8);
}
}
}
return ret;
}
}
static int MemIsEqual(const char *p, const char *q, Ssiz_t n)
{
while (n--)
{
if (tolower((unsigned char)*p) != tolower((unsigned char)*q))
return kFALSE;
p++; q++;
}
return kTRUE;
}
Ssiz_t TString::Index(const char *pattern, Ssiz_t plen, Ssiz_t startIndex,
ECaseCompare cmp) const
{
Ssiz_t slen = Length();
if (slen < startIndex + plen) return kNPOS;
if (plen == 0) return startIndex;
slen -= startIndex + plen;
const char *sp = Data() + startIndex;
if (cmp == kExact) {
char first = *pattern;
for (Ssiz_t i = 0; i <= slen; ++i)
if (sp[i] == first && memcmp(sp+i+1, pattern+1, plen-1) == 0)
return i + startIndex;
} else {
int first = tolower((unsigned char) *pattern);
for (Ssiz_t i = 0; i <= slen; ++i)
if (tolower((unsigned char) sp[i]) == first &&
MemIsEqual(sp+i+1, pattern+1, plen-1))
return i + startIndex;
}
return kNPOS;
}
Ssiz_t TString::Last(char c) const
{
const char *f = strrchr(Data(), (unsigned char) c);
return f ? f - Data() : kNPOS;
}
TString TString::MD5() const
{
TMD5 md5;
md5.Update((const UChar_t*)Data(), Length());
UChar_t digest[16];
md5.Final(digest);
return md5.AsString();
}
Bool_t TString::MaybeRegexp() const
{
const char *specials = "^$.[]*+?";
if (First(specials) == kNPOS)
return kFALSE;
return kTRUE;
}
Bool_t TString::MaybeWildcard() const
{
const char *specials = "[]*?";
if (First(specials) == kNPOS)
return kFALSE;
return kTRUE;
}
TString& TString::Prepend(char c, Ssiz_t rep)
{
if (!rep) return *this;
Ssiz_t len = Length();
Ssiz_t tot = len + rep;
if (tot > MaxSize()) {
Error("TString::Prepend", "rep too large (%d, max = %d)", rep, MaxSize()-len);
tot = MaxSize();
rep = tot - len;
}
Ssiz_t capac = Capacity();
char *data, *p = GetPointer();
if (capac - tot >= 0) {
memmove(p + rep, p, len);
SetSize(tot);
data = p;
} else {
Ssiz_t cap = AdjustCapacity(capac, tot);
data = new char[cap+1];
memcpy(data+rep, p, len);
UnLink();
SetLongCap(cap+1);
SetLongSize(tot);
SetLongPointer(data);
}
data[tot] = 0;
while (rep--)
*data++ = c;
return *this;
}
TString &TString::Replace(Ssiz_t pos, Ssiz_t n1, const char *cs, Ssiz_t n2)
{
Ssiz_t len = Length();
if (pos <= kNPOS || pos > len) {
Error("TString::Replace",
"first argument out of bounds: pos = %d, Length = %d", pos, len);
return *this;
}
n1 = TMath::Min(n1, len - pos);
if (!cs) n2 = 0;
Ssiz_t tot = len - n1 + n2;
Ssiz_t rem = len - n1 - pos;
Ssiz_t capac = Capacity();
char *p = GetPointer();
if (capac - len + n1 >= n2) {
if (n1 != n2) {
if (rem) {
if (n1 > n2) {
if (n2) memmove(p + pos, cs, n2);
memmove(p + pos + n2, p + pos + n1, rem);
goto finish;
}
if (p + pos < cs && cs < p + len) {
if (p + pos + n1 <= cs)
cs += n2 - n1;
else {
memmove(p + pos, cs, n1);
pos += n1;
cs += n2;
n2 -= n1;
n1 = 0;
}
}
memmove(p + pos + n2, p + pos + n1, rem);
}
}
if (n2) memmove(p + pos, cs, n2);
finish:
SetSize(tot);
p[tot] = 0;
} else {
Ssiz_t cap = AdjustCapacity(capac, tot);
char *data = new char[cap+1];
if (pos) memcpy(data, p, pos);
if (n2 ) memcpy(data + pos, cs, n2);
if (rem) memcpy(data + pos + n2, p + pos + n1, rem);
UnLink();
SetLongCap(cap+1);
SetLongSize(tot);
SetLongPointer(data);
data[tot] = 0;
}
return *this;
}
TString& TString::ReplaceAll(const char *s1, Ssiz_t ls1, const char *s2,
Ssiz_t ls2)
{
if (s1 && ls1 > 0) {
Ssiz_t index = 0;
while ((index = Index(s1, ls1, index, kExact)) != kNPOS) {
Replace(index, ls1, s2, ls2);
index += ls2;
}
}
return *this;
}
TString &TString::Remove(EStripType st, char c)
{
Ssiz_t start = 0;
Ssiz_t end = Length();
const char *direct = Data();
Ssiz_t send = end;
if (st & kLeading)
while (start < end && direct[start] == c)
++start;
if (st & kTrailing)
while (start < end && direct[end-1] == c)
--end;
if (end == start) {
UnLink();
Zero();
return *this;
}
if (start)
Remove(0, start);
if (send != end)
Remove(send - start - (send - end), send - end);
return *this;
}
void TString::Resize(Ssiz_t n)
{
if (n < Length())
Remove(n);
else
Append(' ', n-Length());
}
TSubString TString::Strip(EStripType st, char c) const
{
Ssiz_t start = 0;
Ssiz_t end = Length();
const char *direct = Data();
if (st & kLeading)
while (start < end && direct[start] == c)
++start;
if (st & kTrailing)
while (start < end && direct[end-1] == c)
--end;
if (end == start) start = end = kNPOS;
return TSubString(*this, start, end-start);
}
void TString::ToLower()
{
Ssiz_t n = Length();
char *p = GetPointer();
while (n--) {
*p = tolower((unsigned char)*p);
p++;
}
}
void TString::ToUpper()
{
Ssiz_t n = Length();
char *p = GetPointer();
while (n--) {
*p = toupper((unsigned char)*p);
p++;
}
}
void TString::AssertElement(Ssiz_t i) const
{
if (i == kNPOS || i > Length())
Error("TString::AssertElement",
"out of bounds: i = %d, Length = %d", i, Length());
}
Ssiz_t TString::AdjustCapacity(Ssiz_t oldCap, Ssiz_t newCap)
{
Ssiz_t ms = MaxSize();
if (newCap > ms - 1) {
Error("TString::AdjustCapacity", "capacity too large (%d, max = %d)",
newCap, ms);
}
Ssiz_t cap = oldCap < ms / 2 - kAlignment ?
Recommend(TMath::Max(newCap, 2 * oldCap)) : ms - 1;
return cap;
}
void TString::Clear()
{
Clobber(Capacity());
}
void TString::Clobber(Ssiz_t nc)
{
if (nc > MaxSize()) {
Error("TString::Clobber", "capacity too large (%d, max = %d)", nc, MaxSize());
nc = MaxSize();
}
if (nc < kMinCap) {
UnLink();
Zero();
} else {
char *data = GetLongPointer();
Ssiz_t cap = Recommend(nc);
if (cap != Capacity()) {
data = new char[cap+1];
UnLink();
SetLongCap(cap+1);
SetLongPointer(data);
}
SetLongSize(0);
data[0] = 0;
}
}
void TString::Clone(Ssiz_t tot)
{
Ssiz_t len = Length();
if (len >= tot) return;
if (tot > MaxSize()) {
Error("TString::Clone", "tot too large (%d, max = %d)", tot, MaxSize());
tot = MaxSize();
}
Ssiz_t capac = Capacity();
char *data, *p = GetPointer();
if (capac - tot < 0) {
Ssiz_t cap = Recommend(tot);
data = new char[cap+1];
memcpy(data, p, len);
UnLink();
SetLongCap(cap+1);
SetLongSize(len);
SetLongPointer(data);
data[len] = 0;
}
}
void TString::FillBuffer(char *&buffer) const
{
UChar_t nwh;
Int_t nchars = Length();
if (nchars > 254) {
nwh = 255;
tobuf(buffer, nwh);
tobuf(buffer, nchars);
} else {
nwh = UChar_t(nchars);
tobuf(buffer, nwh);
}
const char *data = GetPointer();
for (int i = 0; i < nchars; i++) buffer[i] = data[i];
buffer += nchars;
}
void TString::ReadBuffer(char *&buffer)
{
UnLink();
Zero();
UChar_t nwh;
Int_t nchars;
frombuf(buffer, &nwh);
if (nwh == 255)
frombuf(buffer, &nchars);
else
nchars = nwh;
if (nchars < 0) {
Error("TString::ReadBuffer", "found case with nwh=%d and nchars=%d", nwh, nchars);
return;
}
char *data = Init(nchars, nchars);
for (int i = 0; i < nchars; i++) frombuf(buffer, &data[i]);
}
TString *TString::ReadString(TBuffer &b, const TClass *clReq)
{
R__ASSERT(b.IsReading());
b.InitMap();
UInt_t startpos = UInt_t(b.Length());
UInt_t tag;
TClass *clRef = b.ReadClass(clReq, &tag);
TString *a;
if (!clRef) {
a = 0;
} else {
a = (TString *) clRef->New();
if (!a) {
::Error("TString::ReadObject", "could not create object of class %s",
clRef->GetName());
return a;
}
a->Streamer(b);
b.CheckByteCount(startpos, tag, clRef);
}
return a;
}
Int_t TString::Sizeof() const
{
if (Length() > 254)
return Length()+sizeof(UChar_t)+sizeof(Int_t);
else
return Length()+sizeof(UChar_t);
}
void TString::Streamer(TBuffer &b)
{
if (b.IsReading()) {
b.ReadTString(*this);
} else {
b.WriteTString(*this);
}
}
void TString::WriteString(TBuffer &b, const TString *a)
{
R__ASSERT(b.IsWriting());
b.InitMap();
if (!a) {
b << (UInt_t) 0;
} else {
UInt_t cntpos = UInt_t(b.Length());
b.SetBufferOffset(Int_t(cntpos+sizeof(UInt_t)));
TClass *cl = a->IsA();
b.WriteClass(cl);
((TString *)a)->Streamer(b);
b.SetByteCount(cntpos);
}
}
#if defined(R__TEMPLATE_OVERLOAD_BUG)
template <>
#endif
TBuffer &operator>>(TBuffer &buf, TString *&s)
{
s = (TString *) TString::ReadString(buf, TString::Class());
return buf;
}
TBuffer &operator<<(TBuffer &buf, const TString *s)
{
TString::WriteString(buf, s);
return buf;
}
Bool_t operator==(const TString& s1, const char *s2)
{
if (!s2) return kFALSE;
const char *data = s1.Data();
Ssiz_t len = s1.Length();
Ssiz_t i;
for (i = 0; s2[i]; ++i)
if (data[i] != s2[i] || i == len) return kFALSE;
return (i == len);
}
TString ToLower(const TString &str)
{
Ssiz_t n = str.Length();
TString temp((char)0, n);
const char *uc = str.Data();
char *lc = (char*)temp.Data();
while (n--) { *lc++ = tolower((unsigned char)*uc); uc++; }
return temp;
}
TString ToUpper(const TString &str)
{
Ssiz_t n = str.Length();
TString temp((char)0, n);
const char* uc = str.Data();
char* lc = (char*)temp.Data();
while (n--) { *lc++ = toupper((unsigned char)*uc); uc++; }
return temp;
}
TString operator+(const TString &s, const char *cs)
{
return TString(s.Data(), s.Length(), cs, cs ? strlen(cs) : 0);
}
TString operator+(const char *cs, const TString &s)
{
return TString(cs, cs ? strlen(cs) : 0, s.Data(), s.Length());
}
TString operator+(const TString &s1, const TString &s2)
{
return TString(s1.Data(), s1.Length(), s2.Data(), s2.Length());
}
TString operator+(const TString &s, char c)
{
return TString(s.Data(), s.Length(), &c, 1);
}
TString operator+(const TString &s, Long_t i)
{
char si[32];
snprintf(si, sizeof(si), "%ld", i);
return TString(s.Data(), s.Length(), si, strlen(si));
}
TString operator+(const TString &s, ULong_t i)
{
char si[32];
snprintf(si, sizeof(si), "%lu", i);
return TString(s.Data(), s.Length(), si, strlen(si));
}
TString operator+(const TString &s, Long64_t i)
{
char si[32];
snprintf(si, sizeof(si), "%lld", i);
return TString(s.Data(), s.Length(), si, strlen(si));
}
TString operator+(const TString &s, ULong64_t i)
{
char si[32];
snprintf(si, sizeof(si), "%llu", i);
return TString(s.Data(), s.Length(), si, strlen(si));
}
TString operator+(char c, const TString &s)
{
return TString(&c, 1, s.Data(), s.Length());
}
TString operator+(Long_t i, const TString &s)
{
char si[32];
snprintf(si, sizeof(si), "%ld", i);
return TString(si, strlen(si), s.Data(), s.Length());
}
TString operator+(ULong_t i, const TString &s)
{
char si[32];
snprintf(si, sizeof(si), "%lu", i);
return TString(si, strlen(si), s.Data(), s.Length());
}
TString operator+(Long64_t i, const TString &s)
{
char si[32];
snprintf(si, sizeof(si), "%lld", i);
return TString(si, strlen(si), s.Data(), s.Length());
}
TString operator+(ULong64_t i, const TString &s)
{
char si[32];
snprintf(si, sizeof(si), "%llu", i);
return TString(si, strlen(si), s.Data(), s.Length());
}
Ssiz_t TString::GetInitialCapacity()
{
::Obsolete("TString::GetInitialCapacity", "v5-30-00", "v5-32-00");
return 15;
}
Ssiz_t TString::GetResizeIncrement()
{
::Obsolete("TString::GetResizeIncrement", "v5-30-00", "v5-32-00");
return 16;
}
Ssiz_t TString::GetMaxWaste()
{
::Obsolete("TString::GetMaxWaste", "v5-30-00", "v5-32-00");
return 15;
}
Ssiz_t TString::InitialCapacity(Ssiz_t)
{
::Obsolete("TString::InitialCapacity", "v5-30-00", "v5-32-00");
return 15;
}
Ssiz_t TString::ResizeIncrement(Ssiz_t)
{
::Obsolete("TString::ResizeIncrement", "v5-30-00", "v5-32-00");
return 16;
}
Ssiz_t TString::MaxWaste(Ssiz_t)
{
::Obsolete("TString::MaxWaste", "v5-30-00", "v5-32-00");
return 15;
}
TSubString::TSubString(const TString &str, Ssiz_t start, Ssiz_t nextent)
: fStr((TString&)str), fBegin(start), fExtent(nextent)
{
}
TSubString TString::operator()(Ssiz_t start, Ssiz_t len) const
{
if (start < Length() && len > 0) {
if (start+len > Length())
len = Length() - start;
} else {
start = kNPOS;
len = 0;
}
return TSubString(*this, start, len);
}
TSubString TString::SubString(const char *pattern, Ssiz_t startIndex,
ECaseCompare cmp) const
{
Ssiz_t len = pattern ? strlen(pattern) : 0;
Ssiz_t i = Index(pattern, len, startIndex, cmp);
return TSubString(*this, i, i == kNPOS ? 0 : len);
}
char& TSubString::operator[](Ssiz_t i)
{
AssertElement(i);
return fStr(fBegin+i);
}
char& TSubString::operator()(Ssiz_t i)
{
return fStr(fBegin+i);
}
TSubString& TSubString::operator=(const TString &str)
{
if (!IsNull())
fStr.Replace(fBegin, fExtent, str.Data(), str.Length());
return *this;
}
TSubString& TSubString::operator=(const char *cs)
{
if (!IsNull())
fStr.Replace(fBegin, fExtent, cs, cs ? strlen(cs) : 0);
return *this;
}
Bool_t operator==(const TSubString& ss, const char *cs)
{
if (ss.IsNull()) return *cs =='\0';
const char* data = ss.fStr.Data() + ss.fBegin;
Ssiz_t i;
for (i = 0; cs[i]; ++i)
if (cs[i] != data[i] || i == ss.fExtent) return kFALSE;
return (i == ss.fExtent);
}
Bool_t operator==(const TSubString& ss, const TString &s)
{
if (ss.IsNull()) return s.IsNull();
if (ss.fExtent != s.Length()) return kFALSE;
return !memcmp(ss.fStr.Data() + ss.fBegin, s.Data(), ss.fExtent);
}
Bool_t operator==(const TSubString &s1, const TSubString &s2)
{
if (s1.IsNull()) return s2.IsNull();
if (s1.fExtent != s2.fExtent) return kFALSE;
return !memcmp(s1.fStr.Data()+s1.fBegin, s2.fStr.Data()+s2.fBegin,
s1.fExtent);
}
void TSubString::ToLower()
{
if (!IsNull()) {
char *p = fStr.GetPointer() + fBegin;
Ssiz_t n = fExtent;
while (n--) { *p = tolower((unsigned char)*p); p++;}
}
}
void TSubString::ToUpper()
{
if (!IsNull()) {
char *p = fStr.GetPointer() + fBegin;
Ssiz_t n = fExtent;
while (n--) { *p = toupper((unsigned char)*p); p++;}
}
}
void TSubString::SubStringError(Ssiz_t sr, Ssiz_t start, Ssiz_t n) const
{
Error("TSubString::SubStringError",
"out of bounds: start = %d, n = %d, sr = %d", start, n, sr);
}
void TSubString::AssertElement(Ssiz_t i) const
{
if (i == kNPOS || i >= Length())
Error("TSubString::AssertElement",
"out of bounds: i = %d, Length = %d", i, Length());
}
Bool_t TString::IsAscii() const
{
const char *cp = Data();
for (Ssiz_t i = 0; i < Length(); ++i)
if (cp[i] & ~0x7F)
return kFALSE;
return kTRUE;
}
Bool_t TString::IsAlpha() const
{
const char *cp = Data();
Ssiz_t len = Length();
if (len == 0) return kFALSE;
for (Ssiz_t i = 0; i < len; ++i)
if (!isalpha(cp[i]))
return kFALSE;
return kTRUE;
}
Bool_t TString::IsAlnum() const
{
const char *cp = Data();
Ssiz_t len = Length();
if (len == 0) return kFALSE;
for (Ssiz_t i = 0; i < len; ++i)
if (!isalnum(cp[i]))
return kFALSE;
return kTRUE;
}
Bool_t TString::IsDigit() const
{
const char *cp = Data();
Ssiz_t len = Length();
if (len == 0) return kFALSE;
Int_t b = 0, d = 0;
for (Ssiz_t i = 0; i < len; ++i) {
if (cp[i] != ' ' && !isdigit(cp[i])) return kFALSE;
if (cp[i] == ' ') b++;
if (isdigit(cp[i])) d++;
}
if (b && !d)
return kFALSE;
return kTRUE;
}
Bool_t TString::IsFloat() const
{
if (IsDigit()) return kTRUE;
TString tmp = *this;
tmp.ToLower();
Ssiz_t pos = tmp.First('.');
if (pos != kNPOS) tmp.Replace(pos, 1, " ", 1);
pos = tmp.First(',');
if (pos != kNPOS) tmp.Replace(pos, 1, " ", 1);
pos = tmp.Index("e-");
if (pos >= 1) tmp.Replace(pos, 2, " ", 1);
pos = tmp.Index("e+");
if (pos >= 1) tmp.Replace(pos, 2, " ", 1);
pos = tmp.Index("e");
if (pos >= 1) tmp.Replace(pos, 1, " ", 1);
pos = tmp.First('-');
if (pos == 0) tmp.Replace(pos, 1, " ", 1);
pos = tmp.First('+');
if (pos == 0) tmp.Replace(pos, 1, " ", 1);
return tmp.IsDigit();
}
Bool_t TString::IsHex() const
{
const char *cp = Data();
Ssiz_t len = Length();
if (len == 0) return kFALSE;
for (Ssiz_t i = 0; i < len; ++i)
if (!isxdigit(cp[i]))
return kFALSE;
return kTRUE;
}
Bool_t TString::IsBin() const
{
const char *cp = Data();
Ssiz_t len = Length();
if (len == 0) return kFALSE;
for (Ssiz_t i = 0; i < len; ++i)
if (cp[i] != '0' && cp[i] != '1')
return kFALSE;
return kTRUE;
}
Bool_t TString::IsOct() const
{
const char *cp = Data();
Ssiz_t len = Length();
if (len == 0) return kFALSE;
for (Ssiz_t i = 0; i < len; ++i)
if (!isdigit(cp[i]) || cp[i]=='8' || cp[i]=='9')
return kFALSE;
return kTRUE;
}
Bool_t TString::IsDec() const
{
const char *cp = Data();
Ssiz_t len = Length();
if (len == 0) return kFALSE;
for (Ssiz_t i = 0; i < len; ++i)
if (!isdigit(cp[i]))
return kFALSE;
return kTRUE;
}
Bool_t TString::IsInBaseN(Int_t base) const
{
if (base < 2 || base > 36) {
Error("TString::IsInBaseN", "base %d is not supported. Supported bases are {2,3,...,36}.", base);
return kFALSE;
}
if (Length() == 0) {
Error("TString::IsInBaseN", "input string is empty.") ;
return kFALSE;
}
TString str = TString(Data()) ;
str.ToUpper() ;
TString str_ref0 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" ;
TString str_ref = str_ref0 ;
str_ref.Remove(base) ;
Bool_t isInBase = kTRUE ;
for (Int_t k = 0; k < str.Length(); k++) {
if (! str_ref.Contains(str[k])) {
isInBase = kFALSE ;
break ;
}
}
return (isInBase);
}
Int_t TString::Atoi() const
{
Int_t end = Index(" ");
if (end == -1) return atoi(Data());
Int_t start = 0;
TString tmp;
while (end > -1) {
tmp += (*this)(start, end-start);
start = end+1; end = Index(" ", start);
}
end = Length();
tmp += (*this)(start, end-start);
return atoi(tmp.Data());
}
Long64_t TString::Atoll() const
{
Int_t end = Index(" ");
#ifndef R__WIN32
if (end == -1) return atoll(Data());
#else
if (end == -1) return _atoi64(Data());
#endif
Int_t start = 0;
TString tmp;
while (end > -1) {
tmp += (*this)(start, end-start);
start = end+1; end = Index(" ", start);
}
end = Length();
tmp += (*this)(start, end-start);
#ifndef R__WIN32
return atoll(tmp.Data());
#else
return _atoi64(tmp.Data());
#endif
}
Double_t TString::Atof() const
{
Int_t comma = Index(",");
Int_t end = Index(" ");
if (comma == -1 && end == -1) return atof(Data());
TString tmp = *this;
if (comma > -1) {
tmp.Replace(comma, 1, ".");
}
if (end == -1) return atof(tmp.Data());
Int_t start = 0;
TString tmp2;
while (end > -1) {
tmp2 += tmp(start, end-start);
start = end+1; end = tmp.Index(" ", start);
}
end = tmp.Length();
tmp2 += tmp(start, end-start);
return atof(tmp2.Data());
}
TString TString::Itoa(Int_t value, Int_t base)
{
std::string buf;
if (base < 2 || base > 36) {
Error("TString::Itoa", "base %d is not supported. Supported bases are {2,3,...,36}.",base) ;
return (TString("!"));
}
buf.reserve(35);
Int_t quotient = value;
do {
buf += "0123456789abcdefghijklmnopqrstuvwxyz"[ TMath::Abs(quotient % base) ];
quotient /= base;
} while (quotient);
if (value < 0) buf += '-';
std::reverse(buf.begin(), buf.end());
return (TString(buf.data()));
}
TString TString::UItoa(UInt_t value, Int_t base)
{
std::string buf;
if (base < 2 || base > 36) {
Error("TString::UItoa", "base %d is not supported. Supported bases are {2,3,...,36}.",base);
return (TString("!"));
}
buf.reserve(35);
UInt_t quotient = value;
do {
buf += "0123456789abcdefghijklmnopqrstuvwxyz"[ quotient % base ];
quotient /= base;
} while (quotient);
std::reverse(buf.begin(), buf.end());
return (TString(buf.data()));
}
TString TString::LLtoa(Long64_t value, Int_t base)
{
std::string buf;
if (base < 2 || base > 36) {
Error("TString::LLtoa", "base %d is not supported. Supported bases are {2,3,...,36}.",base);
return (TString("!"));
}
buf.reserve(35);
Long64_t quotient = value;
do {
buf += "0123456789abcdefghijklmnopqrstuvwxyz"[ TMath::Abs(quotient % base) ];
quotient /= base;
} while (quotient);
if (value < 0) buf += '-';
std::reverse(buf.begin(), buf.end());
return (TString(buf.data()));
}
TString TString::ULLtoa(ULong64_t value, Int_t base)
{
std::string buf;
if (base < 2 || base > 36) {
Error("TString::ULLtoa", "base %d is not supported. Supported bases are {2,3,...,36}.",base);
return (TString("!"));
}
buf.reserve(35);
ULong64_t quotient = value;
do {
buf += "0123456789abcdefghijklmnopqrstuvwxyz"[ quotient % base ];
quotient /= base;
} while (quotient);
std::reverse(buf.begin(), buf.end());
return (TString(buf.data()));
}
TString TString::BaseConvert(const TString& s_in, Int_t base_in, Int_t base_out)
{
TString s_out = "!" ;
if (base_in < 2 || base_in > 36 || base_out < 2 || base_out > 36) {
Error("TString::BaseConvert", "only bases 2-36 are supported (base_in=%d, base_out=%d).", base_in, base_out);
return (s_out);
}
TString s_in_ = s_in;
Bool_t isSigned = kFALSE;
if (s_in_[0] == '-') {
isSigned = kTRUE;
s_in_.Remove(0, 1);
}
if (!isSigned && s_in_[0] == '+') s_in_.Remove(0, 1);
if (base_in == 16 && s_in_.BeginsWith("0x")) s_in_.Remove(0, 2);
s_in_ = TString(s_in_.Strip(TString::kLeading, '0'));
if (!s_in_.Length()) s_in_ += '0';
if (!s_in_.IsInBaseN(base_in)) {
Error("TString::BaseConvert", "s_in=\"%s\" is not in base %d", s_in.Data(), base_in);
return (s_out);
}
TString s_max = TString::ULLtoa(18446744073709551615ULL, base_in);
if (s_in_.Length() > s_max.Length()) {
Error("TString::BaseConvert", "s_in=\"%s\" > %s = 2^64-1 in base %d.", s_in.Data(), s_max.Data(), base_in);
return (s_out);
} else if (s_in_.Length() == s_max.Length()) {
s_in_.ToLower();
if (s_in_ > s_max) {
Error("TString::BaseConvert", "s_in=\"%s\" > %s = 2^64-1 in base %d.", s_in.Data(), s_max.Data(), base_in);
return (s_out);
}
}
ULong64_t i = ULong64_t(strtoull(s_in.Data(), 0, base_in));
s_out = TString::ULLtoa(i, base_out);
if (isSigned) s_out.Prepend("-");
return (s_out);
}
Bool_t TString::EndsWith(const char *s, ECaseCompare cmp) const
{
if (!s) return kTRUE;
Ssiz_t l = strlen(s);
if (l > Length()) return kFALSE;
const char *s2 = Data() + Length() - l;
if (cmp == kExact)
return strcmp(s, s2) == 0;
return strcasecmp(s, s2) == 0;
}
TObjArray *TString::Tokenize(const TString &delim) const
{
std::list<Int_t> splitIndex;
Int_t i, start, nrDiff = 0;
for (i = 0; i < delim.Length(); i++) {
start = 0;
while (start < Length()) {
Int_t pos = Index(delim(i), start);
if (pos == kNPOS) break;
splitIndex.push_back(pos);
start = pos + 1;
}
if (start > 0) nrDiff++;
}
splitIndex.push_back(Length());
if (nrDiff > 1)
splitIndex.sort();
TObjArray *arr = new TObjArray();
arr->SetOwner();
start = -1;
std::list<Int_t>::const_iterator it;
#ifndef R__HPUX
for (it = splitIndex.begin(); it != splitIndex.end(); it++) {
#else
for (it = splitIndex.begin(); it != (std::list<Int_t>::const_iterator) splitIndex.end(); it++) {
#endif
Int_t stop = *it;
if (stop - 1 >= start + 1) {
TString tok = (*this)(start+1, stop-start-1);
TObjString *objstr = new TObjString(tok);
arr->Add(objstr);
}
start = stop;
}
return arr;
}
void TString::FormImp(const char *fmt, va_list ap)
{
Ssiz_t buflen = 20 + 20 * strlen(fmt);
Clobber(buflen);
va_list sap;
R__VA_COPY(sap, ap);
int n, vc = 0;
again:
n = vsnprintf(GetPointer(), buflen, fmt, ap);
if (n == -1 || n >= buflen) {
if (n == -1)
buflen *= 2;
else
buflen = n+1;
Clobber(buflen);
va_end(ap);
R__VA_COPY(ap, sap);
vc = 1;
goto again;
}
va_end(sap);
if (vc)
va_end(ap);
SetSize(strlen(Data()));
}
void TString::Form(const char *va_(fmt), ...)
{
va_list ap;
va_start(ap, va_(fmt));
FormImp(va_(fmt), ap);
va_end(ap);
}
TString TString::Format(const char *va_(fmt), ...)
{
va_list ap;
va_start(ap, va_(fmt));
TString str;
str.FormImp(va_(fmt), ap);
va_end(ap);
return str;
}
static char *SlowFormat(const char *format, va_list ap, int hint)
{
static const int fld_size = 2048;
TTHREAD_TLS(char*) slowBuffer(0);
TTHREAD_TLS(int) slowBufferSize(0);
if (hint == -1) hint = fld_size;
if (hint > slowBufferSize) {
delete [] slowBuffer;
slowBufferSize = 2 * hint;
if (hint < 0 || slowBufferSize < 0) {
slowBufferSize = 0;
slowBuffer = 0;
return 0;
}
slowBuffer = new char[slowBufferSize];
}
va_list sap;
R__VA_COPY(sap, ap);
int n = vsnprintf(slowBuffer, slowBufferSize, format, ap);
if (n == -1 || n >= slowBufferSize) {
if (n == -1) n = 2 * slowBufferSize;
if (n == slowBufferSize) n++;
if (n <= 0) {
va_end(sap);
return 0;
}
va_end(ap);
R__VA_COPY(ap, sap);
char *buf = SlowFormat(format, ap, n);
va_end(sap);
va_end(ap);
return buf;
}
va_end(sap);
return slowBuffer;
}
static char *Format(const char *format, va_list ap)
{
static const int cb_size = 4096;
static const int fld_size = 2048;
TTHREAD_TLS_ARRAY(char,cb_size,gFormbuf);
TTHREAD_TLS(char*) gBfree(0);
TTHREAD_TLS(char*) gEndbuf(0);
if (gBfree == 0) {
gBfree = gFormbuf;
gEndbuf = &gFormbuf[cb_size-1];
}
char *buf = gBfree;
if (buf+fld_size > gEndbuf)
buf = gFormbuf;
va_list sap;
R__VA_COPY(sap, ap);
int n = vsnprintf(buf, fld_size, format, ap);
if (n == -1 || n >= fld_size) {
va_end(ap);
R__VA_COPY(ap, sap);
buf = SlowFormat(format, ap, n);
va_end(sap);
va_end(ap);
return buf;
}
va_end(sap);
gBfree = buf+n+1;
return buf;
}
char *Form(const char *va_(fmt), ...)
{
va_list ap;
va_start(ap,va_(fmt));
char *b = Format(va_(fmt), ap);
va_end(ap);
return b;
}
void Printf(const char *va_(fmt), ...)
{
va_list ap;
va_start(ap,va_(fmt));
if (gPrintViaErrorHandler)
ErrorHandler(kPrint, 0, va_(fmt), ap);
else {
char *b = Format(va_(fmt), ap);
printf("%s\n", b);
fflush(stdout);
}
va_end(ap);
}
char *Strip(const char *s, char c)
{
if (!s) return 0;
int l = strlen(s);
char *buf = new char[l+1];
if (l == 0) {
*buf = '\0';
return buf;
}
const char *t1 = s;
while (*t1 == c)
t1++;
const char *t2 = s + l - 1;
while (*t2 == c && t2 > s)
t2--;
if (t1 > t2) {
*buf = '\0';
return buf;
}
strncpy(buf, t1, (Ssiz_t) (t2-t1+1));
*(buf+(t2-t1+1)) = '\0';
return buf;
}
char *StrDup(const char *str)
{
if (!str) return 0;
char *s = new char[strlen(str)+1];
if (s) strcpy(s, str);
return s;
}
char *Compress(const char *str)
{
if (!str) return 0;
const char *p = str;
char *s, *s1 = new char[strlen(str)+1];
s = s1;
while (*p) {
if (*p != ' ')
*s++ = *p;
p++;
}
*s = '\0';
return s1;
}
int EscChar(const char *src, char *dst, int dstlen, char *specchars,
char escchar)
{
const char *p;
char *q, *end = dst+dstlen-1;
for (p = src, q = dst; *p && q < end; ) {
if (strchr(specchars, *p)) {
*q++ = escchar;
if (q < end)
*q++ = *p++;
} else
*q++ = *p++;
}
*q = '\0';
if (*p != 0)
return -1;
return q-dst;
}
int UnEscChar(const char *src, char *dst, int dstlen, char *specchars, char)
{
const char *p;
char *q, *end = dst+dstlen-1;
for (p = src, q = dst; *p && q < end; ) {
if (strchr(specchars, *p))
p++;
else
*q++ = *p++;
}
*q = '\0';
if (*p != 0)
return -1;
return q-dst;
}
#ifdef NEED_STRCASECMP
int strcasecmp(const char *str1, const char *str2)
{
return strncasecmp(str1, str2, str2 ? strlen(str2)+1 : 0);
}
int strncasecmp(const char *str1, const char *str2, Ssiz_t n)
{
while (n > 0) {
int c1 = *str1;
int c2 = *str2;
if (isupper(c1))
c1 = tolower(c1);
if (isupper(c2))
c2 = tolower(c2);
if (c1 != c2)
return c1 - c2;
str1++;
str2++;
n--;
}
return 0;
}
#endif