/* Web Polygraph http://www.web-polygraph.org/
* (C) 2003-2006 The Measurement Factory
* Licensed under the Apache License, Version 2.0 */
#include "xstd/xstd.h"
#include "xstd/h/iostream.h"
#include "xstd/h/sstream.h"
#include "xstd/h/string.h"
#include "xstd/Assert.h"
#include "xstd/String.h"
#include "xstd/gadgets.h"
/* StrBuf */
void StrBuf::alloc(int aSize) {
theBuf = new char[theSize = aSize];
}
void StrBuf::set(const char *aBuf, int aSize) {
Assert(!theUseLvl);
//cerr << here << "new string: " << aSize << ' ' << aBuf << endl;
delete[] theBuf;
alloc(aSize);
memcpy(theBuf, aBuf, aSize);
}
StrBuf *StrBuf::clone() const {
StrBuf *sb = new StrBuf;
sb->set(theBuf, theSize);
return sb;
}
void StrBuf::realloc(int newSize) {
if (newSize > theSize) {
char *buf = theBuf;
const int sz = theSize;
theBuf = 0;
alloc(newSize);
if (buf)
memcpy(theBuf, buf, sz);
delete[] buf;
}
}
/* String */
String::String(const char *s, int len): theBuf(0) {
Assert(s);
Assert(len >= 0);
if (len > 0) {
theBuf = new StrBuf;
theBuf->alloc(len+1);
memcpy(theBuf->theBuf, s, len);
theBuf->theBuf[len] = '\0';
theBuf->use();
}
}
void String::set(const char *s) {
if (theBuf)
theBuf = theBuf->abandon();
if (s) {
if (const int l = strlen(s)) {
theBuf = new StrBuf;
theBuf->set(s, l+1);
theBuf->use();
}
}
}
void String::set(const String &s) {
if (theBuf == s.theBuf)
return; // either "copy to self" or "0 = 0"
if (theBuf)
theBuf->abandon();
if ((theBuf = s.theBuf))
theBuf->use();
}
char *String::alloc(int size) {
if (theBuf)
theBuf->abandon();
theBuf = new StrBuf;
theBuf->alloc(size);
theBuf->use();
return theBuf->theBuf;
}
void String::stretch(int newSize) {
if (!theBuf || theBuf->theSize < newSize) {
if (theBuf)
theBuf->realloc(newSize);
else
alloc(newSize);
}
}
// clone a private copy if we are using shared memory
// (copy-on-write or lazy copying)
void String::aboutToMod() {
if (theBuf && theBuf->theUseLvl > 1) {
StrBuf *sb = theBuf;
theBuf = sb->clone();
theBuf->use();
sb->abandon();
}
}
const char *String::chr(char c) const {
return theBuf ? strchr(cstr(), c) : 0;
}
const char *String::rchr(char c) const {
return theBuf ? strrchr(cstr(), c) : 0;
}
const char *String::str(const char *s) const {
return theBuf ? strstr(cstr(), s) : 0;
}
const char *String::str(const String &s) const {
return str(s.cstr());
}
String String::operator ()(int min, int maxp1) const {
maxp1 = Min(maxp1, len());
const int len = maxp1 - min;
Assert(len >= 0);
return String(data() + min, len);
}
Area String::area(int offset, int size) const {
if (offset == 0 && size == npos && len() == 0)
return Area::Empty();
Assert(offset < len() || size == 0);
return Area::Create(data(), offset, Min(size, len()-offset));
}
int String::cmp(const String &s) const {
return strcmp(cstr(), s.cstr());
}
int String::cmp(const String &s, int len) const {
return strncmp(cstr(), s.cstr(), len);
}
int String::cmp(const char *s) const {
return strcmp(cstr(), s);
}
int String::cmp(const char *s, int size) const {
return strncmp(cstr(), s, size);
}
bool String::startsWith(const String &s) const {
return s.prefixOf(this->cstr());
}
bool String::prefixOf(const char *buf) const {
if (const int l = len())
return strncmp(theBuf->theBuf, buf, l) == 0;
else
return true; // empty string is always a prefix?
}
bool String::casePrefixOf(const char *buf, int size) const {
if (const int l = len())
return l <= size && !strncasecmp(theBuf->theBuf, buf, l);
else
return true; // empty string is always a prefix?
}
bool String::caseEndsWith(const char *buf, int size) const {
if (const int l = len())
return size <= l && !strncasecmp(theBuf->theBuf + l-size, buf, l);
else
return false;
}
int String::find(char c, int offset) const {
if (!Should(offset <= len()))
return npos;
if (const char *p = strchr(cstr() + offset, c))
return p - cstr();
else
return npos;
}
int String::find(const Area &area, int offset) const {
if (!area)
return npos;
for (const int maxo = len() - area.size(); offset <= maxo; ++offset) {
offset = find(area[0], offset);
if (maxo < offset)
break;
if (strncmp(data()+offset, area.data(), area.size()) == 0)
return offset;
}
return npos;
}
int String::hash() const {
const int step = Max(1, len() / 16);
unsigned int res = 0;
for (int i = 0; i < len(); i += step)
res = res*33U + data()[i];
return Max(1, abs((int)res));
}
// adds 0 after appending if not already there
void String::append(const char *buf, int size) {
Assert(buf || !size);
aboutToMod();
const bool addTerm = !size || buf[size-1] != (char)0;
const int l = len();
stretch(l + size + (int)addTerm);
Assert(theBuf);
if (size)
memcpy(theBuf->theBuf+l, buf, size);
theBuf->theBuf[len()] = '\0';
}
String &String::operator +=(const String &s) {
append(s.data(), s.len());
return *this;
}
String &String::operator +=(char c) {
append(&c, 1);
return *this;
}
String String::operator +(char c) const {
String s(*this);
s += c;
return s;
}
/* operators on strings */
ostream &operator <<(ostream &os, const String &s) {
if (s)
os.write(s.data(), s.len());
return os;
}
String operator +(const String &s1, const String &s2) {
String s(s1);
s += s2;
return s;
}
String Stream2String(ostringstream &os) {
const std::string s = os.str();
const String res = s.size() > 0 ?
String(s.data(), s.size()) : String();
streamFreeze(os, false);
return res;
}
/* StrIter */
StrIter::StrIter(const String &aStr, char aDel):
theStr(aStr), theTokBeg(0), theTokEnd(0), theDel(aDel) {
if (theStr) {
theTokBeg = theTokEnd = theStr.data();
moveEnd();
}
}
String StrIter::token() const {
return String(tokBeg(), tokLen());
}
void StrIter::next() {
if (theTokEnd < theStr.data() + theStr.len()) {
theTokBeg = ++theTokEnd;
moveEnd();
} else {
theTokBeg = theTokEnd;
}
}
void StrIter::moveEnd() {
while (theTokEnd < theStr.data() + theStr.len() && *theTokEnd != theDel)
++theTokEnd;
}
syntax highlighted by Code2HTML, v. 0.9.1