String.h

00001 // $Id: String.h 21 2010-09-05 04:18:17Z cschwarz1 $
00002 
00003 #ifndef BASE_STRING_H
00004 #define BASE_STRING_H
00005 
00006 #include <cstdlib>
00007 #include <stdexcept>
00008 #include <vector>
00009 #include "CharTraits.h"
00010 #include "IntTraits.h"
00011 
00012 namespace base {
00014 
00018     template<class charT, class traits = CharTraits<charT> > class StringT {
00019     public:
00020         typedef typename traits::size_type size_type;   
00021         static const size_type npos = static_cast<size_type>(-1);   
00022 
00024         StringT() {
00025             _buf = NULL;
00026             _len = _size = 0;
00027         }
00028 
00030         StringT(const StringT &s) {
00031             _buf = NULL;
00032             _size = 0;
00033             assign(s);
00034         }
00035 
00037         template<typename T> StringT(T t)  {
00038             _buf = NULL;
00039             _size = 0;
00040             assign(t);
00041         }
00042 
00044         StringT(const StringT &s, size_type pos, size_type len = npos) {
00045             _buf = NULL;
00046             _size = 0;
00047             assign(s, pos, len);
00048         }
00049 
00051         StringT(const charT *s, size_type len) {
00052             _buf = NULL;
00053             _size = 0;
00054             assign(s, len);
00055         }
00056 
00058         ~StringT() {
00059             if (_buf)
00060                 free(_buf);
00061         }
00062 
00064         StringT &append(charT ch) {
00065             return append(&ch, 1);
00066         }
00067 
00069         StringT &append(double n) {
00070             charT buf[128];
00071 
00072             return append(buf, traits::dtoa(n, buf));
00073         }
00074 
00076         StringT &append(int n) {
00077             charT buf[64];
00078 
00079             return append(buf, traits::ltoa(n, buf));
00080         }
00081 
00083         StringT &append(unsigned int n) {
00084             charT buf[64];
00085 
00086             return append(buf, traits::ultoa(n, buf));
00087         }
00088 
00090         StringT &append(long n) {
00091             charT buf[64];
00092 
00093             return append(buf, traits::ltoa(n, buf));
00094         }
00095 
00097         StringT &append(unsigned long n) {
00098             charT buf[64];
00099 
00100             return append(buf, traits::ultoa(n, buf));
00101         }
00102 
00104         StringT &append(longlong_t n) {
00105             charT buf[64];
00106 
00107             return append(buf, traits::lltoa(n, buf));
00108         }
00109 
00111         StringT &append(u_longlong_t n) {
00112             charT buf[64];
00113 
00114             return append(buf, traits::ulltoa(n, buf));
00115         }
00116 
00118         StringT &append(const StringT &s) {
00119             return append(s.data(), s.length());
00120         }
00121 
00123         StringT &append(const StringT &s, size_type pos, size_type len = npos) {
00124             if (pos < s.length()) {
00125                 if (len == npos || pos + len > s.length())
00126                     len = s.length() - pos;
00127                 return append(s.data() + pos, len);
00128             } else
00129                 return *this;
00130         }
00131 
00133         StringT &append (const charT *s) {
00134             return append(s, traits::length(s));
00135         }
00136 
00138         StringT &append(const charT *s, size_type len)  {
00139             if (s && len > 0) {
00140                 if (len + _len >= _size)
00141                     resize(len + _len);
00142                 traits::memmove(_buf + _len, s, len);
00143                 _buf[_len += len] = traits::nul;
00144             }
00145             return *this;
00146         }
00147 
00149         StringT &append(size_type n, charT ch) {
00150             if (n > 0) {
00151                 if (n + _len >= _size)
00152                     resize(n + _len);
00153                 traits::memset(_buf + _len, ch, n);
00154                 _buf[_len += n] = traits::nul;
00155             }
00156             return *this;
00157         }
00158 
00160 
00164         StringT &appendf(const charT *fmt, ...) {
00165             va_list ap;
00166 
00167             va_start(ap, fmt);
00168             appendvf(fmt, ap);
00169             va_end(ap);
00170             return *this;
00171         }
00172 
00174 
00178         StringT &appendvf(const charT *fmt, va_list ap) {
00179             size_type len;
00180             size_type n = 4;
00181 
00182             for (;;) {
00183                 len = traits::vxprintf(_buf + _len, _size - _len, fmt, ap);
00184                 if (len == npos) {
00185                     n <<= 1;
00186                     resize(_size + n);
00187                 } else if (len >= _size - _len)
00188                     resize(_len + len);
00189                 else {
00190                     _len += len;
00191                     break;
00192                 }
00193             }
00194             return *this;
00195         }
00196 
00198         StringT &assign(charT ch) {
00199             return assign(&ch, 1);
00200         }
00201 
00203         StringT &assign(double n) {
00204             charT buf[128];
00205 
00206             return assign(buf, traits::dtoa(n, buf));
00207         }
00208 
00210         StringT &assign(int n) {
00211             charT buf[64];
00212 
00213             return assign(buf, traits::ltoa(n, buf));
00214         }
00215 
00217         StringT &assign(unsigned int n) {
00218             charT buf[64];
00219 
00220             return assign(buf, traits::ultoa(n, buf));
00221         }
00222 
00224         StringT &assign(long n) {
00225             charT buf[64];
00226 
00227             return assign(buf, traits::ltoa(n, buf));
00228         }
00229 
00231         StringT &assign(unsigned long n) {
00232             charT buf[64];
00233 
00234             return assign(buf, traits::ultoa(n, buf));
00235         }
00236 
00238         StringT &assign(longlong_t n) {
00239             charT buf[64];
00240 
00241             return assign(buf, traits::lltoa(n, buf));
00242         }
00243 
00245         StringT &assign(u_longlong_t n) {
00246             charT buf[64];
00247 
00248             return assign(buf, traits::ulltoa(n, buf));
00249         }
00250 
00252         StringT &assign(const StringT &s) {
00253             return assign(s.data(), s.length());
00254         }
00255 
00257         StringT &assign(const StringT &s, size_type pos, size_type len = npos) {
00258             if (pos < s.length()) {
00259                 if (len > s.length() - pos)
00260                     len = s.length() - pos;
00261                 return assign(s.data() + pos, len);
00262             } else
00263                 return clear();
00264         }
00265 
00267         StringT &assign(const charT *s) {
00268             return assign(s, traits::length(s));
00269         }
00270 
00272         StringT &assign(const charT *s, size_type len) {
00273             if (s) {
00274                 if (len >= _size)
00275                     resize(len);
00276                 if (len <= 0)
00277                     len = 0;
00278                 else
00279                     traits::memmove(_buf, s, len);
00280                 _len = len;
00281                 _buf[_len] = traits::nul;
00282             } else {
00283                 _len = 0;
00284                 if (_buf)
00285                     *_buf = traits::nul;
00286             }
00287             return *this;
00288         }
00289 
00291 
00295         StringT &assignf(const charT *fmt, ...) {
00296             va_list ap;
00297 
00298             va_start(ap, fmt);
00299             assignvf(fmt, ap);
00300             va_end(ap);
00301             return *this;
00302         }
00303 
00305 
00309         StringT &assignvf(const charT *fmt, va_list ap) {
00310             size_type len;
00311             size_type n = 4;
00312 
00313             for (;;) {
00314                 len = traits::vxprintf(_buf, _size, fmt, ap);
00315                 if (len == npos) {
00316                     n <<= 1;
00317                     resize(_size + n);
00318                 } else if (len >= _size)
00319                     resize(len);
00320                 else {
00321                     _len = len;
00322                     break;
00323                 }
00324             }
00325             return *this;
00326         }
00327 
00329         const charT *c_str() const {
00330             return _buf ? _buf : traits::empty;
00331         }
00332 
00334         size_type capacity() const {
00335             return _size ? _size - 1 : 0;
00336         }
00337 
00339         StringT &clear() {
00340             if (_buf)
00341                 _buf[_len = 0] = traits::nul;
00342             return *this;
00343         }
00344 
00346 
00351         int compare(const StringT &s, bool icase = false) const {
00352             return compare(0, _len, s.data(), s.length(), icase);
00353         }
00354 
00356         int compare(const StringT &s, size_type pos, size_type len, bool icase = false) const {
00357             return compare(0, _len, s.data() + pos, len, icase);
00358         }
00359 
00361         int compare(size_type pos, size_type len, const StringT &s, bool icase = false) const {
00362             return compare(pos, len, s.data(), s.length(), icase);
00363         }
00364 
00366         int compare(size_type pos, size_type len, const StringT &s, size_type spos, size_type slen, bool icase = false) const {
00367             return compare(pos, len, s.data() + spos, slen, icase);
00368         }
00369 
00371         int compare(const charT *s, bool icase = false) const {
00372             return compare(0, _len, s, traits::length(s), icase);
00373         }
00374 
00376         int compare(const charT *s, size_type len, bool icase = false) const {
00377             return compare(0, _len, s, len, icase);
00378         }
00379 
00381         int compare(size_type pos, size_type len, const charT *s, bool icase = false) const {
00382             return compare(pos, len, s, traits::length(s), icase);
00383         }
00384 
00386         int compare(size_type pos, size_type len, const charT *s, size_type slen, bool icase = false) const {
00387             size_type    m;
00388             size_type    n;
00389             const charT *p;
00390             const charT *q;
00391             int          ret;
00392 
00393             if (pos >= _len)
00394                 ret = slen ? -1 : 0;
00395             else {
00396                 if (pos + len > _len)
00397                     len = _len - pos;
00398                 if (icase) {
00399                     n = len;
00400                     q = s;
00401                     m = slen;
00402                     p = _buf + pos;
00403                     ret = 0;
00404                     while (m > 0 && n > 0) {
00405                         if (traits::tolower(*p) < traits::tolower(*q)) {
00406                             ret = -1;
00407                             break;
00408                         } else if (traits::tolower(*p) > traits::tolower(*q)) {
00409                             ret = 1;
00410                             break;
00411                         } else {
00412                             m--;
00413                             n--;
00414                             p++;
00415                             q++;
00416                         }
00417                     }
00418                     if (!ret)
00419                         ret = n ? 1 : (m ? -1 : 0);
00420                 } else {
00421                     if ((ret = traits::memcmp(_buf + pos, s, slen < len ? slen : len)) == 0)
00422                         ret = slen < len ? 1 : (slen > len ? -1 : 0);
00423                 }
00424             }
00425             return ret;
00426         }
00427 
00429         const charT *data() const {
00430             return _buf ? _buf : traits::empty;
00431         }
00432 
00434         bool empty() const {
00435             return _len <= 0;
00436         }
00437 
00439         StringT &erase(size_type pos = 0, size_type len = npos) {
00440             if (pos < _len) {
00441                 if (len > _len - pos)
00442                     len = _len - pos;
00443                 if (len > 0) {
00444                     traits::memmove(_buf + pos, _buf + pos + len, _len - pos - len + 1);
00445                     _len -= len;
00446                 }
00447             }
00448             return *this;
00449         }
00450 
00452         StringT &eraseAll(charT ch) {
00453             for (size_type pos = 0; pos < _len; ) {
00454                 if (_buf[pos] == ch)
00455                     erase(pos, 1);
00456                 else
00457                     pos++;
00458             }
00459             return *this;
00460         }
00461 
00463         size_type find(const StringT &s, size_type pos = 0, bool icase = false) const {
00464             return find(s.data(), pos, s.length(), icase);
00465         }
00466 
00468         size_type find(const charT *s, size_type pos = 0, bool icase = false) const {
00469             return find(s, pos, traits::length(s), icase);
00470         }
00471 
00473         size_type find(const charT *s, size_type pos, size_type len, bool icase = false) const {
00474             size_type i;
00475             size_type ret = npos;
00476 
00477             if (len > 0) {
00478                 if (icase) {
00479                     for (i = 0; pos + i < _len; ) {
00480                         if (traits::tolower(s[i]) == traits::tolower(_buf[pos + i])) {
00481                             if (++i >= len) {
00482                                 ret = pos;
00483                                 break;
00484                             }
00485                         } else {
00486                             i = 0;
00487                             pos++;
00488                         }
00489                     }
00490                 } else {
00491                     for (i = 0; pos + i < _len; ) {
00492                         if (s[i] == _buf[pos + i]) {
00493                             if (++i >= len) {
00494                                 ret = pos;
00495                                 break;
00496                             }
00497                         } else {
00498                             i = 0;
00499                             pos++;
00500                         }
00501                     }
00502                 }
00503             }
00504 
00505             return ret;
00506         }
00507 
00509         size_type find(charT ch, size_type pos = 0) const {
00510             size_type ret;
00511 
00512             for (ret = pos; ret < _len && _buf[ret] != ch; ret++) ;
00513             if (ret >= _len)
00514                 ret = npos;
00515 
00516             return ret;
00517         }
00518 
00520         size_type find_first_not_of(const StringT &s, size_type pos = 0) const {
00521             return find_first_not_of(s.data(), pos, s.length());
00522         }
00523 
00525         size_type find_first_not_of(const charT *s, size_type pos = 0) const {
00526             return find_first_not_of(s, pos, traits::length(s));
00527         }
00528 
00530         size_type find_first_not_of(const charT *s, size_type pos, size_type len) const {
00531             size_type  i;
00532             size_type  n = _len;
00533             charT     *p;
00534             size_type  ret;
00535 
00536             // len = length of s
00537             if (pos < n) {
00538                 for (ret = pos, p = _buf + pos; ret < n; p++, ret++) {
00539                     // p = pointer to the current char in *this
00540                     unsigned c = 0;
00541 
00542                     for (i = 0; i < len; i++)
00543                         if (s[i] != *p)
00544                             c++;
00545                     if (c == len)
00546                         return ret;
00547                     if (i < len)
00548                         break;
00549                 }
00550                 if (ret >= n)
00551                     ret = npos;
00552             } else
00553                 ret = npos;
00554             return ret;
00555         }
00556 
00558         size_type find_first_of(const StringT &s, size_type pos = 0) const {
00559             return find_first_of(s.data(), pos, s.length());
00560         }
00561 
00563         size_type find_first_of(const charT *s, size_type pos = 0) const {
00564             return find_first_of(s, pos, traits::length(s));
00565         }
00566 
00568         size_type find_first_of(const charT *s, size_type pos, size_type len) const {
00569             size_type  i;
00570             size_type  n = _len;
00571             charT     *p;
00572             size_type  ret;
00573 
00574             if (pos < n) {
00575                 for (ret = pos, p = _buf + pos; ret < n; p++, ret++) {
00576                     for (i = 0; i < len; i++)
00577                         if (s[i] == *p)
00578                             break;
00579                     if (i < len)
00580                         break;
00581                 }
00582                 if (ret >= n)
00583                     ret = npos;
00584             } else
00585                 ret = npos;
00586             return ret;
00587         }
00588 
00590         size_type find_first_of(charT ch, size_type pos = 0) const {
00591             return find(ch, pos);
00592         }
00593 
00595         size_type find_last_not_of(const StringT &s, size_type pos = npos) const {
00596             return find_last_not_of(s.data(), pos, s.length());
00597         }
00598 
00600         size_type find_last_not_of(const charT *s, size_type pos = npos) const {
00601             return find_last_not_of(s, pos, traits::length(s));
00602         }
00603 
00605         size_type find_last_not_of(const charT *s, size_type pos, size_type len) const {
00606             size_type  i;
00607             size_type  n = _len;
00608             charT     *p;
00609             size_type  ret;
00610 
00611             // len = length of s
00612             if (pos >= n)
00613                 pos = n - 1;
00614             if (pos < n) {
00615                 for (ret = pos, p = _buf + pos; ; p--, ret--) {
00616                     // p = pointer to the current char in *this
00617                     unsigned c = 0;
00618 
00619                     for (i = 0; i < len; i++)
00620                         if (s[i] != *p)
00621                             c++;
00622                     if (c == len)
00623                         return ret;
00624                     if (i < len)
00625                         break;
00626                     if (!ret)
00627                         return npos;
00628                 }
00629             } else
00630                 ret = npos;
00631             return ret;
00632         }
00633 
00635         size_type find_last_of(const StringT &s, size_type pos = npos) const {
00636             return find_last_of(s.data(), pos, s.length());
00637         }
00638 
00640         size_type find_last_of(const charT *s, size_type pos = npos) const {
00641             return find_last_of(s, pos, traits::length(s));
00642         }
00643 
00645         size_type find_last_of(const charT *s, size_type pos, size_type len) const {
00646             size_type  i;
00647             size_type  n = _len;
00648             charT     *p;
00649             size_type  ret;
00650 
00651             // len = length of s
00652             if (pos >= n)
00653                 pos = n - 1;
00654             if (pos < n) {
00655                 for (ret = pos, p = _buf + pos; ; p--, ret--) { 
00656                     // p = pointer to the current char in *this
00657                     for (i = 0; i < len; i++)
00658                         if (s[i] == *p)
00659                             return ret;
00660                     if (!ret)
00661                         break;
00662                 }
00663                 ret = npos;
00664             } else
00665                 ret = npos;
00666             return ret;
00667         }
00668 
00670         charT *getBuffer() {
00671             return _buf;
00672         }
00673 
00675         charT getCharAt(size_type pos) const {
00676             return pos < _len ? _buf[pos] : traits::nul;
00677         }
00678 
00680         StringT &insert(size_type pos, charT ch) {
00681             return insert(pos, &ch, 1);
00682         }
00683 
00685         StringT &insert(size_type pos, const StringT &s) {
00686             return insert(pos, s.data(), s.length());
00687         }
00688 
00690         StringT &insert(size_type pos, const charT *s) {
00691             return insert(pos, s, traits::length(s));
00692         }
00693 
00695         StringT &insert(size_type pos, const charT *s, size_type len) {
00696             if (len > 0 && pos <= _len) {
00697                 if (_len + len >= _size)
00698                     resize(_len + len);
00699                 if (!_len)
00700                     *_buf = traits::nul;
00701                 traits::memmove(_buf + pos + len, _buf + pos, _len - pos + 1);
00702                 traits::memmove(_buf + pos, s, len);
00703                 _len += len;
00704             }
00705             return *this;
00706         }
00707 
00709         size_type length() const {
00710             return _len;
00711         }
00712 
00714         StringT &replace(size_type pos, size_type cnt, const StringT &s, size_type start = 0, size_type len = npos) {
00715             if (len == npos)
00716                 len = s.length() - start;
00717             return replace(pos, cnt, s.data() + start, len);
00718         }
00719 
00721         StringT &replace(size_type pos, size_type cnt, const charT *s) {
00722             return replace(pos, cnt, s, traits::length(s));
00723         }
00724 
00726         StringT &replace(size_type pos, size_type cnt, const charT *s, size_type len) {
00727             if (pos <= _len) {
00728                 if (pos + cnt > _len)
00729                     cnt = _len - pos;
00730                 if (cnt < len) {
00731                     if (_size - _len <= len - cnt)
00732                         resize(_len + len - cnt);
00733                     if (_len - pos > cnt)
00734                         traits::memmove(_buf + pos + len, _buf + pos + cnt, _len - pos - cnt);
00735                     _len += len - cnt;
00736                 } else if (cnt > len) {
00737                     traits::memmove(_buf + pos + len, _buf + pos + cnt, _len - pos - cnt);
00738                     _len -= cnt - len;
00739                 }
00740                 if (len > 0)
00741                     traits::memmove(_buf + pos, s, len);
00742                 _buf[_len] = traits::nul;
00743             }
00744             return *this;
00745         }
00746 
00748 
00753         StringT &replaceAll(const StringT &oldstr, const StringT &newstr) {
00754             size_type pos = 0;
00755 
00756             do {
00757                 pos = find(oldstr, pos);
00758                 if (pos != npos) {
00759                     replace(pos, oldstr.length(), newstr);
00760                     pos += newstr.length();
00761                 }
00762             } while (pos != npos);
00763             return *this;
00764         }
00765 
00767 
00772         StringT &replaceAll(charT oldch, charT newch) {
00773             size_type pos;
00774 
00775             for (pos = 0; pos < _len; pos++)
00776                 if (_buf[pos] == oldch)
00777                     _buf[pos] = newch;
00778             return *this;
00779         }
00780 
00782         void resize(size_type n) {
00783             charT *buf;
00784 
00785             if (n >= _size) {
00786                 n++;              // terminating 0-byte
00787                 if (n % 8 != 0)   // allocate in multiples of 8
00788                     n += 8 - (n % 8);
00789                 if (_buf) {
00790                     if ((buf = static_cast<charT*>(realloc(_buf, n * sizeof(charT)))) == NULL)
00791                         throw std::bad_alloc();
00792                     _buf = buf;
00793                 } else {
00794                     if ((_buf = static_cast<charT*>(malloc(n * sizeof(charT)))) == NULL)
00795                         throw std::bad_alloc();
00796                 }
00797                 _size = n;
00798             }
00799         }
00800 
00802         size_type rfind(const StringT &s, size_type pos = npos, bool icase = false) const {
00803             return rfind(s.data(), pos, s.length(), icase);
00804         }
00805 
00807         size_type rfind(const charT *s, size_type pos = npos, bool icase = false) const {
00808             return rfind(s, pos, traits::length(s), icase);
00809         }
00810 
00812         size_type rfind(const charT *s, size_type pos, size_type len, bool icase = false) const {
00813             size_type i;
00814             size_type ret = npos;
00815 
00816             if (pos == npos || pos + len > _len) {
00817                 if (len <= _len)
00818                     pos = _len - len;
00819                 else
00820                     len = 0;   // search string is larger than this string -> cannot be found
00821             }
00822             if (len > 0) {
00823                 if (icase) {
00824                     for (i = 0; pos != npos; ) {
00825                         if (traits::tolower(s[i]) == traits::tolower(_buf[pos + i])) {
00826                             if (++i >= len) {
00827                                 ret = pos;
00828                                 break;
00829                             }
00830                         } else {
00831                             i = 0;
00832                             pos--;
00833                         }
00834                     }
00835                 } else {
00836                     for (i = 0; pos != npos; ) {
00837                         if (s[i] == _buf[pos + i]) {
00838                             if (++i >= len) {
00839                                 ret = pos;
00840                                 break;
00841                             }
00842                         } else {
00843                             i = 0;
00844                             pos--;
00845                         }
00846                     }
00847                 }
00848             }
00849 
00850             return ret;
00851         }
00852 
00854         size_type rfind(charT ch, size_type pos = npos) const {
00855             size_type ret;
00856 
00857             if (pos == npos)
00858                 pos = _len - 1;
00859             for (ret = pos; ret != npos && _buf[ret] != ch; ret--) ;
00860 
00861             return ret;
00862         }
00863 
00865         void setCharAt(size_type pos, charT ch) {
00866             if (pos < _len)
00867                 _buf[pos] = ch;
00868         }
00869 
00871         void setLength(size_type len) {
00872             if (len) {
00873                 if (len >= _size)
00874                     resize(len);
00875                 _buf[len] = traits::nul;
00876             } else {
00877                 if (_buf)
00878                     *_buf = traits::nul;
00879             }
00880             _len = len;
00881         }
00882 
00884         size_type size() const {
00885             return _len;
00886         }
00887 
00889 
00893         std::vector<StringT> split(const charT *delim) const {
00894             size_type            nxpos;
00895             size_type            pos;
00896             std::vector<StringT> ret;
00897             StringT              tmp;
00898 
00899             for (pos = 0; pos != npos; pos = nxpos) {
00900                 if ((nxpos = find_first_of(delim, pos)) == npos)
00901                     tmp = substr(pos);
00902                 else {
00903                     tmp = substr(pos, nxpos - pos);
00904                     nxpos++;
00905                 }
00906                 if (!tmp.trim().empty())
00907                     ret.push_back(tmp);
00908             }
00909             return ret;
00910         }
00911 
00913 
00918         charT *stealBuffer(size_type *rlen = NULL, size_type *rsize = NULL) {
00919             charT *ret;
00920 
00921             if (rlen)
00922                 *rlen = _len;
00923             if (rsize)
00924                 *rsize = _size;
00925             _len = _size = 0;
00926             ret = _buf;
00927             _buf = NULL;
00928             return ret;
00929         }
00930 
00932         StringT substr(size_type pos = 0, size_type len = npos) const {
00933             StringT ret;
00934 
00935             if (pos < _len) {
00936                 if (len > _len - pos)
00937                     len = _len - pos;
00938                 if (len > 0)
00939                     ret.assign(_buf + pos, len);
00940             }
00941             return ret;
00942         }
00943 
00945         StringT left(size_type len) const {
00946             return substr(0, len);
00947         }
00948 
00950         StringT &ltrim() {
00951             size_type i;
00952 
00953             if (_len) {
00954                 for (i = 0; i < _len; i++)
00955                     if (!traits::isspace(_buf[i]))
00956                         break;
00957                 if (i > 0) {
00958                     _len -= i;
00959                     if (_len > 0)
00960                         traits::memmove(_buf, _buf + i, _len);
00961                 }
00962                 _buf[_len] = traits::nul;
00963             }
00964             return *this;
00965         }
00966 
00968         StringT right(size_type len) const {
00969             return substr(len < _len ? _len - len : 0, len);
00970         }
00971 
00973         StringT &rtrim() {
00974             size_type i;
00975 
00976             if (_len) {
00977                 for (i = _len - 1; i != npos; i--)
00978                     if (!traits::isspace(_buf[i]))
00979                         break;
00980                 _buf[_len = i + 1] = traits::nul;
00981             }
00982             return *this;
00983         }
00984 
00986         StringT &toLowerCase() {
00987             size_type i;
00988 
00989             for (i = 0; i < _len; i++)
00990                 _buf[i] = traits::tolower(_buf[i]);
00991             return *this;
00992         }
00993 
00995         StringT &toUpperCase() {
00996             size_type i;
00997 
00998             for (i = 0; i < _len; i++)
00999                 _buf[i] = traits::toupper(_buf[i]);
01000             return *this;
01001         }
01002 
01004         StringT &trim() {
01005             size_type i;
01006 
01007             if (_len) {
01008                 for (i = _len - 1; i != npos; i--)
01009                     if (!traits::isspace(_buf[i]))
01010                         break;
01011                 _len = i + 1;
01012                 for (i = 0; i < _len; i++)
01013                     if (!traits::isspace(_buf[i]))
01014                         break;
01015                 if (i > 0) {
01016                     _len -= i;
01017                     if (_len > 0)
01018                         traits::memmove(_buf,_buf+i,_len);
01019                 }
01020                 _buf[_len] = traits::nul;
01021             }
01022             return *this;
01023         }
01024 
01026         StringT &trim(charT c) {
01027             size_type i;
01028 
01029             if (_len) {
01030                 for (i = _len - 1; i != npos; i--)
01031                     if (_buf[i] != c)
01032                         break;
01033                 _len = i + 1;
01034                 for (i = 0; i < _len; i++)
01035                     if (_buf[i] != c)
01036                         break;
01037                 if (i > 0) {
01038                     _len -= i;
01039                     if (_len > 0)
01040                         traits::memmove(_buf,_buf+i,_len);
01041                 }
01042                 _buf[_len] = traits::nul;
01043             }
01044             return *this;
01045         }
01046 
01048 
01058         void useBuffer(charT *buf) {
01059             size_type len;
01060 
01061             len = traits::length(buf);
01062             useBuffer(buf, len, len + 1);
01063         }
01064 
01066         void useBuffer(charT *buf, size_type len, size_type bufsize) {
01067             if (_buf)
01068                 free(_buf);
01069             if ((_buf = buf) != NULL) {
01070                 _len = len;
01071                 _size = bufsize;
01072             } else
01073                 _len = _size = 0;
01074         }
01075 
01077         void releaseBuffer() {
01078             _buf = NULL;
01079             _len = _size = 0;
01080         }
01081 
01083         charT &operator[](size_type pos) {
01084             if (pos >= _len)
01085                 throw std::range_error(StringT<char>().assignf("base::StringT[] index out of range: %u >= %u", pos, _len).c_str());
01086             return _buf[pos];
01087         }
01088 
01090         charT operator[](size_type pos) const {
01091             return pos < _len ? _buf[pos] : traits::nul;
01092         }
01093 
01095         operator void*() const {
01096             return _len <= 0 ? NULL : _buf;
01097         }
01098 
01100         bool operator!() const {
01101             return _len <= 0;
01102         }
01103 
01105         StringT &operator=(const StringT &s) {
01106             return assign(s);
01107         }
01108 
01110         template<typename T> StringT &operator=(T t) {
01111             return assign(t);
01112         }
01113 
01115         template<typename T> StringT &operator+=(T t) {
01116             return append(t);
01117         }
01118 
01120         bool operator==(const StringT &s) const {
01121             return compare(s) == 0;
01122         }
01123 
01125         bool operator==(const charT *s) const {
01126             return compare(s) == 0;
01127         }
01128 
01130         bool operator!=(const StringT &s) const {
01131             return compare(s) != 0;
01132         }
01133 
01135         bool operator!=(const charT *s) const {
01136             return compare(s) != 0;
01137         }
01138 
01140         bool operator<(const StringT &s) const {
01141             return compare(s) < 0;
01142         }
01143 
01145         bool operator<(const charT *s) const {
01146             return compare(s) < 0;
01147         }
01148 
01150         bool operator<=(const StringT &s) const {
01151             return compare(s) <= 0;
01152         }
01153 
01155         bool operator<=(const charT *s) const {
01156             return compare(s) <= 0;
01157         }
01158 
01160         bool operator>(const StringT &s) const {
01161             return compare(s) > 0;
01162         }
01163 
01165         bool operator>(const charT *s) const {
01166             return compare(s) > 0;
01167         }
01168 
01170         bool operator>=(const StringT &s) const {
01171             return compare(s) >= 0;
01172         }
01173 
01175         bool operator>=(const charT *s) const {
01176             return compare(s) >= 0;
01177         }
01178 
01179     protected:
01180         charT     *_buf;   
01181         size_type  _len;   
01182         size_type  _size;  
01183     };
01184 
01185     typedef StringT<char>    String;   
01186     typedef StringT<wchar_t> WString;  
01187 
01189     template<class charT, class traits, class T> StringT<charT, traits> operator+(const StringT<charT, traits> &s, T t) {
01190         StringT<charT, traits> ret = s;
01191         ret.append(t);
01192         return ret;
01193     }
01194 
01196     template<class streamT, class charT, class traits> streamT &operator<<(streamT &out, const StringT<charT, traits> &s) {
01197         return out.write(s.data(), static_cast<std::streamsize>(s.length()));
01198     }
01199 
01201     template<class streamT, class charT, class traits> streamT &operator>>(streamT &in, StringT<charT, traits> &s) {
01202         charT ch;
01203 
01204         while (in.get(ch) && traits::isspace(ch)) ;
01205         if (in) {
01206             s = ch;
01207             while (in.get(ch) && !traits::isspace(ch))
01208                 s.append(ch);
01209         }
01210         return in;
01211     }
01212 
01227     template<class charT, class intT>
01228     size_t uinttostr(intT i, charT *str, size_t size, unsigned char nbase = 10, charT ca = CharTraits<charT>::chA) {
01229         size_t ret = 0;
01230 
01231         if (nbase < 2 || nbase > 36)
01232             throw std::invalid_argument("base::uinttostr invalid nbase");
01233 
01234         if (str != NULL && size > 0) {
01235             size_t                                  a;
01236             size_t                                  b;
01237             charT                                   c;
01238             typename IntTraits<intT>::unsigned_type n = i;
01239             unsigned char                           j;
01240 
01241             do {
01242                 if (ret == size)
01243                     break;
01244                 j = n % nbase;
01245                 if (j < 10)
01246                     str[ret++] = CharTraits<charT>::ch0 + j;
01247                 else
01248                     str[ret++] = ca + (j - 10);
01249                 n /= nbase;
01250             } while (n != 0);
01251 
01252             if (ret < size) {
01253                 // add terminating null byte
01254                 str[ret] = CharTraits<charT>::nul;
01255                 // reverse string
01256                 for (a = 0, b = ret / 2; a < b; a++) {
01257                     c = str[a];
01258                     str[a] = str[ret - a - 1];
01259                     str[ret - a - 1] = c;
01260                 }
01261             } else
01262                 str[0] = CharTraits<charT>::nul;
01263         }
01264 
01265         return ret;
01266     }
01267 
01269     template<class charT, class intT>
01270     StringT<charT> uinttostr(intT i, unsigned char nbase = 10, charT ca = CharTraits<charT>::chA) {
01271         charT buf[128];
01272 
01273         if (uinttostr(i, buf, sizeof(buf) / sizeof(charT), nbase, ca) == sizeof(buf) / sizeof(charT)) {
01274             // should not happen
01275             throw std::length_error("base::uinttostr buffer too small");
01276         }
01277 
01278         return buf;
01279     }
01280 
01286     template<class charT, class intT>
01287     size_t inttostr(intT i, charT *str, size_t size, unsigned char nbase = 10, charT ca = CharTraits<charT>::chA) {
01288         size_t ret = 0;
01289 
01290         if (nbase < 2 || nbase > 36)
01291             throw std::invalid_argument("base::inttostr invalid nbase");
01292 
01293         if (str != NULL && size > 0) {
01294             typename IntTraits<intT>::unsigned_type n;
01295 
01296             if (i < 0) {
01297                 n = -i;
01298                 str[ret++] = '-';
01299                 size--;
01300                 str++;
01301             } else
01302                 n = i;
01303 
01304             ret += uinttostr(n, str, size, nbase, ca);
01305         }
01306 
01307         return ret;
01308     }
01309 
01311     template<class charT, class intT>
01312     StringT<charT> inttostr(intT i, unsigned char nbase = 10, charT ca = CharTraits<charT>::chA) {
01313         charT buf[128];
01314 
01315         if (inttostr(i, buf, sizeof(buf) / sizeof(charT), nbase, ca) == sizeof(buf) / sizeof(charT)) {
01316             // should not happen
01317             throw std::length_error("base::inttostr buffer too small");
01318         }
01319 
01320         return buf;
01321     }
01322 
01324     template<class charT, class intT>
01325     bool strtoint(const charT *str, intT *rint, int nbase = 0, const charT **rpos = NULL) {
01326         bool neg;
01327         intT ret = 0;
01328         intT tmp;
01329 
01330         *rint = 0;
01331         if (rpos)
01332             *rpos = str;
01333         if (str == NULL)
01334             return false;
01335         while (CharTraits<charT>::isspace(*str))
01336             str++;
01337         if (*str == CharTraits<charT>::ch_neg) {
01338             neg = true;
01339             str++;
01340         } else
01341             neg = false;
01342         if (nbase == 0) {
01343             if (*str == CharTraits<charT>::ch0) {
01344                 str++;
01345                 if (*str == CharTraits<charT>::chx || *str == CharTraits<charT>::chX) {
01346                     nbase = 16;
01347                     str++;
01348                 } else if (*str == CharTraits<charT>::nul) {
01349                     nbase = 10;   // plain "0"
01350                     str--;
01351                 } else
01352                     nbase = 8;
01353             } else
01354                 nbase = 10;
01355         }
01356         if (*str == CharTraits<charT>::nul) {
01357             if (rpos)
01358                 *rpos = str;
01359             return false;
01360         }
01361         if (nbase > 1 && nbase <= 10) {
01362             while (*str >= CharTraits<charT>::ch0 && *str < CharTraits<charT>::ch0 + nbase) {
01363                 tmp = ret;
01364                 ret *= nbase;
01365                 if (ret < tmp) {   // overflow
01366                     if (rpos)
01367                         *rpos = str;
01368                     return false;
01369                 }
01370                 ret += *str - CharTraits<charT>::ch0;
01371                 str++;
01372             }
01373         } else if (nbase > 10 && nbase <= 36) {
01374             for (;;) {
01375                 if (*str >= CharTraits<charT>::ch0 && *str < CharTraits<charT>::ch0 + 10) {
01376                     ret *= nbase;
01377                     ret += *str - CharTraits<charT>::ch0;
01378                 } else if (*str >= CharTraits<charT>::cha && *str < CharTraits<charT>::cha + nbase - 10) {
01379                     ret *= nbase;
01380                     ret += *str - CharTraits<charT>::cha + 10;
01381                 } else if (*str >= CharTraits<charT>::chA && *str < CharTraits<charT>::chA + nbase - 10) {
01382                     ret *= nbase;
01383                     ret += *str - CharTraits<charT>::chA + 10;
01384                 } else
01385                     break;
01386                 str++;
01387             }
01388         } else
01389             return false;
01390         if (*str != CharTraits<charT>::nul && rpos == NULL) {
01391             while (*str != CharTraits<charT>::nul && CharTraits<charT>::isspace(*str))
01392                 str++;
01393             if (*str != CharTraits<charT>::nul)
01394                 return false;
01395         }
01396         if (rpos != NULL)
01397             *rpos = str;
01398         if (neg) {
01399         #ifdef _MSC_VER
01400             #pragma warning (suppress: 4146)   // unary minus operator applied to unsigned type, result still unsigned
01401         #endif
01402             *rint = -ret;
01403         } else
01404             *rint = ret;
01405         return true;
01406     }
01407 
01409     template<class charT, class intT>
01410     bool strtoint(const StringT<charT> &str, intT *rint, int nbase = 0, const charT **rpos = NULL) {
01411         return strtoint(str.c_str(), rint, nbase, rpos);
01412     }
01413 
01414 }   // namespace base
01415 
01416 #endif