/* * * C++ Portable Types Library (PTypes) * Version 2.1.1 Released 27-Jun-2007 * * Copyright (C) 2001-2007 Hovik Melikyan * * http://www.melikyan.com/ptypes/ * */ #include #include #include #include "ptypes.h" #include "ptime.h" // nowstring() is defined in this module PTYPES_BEGIN const int strrecsize = sizeof(_strrec); static void stringoverflow() { fatal(CRIT_FIRST + 21, "String overflow"); } void string::idxerror() { fatal(CRIT_FIRST + 20, "String index overflow"); } int stralloc; char emptystrbuf[strrecsize + 4]; char* emptystr = emptystrbuf + strrecsize; string nullstring; inline int quantize(int numchars) { return memquantize(numchars + 1 + strrecsize); } void string::_alloc(int numchars) { if (numchars <= 0) stringoverflow(); size_t a = quantize(numchars); #ifdef DEBUG stralloc += a; #endif data = (char*)(memalloc(a)) + strrecsize; STR_LENGTH(data) = numchars; STR_REFCOUNT(data) = 1; data[numchars] = 0; } void string::_realloc(int numchars) { if (numchars <= 0 || STR_LENGTH(data) <= 0) stringoverflow(); int a = quantize(numchars); int b = quantize(STR_LENGTH(data)); if (a != b) { #ifdef DEBUG stralloc += a - b; #endif data = (char*)(memrealloc(data - strrecsize, a)) + strrecsize; } STR_LENGTH(data) = numchars; data[numchars] = 0; } inline void _freestrbuf(char* data) { #ifdef DEBUG stralloc -= quantize(STR_LENGTH(data)); #endif memfree((char*)(STR_BASE(data))); } void string::_free() { _freestrbuf(data); data = emptystr; } void string::initialize(const char* sc, int initlen) { if (initlen <= 0 || sc == nil) data = emptystr; else { _alloc(initlen); memmove(data, sc, initlen); } } void string::initialize(const char* sc) { initialize(sc, hstrlen(sc)); } void string::initialize(char c) { _alloc(1); data[0] = c; } void string::initialize(const string& s) { data = s.data; #ifdef PTYPES_ST STR_REFCOUNT(data)++; #else pincrement(&STR_REFCOUNT(data)); #endif } void string::finalize() { if (STR_LENGTH(data) != 0) { #ifdef PTYPES_ST if (--STR_REFCOUNT(data) == 0) #else if (pdecrement(&STR_REFCOUNT(data)) == 0) #endif _freestrbuf(data); data = emptystr; } } char* ptdecl unique(string& s) { if (STR_LENGTH(s.data) > 0 && STR_REFCOUNT(s.data) > 1) { char* odata = s.data; s._alloc(STR_LENGTH(s.data)); memcpy(s.data, odata, STR_LENGTH(s.data)); #ifdef PTYPES_ST STR_REFCOUNT(odata)--; #else if (pdecrement(&STR_REFCOUNT(odata)) == 0) _freestrbuf(odata); #endif } return s.data; } char* ptdecl setlength(string& s, int newlen) { if (newlen < 0) return nil; int curlen = STR_LENGTH(s.data); // if becoming empty if (newlen == 0) s.finalize(); // if otherwise s was empty before else if (curlen == 0) s._alloc(newlen); // if length is not changing, return a unique string else if (newlen == curlen) unique(s); // non-unique reallocation else if (STR_REFCOUNT(s.data) > 1) { char* odata = s.data; s._alloc(newlen); memcpy(s.data, odata, imin(curlen, newlen)); #ifdef PTYPES_ST STR_REFCOUNT(odata)--; #else if (pdecrement(&STR_REFCOUNT(odata)) == 0) _freestrbuf(odata); #endif } // unique reallocation else s._realloc(newlen); return s.data; } void string::assign(const char* sc, int initlen) { if (STR_LENGTH(data) > 0 && initlen > 0 && STR_REFCOUNT(data) == 1) { // reuse data buffer if unique _realloc(initlen); memmove(data, sc, initlen); } else { finalize(); if (initlen == 1) initialize(sc[0]); else if (initlen > 1) initialize(sc, initlen); } } void string::assign(const char* sc) { assign(sc, hstrlen(sc)); } void string::assign(char c) { assign(&c, 1); } void string::assign(const string& s) { if (data != s.data) { finalize(); initialize(s); } } string ptdecl dup(const string& s) { // dup() only reads the data pointer so it is thread-safe return string(s.data); } string ptdecl nowstring(const char* fmt, bool utc) { char buf[128]; time_t longtime; time(&longtime); #if defined(PTYPES_ST) || defined(WIN32) tm* t; if (utc) t = gmtime(&longtime); else t = localtime(&longtime); int r = strftime(buf, sizeof(buf), fmt, t); #else tm t; if (utc) gmtime_r(&longtime, &t); else localtime_r(&longtime, &t); int r = strftime(buf, sizeof(buf), fmt, &t); #endif buf[r] = 0; return string(buf); } PTYPES_END