00001
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
00537 if (pos < n) {
00538 for (ret = pos, p = _buf + pos; ret < n; p++, ret++) {
00539
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
00612 if (pos >= n)
00613 pos = n - 1;
00614 if (pos < n) {
00615 for (ret = pos, p = _buf + pos; ; p--, ret--) {
00616
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
00652 if (pos >= n)
00653 pos = n - 1;
00654 if (pos < n) {
00655 for (ret = pos, p = _buf + pos; ; p--, ret--) {
00656
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++;
00787 if (n % 8 != 0)
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;
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 <rim() {
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
01254 str[ret] = CharTraits<charT>::nul;
01255
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
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
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;
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) {
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 }
01415
01416 #endif