Vault  4.1
vstring.cpp
Go to the documentation of this file.
00001 /*
00002 Copyright c1997-2014 Trygve Isaacson. All rights reserved.
00003 This file is part of the Code Vault version 4.1
00004 http://www.bombaydigital.com/
00005 License: MIT. See LICENSE.md in the Vault top level directory.
00006 */
00007 
00010 #include "vstring.h"
00011 #include "vtypes_internal.h"
00012 
00013 #include "vchar.h"
00014 #include "vcodepoint.h"
00015 #include "vexception.h"
00016 #include "vlogger.h"
00017 
00018 #ifndef V_EFFICIENT_SPRINTF
00019 #include "vmutex.h"
00020 #include "vmutexlocker.h"
00021 #endif /* V_EFFICIENT_SPRINTF */
00022 
00023 V_STATIC_INIT_TRACE
00024 
00025 #undef strlen
00026 #undef strcmp
00027 #undef sscanf
00028 
00029 // Is ASSERT_INVARIANT enabled/disabled specifically for VString?
00030 #ifdef V_ASSERT_INVARIANT_VSTRING_ENABLED
00031     #undef ASSERT_INVARIANT
00032     #if V_ASSERT_INVARIANT_VSTRING_ENABLED == 1
00033         #define ASSERT_INVARIANT() this->_assertInvariant() ///< Macro to call this->_assertInvariant().
00034     #else
00035         #define ASSERT_INVARIANT() ((void) 0) ///< No-op.
00036     #endif
00037 #endif
00038 
00039 /*
00040 The "empty string" constant constructs to an empty string.
00041 When you want to pass "" to a function that takes a "const VString&" parameter,
00042 it's much more efficient to pass the empty VString constant because it avoids
00043 constructing a temporary empty VString object on the fly.
00044 */
00045 // static
00046 const VString& VString::EMPTY() {
00047     static const VString kEmptyString;
00048     return kEmptyString;
00049 }
00050 
00051 // static
00052 const VString& VString::NATIVE_LINE_ENDING() {
00053 #ifdef VPLATFORM_WIN
00054     static const VString kLineEndingString(VSTRING_ARGS("%c%c", (char) 0x0D, (char) 0x0A));
00055 #else /* Unix and Mac OS X use Unix style */
00056     static const VString kLineEndingString((char) 0x0A);
00057 #endif /* VPLATFORM_WIN */
00058     return kLineEndingString;
00059 }
00060 
00061 // static
00062 const VString& VString::UNIX_LINE_ENDING() {
00063     static const VString kUnixLineEndingString((char) 0x0A);
00064     return kUnixLineEndingString;
00065 }
00066 
00067 // static
00068 const VString& VString::MAC_CLASSIC_LINE_ENDING() {
00069     static const VString kMacClassicLineEndingString((char) 0x0D);
00070     return kMacClassicLineEndingString;
00071 }
00072 
00073 // static
00074 const VString& VString::DOS_LINE_ENDING() {
00075     static const VString kDOSLineEndingString(VSTRING_ARGS("%c%c", (char) 0x0D, (char) 0x0A));
00076     return kDOSLineEndingString;
00077 }
00078 
00079 VString::VString()
00080     {
00081     this->_construct();
00082 
00083     ASSERT_INVARIANT();
00084 }
00085 
00086 VString::VString(const VChar& c)
00087     {
00088     this->_construct();
00089 
00090     this->preflight(1);
00091     _set()[0] = c.charValue();
00092     this->_setLength(1);
00093 
00094     ASSERT_INVARIANT();
00095 }
00096 
00097 VString::VString(const VString& s)
00098     {
00099     this->_construct();
00100 
00101     int theLength = s.length();
00102     if (theLength > 0) {
00103         this->preflight(theLength);
00104         s.copyToBuffer(_set(), theLength + 1);
00105         this->_setLength(theLength);
00106     }
00107 
00108     ASSERT_INVARIANT();
00109 }
00110 
00111 VString::VString(char c)
00112     {
00113     this->_construct();
00114 
00115     this->preflight(1);
00116     _set()[0] = c;
00117     this->_setLength(1);
00118 
00119     ASSERT_INVARIANT();
00120 }
00121 
00122 #ifdef VAULT_VSTRING_STRICT_FORMATTING
00123 VString::VString(const char* s)
00124 #else
00125 VString::VString(char* s)
00126 #endif /* VAULT_VSTRING_STRICT_FORMATTING */
00127     {
00128     this->_construct();
00129 
00130     if ((s != NULL) && (s[0] != VCHAR_NULL_TERMINATOR)) { // if s is NULL or zero length, leave as initialized to empty
00131         int    theLength = (int) ::strlen(s);
00132         this->preflight(theLength);
00133         ::memcpy(_set(), s, (VSizeType) (1 + theLength));    // faster than strcpy?
00134         this->_setLength(theLength);
00135     }
00136 
00137     ASSERT_INVARIANT();
00138 }
00139 
00140 #ifdef VAULT_VARARG_STRING_FORMATTING_SUPPORT
00141 
00142 #ifndef VAULT_VSTRING_STRICT_FORMATTING
00143 
00150 static int _getStrlenIfNonFormatting(const char* s) {
00151     if (s == NULL)
00152         return -1;
00153 
00154     int len = 0;
00155     while (s[len] != VCHAR_NULL_TERMINATOR) {
00156         if (s[len] == '%')
00157             return -1;
00158 
00159         ++len;
00160     }
00161 
00162     return len;
00163 }
00164 #endif /* VAULT_VSTRING_STRICT_FORMATTING */
00165 
00166 #ifdef VAULT_VSTRING_STRICT_FORMATTING
00167 VString::VString(Vs8 /*dummy*/, const char* formatText, ...)
00168 #else /* non-strict formatting */
00169 VString::VString(const char* formatText, ...)
00170 #endif /* VAULT_VSTRING_STRICT_FORMATTING */
00171     {
00172     this->_construct();
00173 
00174     if ((formatText != NULL) && (formatText[0] != VCHAR_NULL_TERMINATOR)) { // if formatText is NULL or zero length, leave as initialized to empty
00175 #ifndef VAULT_VSTRING_STRICT_FORMATTING
00176         // A common problem is constructing a string as "%", arriving that this constructor rather than the (char*) constructor.
00177         // It fails to format as desired. We can special case for this.
00178         if (formatText[0] == '%' && formatText[1] == VCHAR_NULL_TERMINATOR) {
00179             this->copyFromBuffer("%", 0, 1);
00180         } else
00181 #endif /* VAULT_VSTRING_STRICT_FORMATTING */
00182         {
00183 #ifndef VAULT_VSTRING_STRICT_FORMATTING
00184             // Scan for formatting directives. If none exist, avoid overhead of trying to format, and just copy.
00185             int nonFormattingLen = _getStrlenIfNonFormatting(formatText);
00186 #else
00187             int nonFormattingLen = -1; // not necessary if strict formatting in use
00188 #endif /* VAULT_VSTRING_STRICT_FORMATTING */
00189             if (nonFormattingLen == -1) {
00190                 va_list args;
00191                 va_start(args, formatText);
00192 
00193                 this->vaFormat(formatText, args);
00194 
00195                 va_end(args);
00196             } else {
00197                 this->copyFromBuffer(formatText, 0, nonFormattingLen);
00198             }
00199         }
00200     }
00201 
00202     ASSERT_INVARIANT();
00203 }
00204 #endif /* VAULT_VARARG_STRING_FORMATTING_SUPPORT */
00205 
00206 VString::VString(const std::wstring& ws) {
00207     this->_construct();
00208 
00209     this->_assignFromUTF16WideString(ws);
00210 
00211     ASSERT_INVARIANT();
00212 }
00213 
00214 #ifdef VAULT_QT_SUPPORT
00215 VString::VString(const QString& s)
00216     {
00217     this->_construct();
00218 
00219     this->copyFromBuffer(s.toUtf8(), 0, s.length());
00220 
00221     ASSERT_INVARIANT();
00222 }
00223 #endif /* VAULT_QT_SUPPORT */
00224 
00225 #ifdef VAULT_BOOST_STRING_FORMATTING_SUPPORT
00226 VString::VString(const boost::format& fmt)
00227     {
00228     this->_construct();
00229 
00230     this->copyFromBuffer(fmt.str().c_str(), 0, static_cast<int>(fmt.size()));
00231 
00232     ASSERT_INVARIANT();
00233 }
00234 #endif /* VAULT_BOOST_STRING_FORMATTING_SUPPORT */
00235 
00236 #ifdef VAULT_CORE_FOUNDATION_SUPPORT
00237 VString::VString(const CFStringRef& s)
00238     {
00239     this->_construct();
00240 
00241     this->_assignFromCFString(s);
00242 
00243     ASSERT_INVARIANT();
00244 }
00245 #endif /* VAULT_CORE_FOUNDATION_SUPPORT */
00246 
00247 VString::VString(const VCodePoint& cp)
00248     {
00249     this->_construct();
00250 
00251     (*this) += cp.toString();
00252 
00253     ASSERT_INVARIANT();
00254 }
00255 
00256 VString::~VString() {
00257     if (!mU.mI.mUsingInternalBuffer) {
00258         delete [] mU.mX.mHeapBufferPtr;
00259     }
00260 }
00261 
00262 VString& VString::operator=(const VString& s) {
00263     ASSERT_INVARIANT();
00264 
00265     if (this != &s) {
00266         int theLength = s.length();
00267 
00268         if (theLength != 0) {
00269             this->preflight(theLength);
00270             s.copyToBuffer(_set(), theLength + 1);
00271         }
00272 
00273         this->_setLength(theLength);
00274     }
00275 
00276     ASSERT_INVARIANT();
00277 
00278     return *this;
00279 }
00280 
00281 VString& VString::operator=(const VString* s) {
00282     ASSERT_INVARIANT();
00283 
00284     if (s == NULL) {
00285         this->_setLength(0);
00286     } else if (this != s) {
00287         int theLength = s->length();
00288 
00289         if (theLength != 0) {
00290             this->preflight(theLength);
00291             s->copyToBuffer(_set(), theLength + 1);
00292         }
00293 
00294         this->_setLength(theLength);
00295     }
00296 
00297     ASSERT_INVARIANT();
00298 
00299     return *this;
00300 }
00301 
00302 #ifdef VAULT_QT_SUPPORT
00303 VString& VString::operator=(const QString& s) {
00304     ASSERT_INVARIANT();
00305 
00306     this->copyFromBuffer(s.toUtf8(), 0, s.length());
00307 
00308     ASSERT_INVARIANT();
00309 
00310     return *this;
00311 }
00312 #endif /* VAULT_QT_SUPPORT */
00313 
00314 #ifdef VAULT_BOOST_STRING_FORMATTING_SUPPORT
00315 VString& VString::operator=(const boost::format& fmt) {
00316     ASSERT_INVARIANT();
00317 
00318     this->copyFromBuffer(fmt.str().c_str(), 0, static_cast<int>(fmt.size()));
00319 
00320     ASSERT_INVARIANT();
00321 
00322     return *this;
00323 }
00324 #endif /* VAULT_BOOST_STRING_FORMATTING_SUPPORT */
00325 
00326 #ifdef VAULT_CORE_FOUNDATION_SUPPORT
00327 VString& VString::operator=(const CFStringRef& s) {
00328     ASSERT_INVARIANT();
00329 
00330     this->_assignFromCFString(s);
00331 
00332     ASSERT_INVARIANT();
00333 
00334     return *this;
00335 }
00336 #endif /* VAULT_CORE_FOUNDATION_SUPPORT */
00337 
00338 VString& VString::operator=(const VCodePoint& cp) {
00339     ASSERT_INVARIANT();
00340 
00341     (*this) = cp.toString();
00342 
00343     ASSERT_INVARIANT();
00344 
00345     return *this;
00346 }
00347 
00348 VString& VString::operator=(const VChar& c) {
00349     ASSERT_INVARIANT();
00350 
00351     this->preflight(1);
00352     _set()[0] = c.charValue();
00353     this->_setLength(1);
00354 
00355     ASSERT_INVARIANT();
00356 
00357     return *this;
00358 }
00359 
00360 VString& VString::operator=(char c) {
00361     ASSERT_INVARIANT();
00362 
00363     this->preflight(1);
00364     _set()[0] = c;
00365     this->_setLength(1);
00366 
00367     ASSERT_INVARIANT();
00368 
00369     return *this;
00370 }
00371 
00372 VString& VString::operator=(const char* s) {
00373     ASSERT_INVARIANT();
00374 
00375     if (s == NULL) {
00376         this->_setLength(0);
00377     } else {
00378         int theLength = static_cast<int>(::strlen(s));
00379 
00380         if (theLength != 0) {
00381             this->preflight(theLength);
00382             ::memcpy(_set(), s, static_cast<VSizeType>(theLength)); // faster than strcpy?
00383         }
00384 
00385         this->_setLength(theLength);
00386     }
00387 
00388     ASSERT_INVARIANT();
00389 
00390     return *this;
00391 }
00392 
00393 VString& VString::operator=(const std::wstring& ws) {
00394     ASSERT_INVARIANT();
00395     
00396     this->_assignFromUTF16WideString(ws);
00397 
00398     ASSERT_INVARIANT();
00399 
00400     return *this;
00401 }
00402 
00403 VString& VString::operator=(int i) {
00404     ASSERT_INVARIANT();
00405 
00406     this->format(VSTRING_FORMATTER_INT, i);
00407 
00408     ASSERT_INVARIANT();
00409 
00410     return *this;
00411 }
00412 
00413 VString& VString::operator=(Vu8 i) {
00414     ASSERT_INVARIANT();
00415 
00416     this->format(VSTRING_FORMATTER_U8, (int) i);
00417 
00418     ASSERT_INVARIANT();
00419 
00420     return *this;
00421 }
00422 
00423 VString& VString::operator=(Vs8 i) {
00424     ASSERT_INVARIANT();
00425 
00426     this->format(VSTRING_FORMATTER_S8, (int) i);
00427 
00428     ASSERT_INVARIANT();
00429 
00430     return *this;
00431 }
00432 
00433 VString& VString::operator=(Vu16 i) {
00434     ASSERT_INVARIANT();
00435 
00436     this->format(VSTRING_FORMATTER_U16, i);
00437 
00438     ASSERT_INVARIANT();
00439 
00440     return *this;
00441 }
00442 
00443 VString& VString::operator=(Vs16 i) {
00444     ASSERT_INVARIANT();
00445 
00446     this->format(VSTRING_FORMATTER_S16, i);
00447 
00448     ASSERT_INVARIANT();
00449 
00450     return *this;
00451 }
00452 
00453 VString& VString::operator=(Vu32 i) {
00454     ASSERT_INVARIANT();
00455 
00456     this->format(VSTRING_FORMATTER_U32, i);
00457 
00458     ASSERT_INVARIANT();
00459 
00460     return *this;
00461 }
00462 
00463 #ifndef Vx32_IS_xINT /* don't redefine if types are same */
00464 VString& VString::operator=(Vs32 i) {
00465     ASSERT_INVARIANT();
00466 
00467     this->format(VSTRING_FORMATTER_S32, i);
00468 
00469     ASSERT_INVARIANT();
00470 
00471     return *this;
00472 }
00473 #endif /* not Vx32_IS_xINT */
00474 
00475 VString& VString::operator=(Vu64 i) {
00476     ASSERT_INVARIANT();
00477 
00478     this->format(VSTRING_FORMATTER_U64, i);
00479 
00480     ASSERT_INVARIANT();
00481 
00482     return *this;
00483 }
00484 
00485 #ifndef Vx64_IS_xINT /* don't redefine if types are same */
00486 VString& VString::operator=(Vs64 i) {
00487     ASSERT_INVARIANT();
00488 
00489     this->format(VSTRING_FORMATTER_S64, i);
00490 
00491     ASSERT_INVARIANT();
00492 
00493     return *this;
00494 }
00495 #endif /* not Vx64_IS_xINT */
00496 
00497 VString& VString::operator=(VDouble f) {
00498     ASSERT_INVARIANT();
00499 
00500     this->format(VSTRING_FORMATTER_DOUBLE, f);
00501 
00502     ASSERT_INVARIANT();
00503 
00504     return *this;
00505 }
00506 
00507 VString VString::operator+(const char c) const {
00508     VString newString(VSTRING_ARGS("%s%c", this->chars(), c));
00509     return newString;
00510 }
00511 
00512 VString VString::operator+(const char* s) const {
00513     VString newString(VSTRING_ARGS("%s%s", this->chars(), s));
00514     return newString;
00515 }
00516 
00517 VString VString::operator+(const std::wstring& ws) const {
00518     VString newString(*this);
00519     newString += VString(ws);
00520     return newString;
00521 }
00522 
00523 VString VString::operator+(const VString& s) const {
00524     VString newString(VSTRING_ARGS("%s%s", this->chars(), s.chars()));
00525     return newString;
00526 }
00527 
00528 #ifdef VAULT_BOOST_STRING_FORMATTING_SUPPORT
00529 VString VString::operator+(const boost::format& fmt) const {
00530     VString newString(*this);
00531     newString += fmt;
00532     return newString;
00533 }
00534 #endif /* VAULT_BOOST_STRING_FORMATTING_SUPPORT */
00535 
00536 VString VString::operator+(const VCodePoint& cp) const {
00537     VString newString(*this);
00538     newString += cp.toString();
00539     return newString;
00540 }
00541 
00542 VString& VString::operator+=(const VChar& c) {
00543     ASSERT_INVARIANT();
00544 
00545     this->preflight(1 + mU.mI.mStringLength);
00546     _set()[mU.mI.mStringLength] = c.charValue();
00547     this->_setLength(1 + mU.mI.mStringLength);
00548 
00549     ASSERT_INVARIANT();
00550 
00551     return *this;
00552 }
00553 
00554 VString& VString::operator+=(const VString& s) {
00555     ASSERT_INVARIANT();
00556 
00557     // We have to be careful copying the buffer if &s==this
00558     // because things morph under us as we work in that case.
00559 
00560     int theLength = s.length();
00561 
00562     this->preflight(theLength + mU.mI.mStringLength);
00563     ::memcpy(&(_set()[mU.mI.mStringLength]), s.chars(), static_cast<VSizeType>(theLength));
00564     this->_setLength(theLength + mU.mI.mStringLength);
00565 
00566     ASSERT_INVARIANT();
00567 
00568     return *this;
00569 }
00570 
00571 VString& VString::operator+=(char c) {
00572     ASSERT_INVARIANT();
00573 
00574     this->preflight(1 + mU.mI.mStringLength);
00575     _set()[mU.mI.mStringLength] = c;
00576     this->_setLength(1 + mU.mI.mStringLength);
00577 
00578     ASSERT_INVARIANT();
00579 
00580     return *this;
00581 }
00582 
00583 VString& VString::operator+=(const char* s) {
00584     ASSERT_INVARIANT();
00585 
00586     int theLength = (int) ::strlen(s);
00587 
00588     this->preflight(theLength + mU.mI.mStringLength);
00589     ::memcpy(&(_set()[mU.mI.mStringLength]), s, static_cast<VSizeType>(theLength));
00590     this->_setLength(theLength + mU.mI.mStringLength);
00591 
00592     ASSERT_INVARIANT();
00593 
00594     return *this;
00595 }
00596 
00597 VString& VString::operator+=(const std::wstring& ws) {
00598     VString appendage(ws);
00599     (*this) += appendage;
00600 
00601     return *this;
00602 }
00603 
00604 #ifdef VAULT_BOOST_STRING_FORMATTING_SUPPORT
00605 VString& VString::operator+=(const boost::format& fmt) {
00606     ASSERT_INVARIANT();
00607 
00608     int theLength = (int) fmt.size();
00609 
00610     this->preflight(theLength + mU.mI.mStringLength);
00611     ::memcpy(&(_set()[mU.mI.mStringLength]), fmt.str().c_str(), static_cast<VSizeType>(theLength));
00612     this->_setLength(theLength + mU.mI.mStringLength);
00613 
00614     ASSERT_INVARIANT();
00615 
00616     return *this;
00617 }
00618 #endif /* VAULT_BOOST_STRING_FORMATTING_SUPPORT */
00619 
00620 VString& VString::operator+=(const VCodePoint& cp) {
00621     ASSERT_INVARIANT();
00622 
00623     VString appendage = cp.toString();
00624     (*this) += appendage;
00625 
00626     ASSERT_INVARIANT();
00627 
00628     return *this;
00629 }
00630 
00631 VString& VString::operator+=(int i) {
00632     ASSERT_INVARIANT();
00633 
00634     *this += VSTRING_INT(i);
00635 
00636     ASSERT_INVARIANT();
00637 
00638     return *this;
00639 }
00640 
00641 VString& VString::operator+=(Vu8 i) {
00642     ASSERT_INVARIANT();
00643 
00644     *this += VSTRING_U8((int) i); // int case req'd for some compilers
00645 
00646     ASSERT_INVARIANT();
00647 
00648     return *this;
00649 }
00650 
00651 VString& VString::operator+=(Vs8 i) {
00652     ASSERT_INVARIANT();
00653 
00654     *this += VSTRING_S8((int) i); // int case req'd for some compilers
00655 
00656     ASSERT_INVARIANT();
00657 
00658     return *this;
00659 }
00660 
00661 VString& VString::operator+=(Vu16 i) {
00662     ASSERT_INVARIANT();
00663 
00664     *this += VSTRING_U16(i);
00665 
00666     ASSERT_INVARIANT();
00667 
00668     return *this;
00669 }
00670 
00671 VString& VString::operator+=(Vs16 i) {
00672     ASSERT_INVARIANT();
00673 
00674     *this += VSTRING_S16(i);
00675 
00676     ASSERT_INVARIANT();
00677 
00678     return *this;
00679 }
00680 
00681 VString& VString::operator+=(Vu32 i) {
00682     ASSERT_INVARIANT();
00683 
00684     *this += VSTRING_U32(i);
00685 
00686     ASSERT_INVARIANT();
00687 
00688     return *this;
00689 }
00690 
00691 #ifndef Vx32_IS_xINT /* don't redefine if types are same */
00692 VString& VString::operator+=(Vs32 i) {
00693     ASSERT_INVARIANT();
00694 
00695     *this += VSTRING_S32(i);
00696 
00697     ASSERT_INVARIANT();
00698 
00699     return *this;
00700 }
00701 #endif /* not Vx32_IS_xINT */
00702 
00703 VString& VString::operator+=(Vu64 i) {
00704     ASSERT_INVARIANT();
00705 
00706     *this += VSTRING_U64(i);
00707 
00708     ASSERT_INVARIANT();
00709 
00710     return *this;
00711 }
00712 
00713 #ifndef Vx64_IS_xINT /* don't redefine if types are same */
00714 VString& VString::operator+=(Vs64 i) {
00715     ASSERT_INVARIANT();
00716 
00717     *this += VSTRING_S64(i);
00718 
00719     ASSERT_INVARIANT();
00720 
00721     return *this;
00722 }
00723 #endif /* not Vx64_IS_xINT */
00724 
00725 VString& VString::operator+=(VDouble d) {
00726     ASSERT_INVARIANT();
00727 
00728     *this += VSTRING_DOUBLE(d);
00729 
00730     ASSERT_INVARIANT();
00731 
00732     return *this;
00733 }
00734 
00735 void VString::readFromIStream(std::istream& in) {
00736     ASSERT_INVARIANT();
00737 
00738     *this = VString::EMPTY();
00739 
00740     this->appendFromIStream(in);
00741 
00742     ASSERT_INVARIANT();
00743 }
00744 
00745 void VString::appendFromIStream(std::istream& in) {
00746     ASSERT_INVARIANT();
00747 
00748     char c;
00749 
00750     in >> c;
00751 
00752     while (c != '\0') {
00753         // Because preflight() expands the buffer in chunks, we no longer need the code that was here
00754         // that conditionally called preflight() in chunks, intending to avoid repeated single-character
00755         // buffer expansion & reallocation in this loop.
00756 
00757         *this += c;
00758 
00759         in >> c;
00760     }
00761 
00762     ASSERT_INVARIANT();
00763 }
00764 
00765 VString::iterator VString::begin() {
00766     ASSERT_INVARIANT();
00767     
00768     VString::iterator result(*this, true/*is forward iterator*/);
00769     
00770     ASSERT_INVARIANT();
00771 
00772     return result;
00773 }
00774 
00775 VString::const_iterator VString::begin() const {
00776     ASSERT_INVARIANT();
00777     
00778     return VString::const_iterator(*this, true/*isForwardIterator*/);
00779 }
00780 
00781 VString::iterator VString::end() {
00782     ASSERT_INVARIANT();
00783     
00784     VString::iterator result(*this, true/*isForwardIterator*/, true/*goToEnd*/);
00785     
00786     ASSERT_INVARIANT();
00787 
00788     return result;
00789 }
00790 
00791 VString::const_iterator VString::end() const {
00792     ASSERT_INVARIANT();
00793     
00794     return VString::const_iterator(*this, true/*isForwardIterator*/, true/*goToEnd*/);
00795 }
00796 
00797 VString::iterator VString::rbegin() {
00798     ASSERT_INVARIANT();
00799     
00800     VString::iterator result(*this, false/*not isForwardIterator*/);
00801     
00802     ASSERT_INVARIANT();
00803 
00804     return result;
00805 }
00806 
00807 VString::const_iterator VString::rbegin() const {
00808     ASSERT_INVARIANT();
00809     
00810     return VString::const_iterator(*this, false/*not isForwardIterator*/);
00811 }
00812 
00813 VString::iterator VString::rend() {
00814     ASSERT_INVARIANT();
00815     
00816     VString::iterator result(*this, false/*not isForwardIterator*/, true/*goToEnd*/);
00817     
00818     ASSERT_INVARIANT();
00819 
00820     return result;
00821 }
00822 
00823 VString::const_iterator VString::rend() const {
00824     ASSERT_INVARIANT();
00825     
00826     return VString::const_iterator(*this, false/*not isForwardIterator*/, true/*goToEnd*/);
00827 }
00828 
00829 #ifdef VAULT_VARARG_STRING_FORMATTING_SUPPORT
00830 void VString::format(const char* formatText, ...) {
00831     ASSERT_INVARIANT();
00832 
00833     va_list args;
00834     va_start(args, formatText);
00835 
00836     this->vaFormat(formatText, args);
00837 
00838     va_end(args);
00839 
00840     ASSERT_INVARIANT();
00841 }
00842 #endif /* VAULT_VARARG_STRING_FORMATTING_SUPPORT */
00843 
00844 void VString::insert(const VCodePoint& cp, const VString::iterator& position) {
00845     this->insert(cp, position.getCurrentOffset());
00846 }
00847 
00848 void VString::insert(const VString& s, const VString::iterator& position) {
00849     this->insert(s, position.getCurrentOffset());
00850 }
00851 
00852 void VString::insert(char c, const VString::iterator& position) {
00853     this->insert(c, position.getCurrentOffset());
00854 }
00855 
00856 void VString::insert(const VCodePoint& cp, int offset) {
00857     this->insert(VString(cp), offset);
00858 }
00859 
00860 void VString::insert(const VString& s, int offset) {
00861     ASSERT_INVARIANT();
00862 
00863     if (s.length() == 0) { // optimize the nothing-to-do case
00864         return;
00865     }
00866 
00867     // If s happens to be 'this', we'll need a temporary copy of it.
00868     // Otherwise, our memmove() + memcpy() data would be messed up.
00869     VString    tempCopy;    // note that by just declaring this, we merely have a few bytes on the stack -- nothing on the heap yet
00870     const char* source = s.chars();
00871 
00872     if (this == &s) {
00873         tempCopy = s;    // this will cause tempCopy to allocate a buffer to hold a copy of s (which is 'this')
00874         source = tempCopy.chars();    // we'll do our final memcpy() from the copy, not from the 'this' buffer that's split by the memmove()
00875     }
00876 
00877     int addedLength = s.length();
00878     int oldLength = this->length();
00879     int newLength = oldLength + addedLength;
00880 
00881     // constrain to guard against bad offset; perhaps an out-of-bounds exception would be better?
00882     int actualOffset = V_MIN(oldLength, V_MAX(0, offset));
00883     int numBytesToMove = oldLength - actualOffset;
00884 
00885     this->preflight(newLength);
00886 
00887     // Need to use memmove here because memcpy behavior is undefined if ranges overlap.
00888     ::memmove(&(_set()[actualOffset+addedLength]), &(_get()[actualOffset]), numBytesToMove);    // shift forward by s.length() byte, everything past the offset
00889     ::memcpy(&(_set()[actualOffset]), source, addedLength);
00890 
00891     this->postflight(newLength);
00892 
00893     ASSERT_INVARIANT();
00894 }
00895 
00896 void VString::insert(char c, int offset) {
00897     ASSERT_INVARIANT();
00898 
00899     // We could make a VString of c, and then insert it, but it seems
00900     // much more efficient to move a single char by itself.
00901 
00902     int addedLength = 1;
00903     int oldLength = this->length();
00904     int newLength = oldLength + addedLength;
00905 
00906     // constrain to guard against bad offset; perhaps an out-of-bounds exception would be better?
00907     int actualOffset = V_MIN(oldLength, V_MAX(0, offset));
00908     int numBytesToMove = oldLength - actualOffset;
00909 
00910     this->preflight(newLength);
00911 
00912     // Need to use memmove here because memcpy behavior is undefined if ranges overlap.
00913     ::memmove(&(_set()[actualOffset+addedLength]), &(_get()[actualOffset]), numBytesToMove);    // shift forward by 1 byte, everything past the offset
00914     _set()[actualOffset] = c;
00915 
00916     this->postflight(newLength);
00917 
00918     ASSERT_INVARIANT();
00919 }
00920 
00921 int VString::getNumCodePoints() const {
00922     ASSERT_INVARIANT();
00923 
00924     if (mU.mI.mNumCodePoints == -1) {
00925         this->_determineNumCodePoints();
00926     }
00927     
00928     return mU.mI.mNumCodePoints;
00929 }
00930 
00931 int VString::length() const {
00932     ASSERT_INVARIANT();
00933 
00934     return mU.mI.mStringLength;
00935 }
00936 
00937 void VString::truncateCodePoints(int maxNumCodePoints) {
00938     ASSERT_INVARIANT();
00939 
00940     if ((maxNumCodePoints >= 0) && (this->getNumCodePoints() > maxNumCodePoints)) {
00941         VString::iterator pos(this->begin() + maxNumCodePoints);
00942         this->_setLength(pos.getCurrentOffset());
00943     }
00944 
00945     ASSERT_INVARIANT();
00946 }
00947 
00948 void VString::truncateLength(int maxLength) {
00949     ASSERT_INVARIANT();
00950 
00951     if ((maxLength >= 0) && (this->length() > maxLength)) {
00952         this->_setLength(maxLength);
00953     }
00954 
00955     ASSERT_INVARIANT();
00956 }
00957 
00958 bool VString::isEmpty() const {
00959     ASSERT_INVARIANT();
00960 
00961     return mU.mI.mStringLength == 0;
00962 }
00963 
00964 bool VString::isNotEmpty() const {
00965     ASSERT_INVARIANT();
00966 
00967     return mU.mI.mStringLength != 0;
00968 }
00969 
00970 VChar VString::at(int i) const {
00971     ASSERT_INVARIANT();
00972 
00973     if (i > mU.mI.mStringLength) {
00974         throw VRangeException(VSTRING_FORMAT("VString::at(%d) index out of range for length %d.", i, mU.mI.mStringLength));
00975     } else if (i == 0 && mU.mI.mStringLength == 0) {
00976         return VChar::NULL_CHAR();
00977     }
00978 
00979     return VChar(_get()[i]);
00980 }
00981 
00982 VChar VString::operator[](int i) const {
00983     ASSERT_INVARIANT();
00984 
00985     if (i > mU.mI.mStringLength) {
00986         throw VRangeException(VSTRING_FORMAT("VString::operator[%d] index out of range for length %d.", i, mU.mI.mStringLength));
00987     } else if (i == 0 && mU.mI.mStringLength == 0) {
00988         return VChar::NULL_CHAR();
00989     }
00990 
00991     return VChar(_get()[i]);
00992 }
00993 
00994 char& VString::operator[](int i) {
00995     ASSERT_INVARIANT();
00996 
00997     if (i >= mU.mI.mStringLength) {
00998         throw VRangeException(VSTRING_FORMAT("VString::operator[%d] index out of range for length %d.", i, mU.mI.mStringLength));
00999     }
01000 
01001     return _set()[i];
01002 }
01003 
01004 char VString::charAt(int i) const {
01005     ASSERT_INVARIANT();
01006 
01007     if (i > mU.mI.mStringLength) {
01008         throw VRangeException(VSTRING_FORMAT("VString::charAt(%d) index out of range for length %d.", i, mU.mI.mStringLength));
01009     } else if (i == 0 && mU.mI.mStringLength == 0) {
01010         return (char) 0;
01011     }
01012 
01013     return _get()[i];
01014 }
01015 
01016 VString::operator const char*() const {
01017     ASSERT_INVARIANT();
01018     
01019     return _get();
01020 }
01021 
01022 const char* VString::chars() const {
01023     ASSERT_INVARIANT();
01024 
01025     return _get();
01026 }
01027 
01028 std::wstring VString::toUTF16() const {
01029     ASSERT_INVARIANT();
01030     
01031     std::wstring utf16WideString;
01032     
01033     for (VString::const_iterator i = this->begin(); i != this->end(); ++i) {
01034         VCodePoint cp = (*i);
01035         utf16WideString += cp.toUTF16WideString();
01036     }
01037     
01038     return utf16WideString;
01039 }
01040 
01041 #ifdef VAULT_QT_SUPPORT
01042 QString VString::qstring() const {
01043     ASSERT_INVARIANT();
01044 
01045     return QString::fromUtf8(this->chars(), this->length());
01046 }
01047 #endif /* VAULT_QT_SUPPORT */
01048 
01049 #ifdef VAULT_CORE_FOUNDATION_SUPPORT
01050 CFStringRef VString::cfstring() const {
01051     ASSERT_INVARIANT();
01052 
01053     return CFStringCreateWithCString(NULL, this->chars(), kCFStringEncodingUTF8);
01054 }
01055 #endif /* VAULT_CORE_FOUNDATION_SUPPORT */
01056 
01057 bool VString::equalsIgnoreCase(const VString& s) const {
01058     ASSERT_INVARIANT();
01059 
01060     return this->equalsIgnoreCase(s.chars());
01061 }
01062 
01063 bool VString::equalsIgnoreCase(const char* s) const {
01064     ASSERT_INVARIANT();
01065 
01066     return this->compareIgnoreCase(s) == 0;
01067 }
01068 
01069 int VString::compare(const VString& s) const {
01070     ASSERT_INVARIANT();
01071 
01072     return this->compare(s.chars());
01073 }
01074 
01075 int VString::compare(const char* s) const {
01076     ASSERT_INVARIANT();
01077 
01078     return ::strcmp(_get(), s);
01079 }
01080 
01081 int VString::compareIgnoreCase(const VString& s) const {
01082     ASSERT_INVARIANT();
01083 
01084     return this->compareIgnoreCase(s.chars());
01085 }
01086 
01087 int VString::compareIgnoreCase(const char* s) const {
01088     ASSERT_INVARIANT();
01089 
01090     return vault::strcasecmp(_get(), s);
01091 }
01092 
01093 bool VString::startsWith(const VString& s) const {
01094     ASSERT_INVARIANT();
01095 
01096     return this->regionMatches(0, s, 0, s.length());
01097 }
01098 
01099 bool VString::startsWithIgnoreCase(const VString& s) const {
01100     ASSERT_INVARIANT();
01101 
01102     return this->regionMatches(0, s, 0, s.length(), /* caseSensitive = */ false);
01103 }
01104 
01105 bool VString::startsWith(const VCodePoint& cp) const {
01106     ASSERT_INVARIANT();
01107 
01108     if (mU.mI.mStringLength < cp.getUTF8Length()) {
01109         return false;
01110     } else {
01111         return (VCodePoint(this->getDataBufferConst(), 0) == cp);
01112     }
01113 }
01114 
01115 bool VString::startsWith(char aChar) const {
01116     ASSERT_INVARIANT();
01117 
01118     if (mU.mI.mStringLength == 0) {
01119         return false;
01120     } else {
01121         return (_get()[0] == aChar);
01122     }
01123 }
01124 
01125 bool VString::endsWith(const VString& s) const {
01126     ASSERT_INVARIANT();
01127 
01128     return this->regionMatches(mU.mI.mStringLength - s.length(), s, 0, s.length());
01129 }
01130 
01131 bool VString::endsWithIgnoreCase(const VString& s) const {
01132     ASSERT_INVARIANT();
01133 
01134     return this->regionMatches(mU.mI.mStringLength - s.length(), s, 0, s.length(), /* caseSensitive = */ false);
01135 }
01136 
01137 bool VString::endsWith(const VCodePoint& cp) const {
01138     ASSERT_INVARIANT();
01139 
01140     if (mU.mI.mStringLength < cp.getUTF8Length()) {
01141         return false;
01142     } else {
01143         VString::const_reverse_iterator ri = this->rbegin();
01144         return (*ri == cp);
01145     }
01146 }
01147 
01148 bool VString::endsWith(char aChar) const {
01149     ASSERT_INVARIANT();
01150 
01151     if (mU.mI.mStringLength == 0) {
01152         return false;
01153     } else {
01154         return (_get()[mU.mI.mStringLength - 1] == aChar);
01155     }
01156 }
01157 
01158 VString::const_iterator VString::find(const VCodePoint& cp) const {
01159     ASSERT_INVARIANT();
01160 
01161     return this->find(cp, this->begin(), this->end());
01162 }
01163 
01164 VString::iterator VString::find(const VCodePoint& cp) {
01165     ASSERT_INVARIANT();
01166 
01167     VString::iterator pos = this->find(cp, this->begin(), this->end());
01168 
01169     ASSERT_INVARIANT();
01170     
01171     return pos;
01172 }
01173 
01174 VString::const_iterator VString::find(const VCodePoint& cp, const VString::const_iterator& startPosition, const VString::const_iterator& endPosition) const {
01175     ASSERT_INVARIANT();
01176 
01177     for (VString::const_iterator pos = startPosition; pos != endPosition; ++pos) {
01178         if (*pos == cp) {
01179             return pos;
01180         }
01181     }
01182     
01183     return this->end();
01184 }
01185 
01186 VString::iterator VString::find(const VCodePoint& cp, const VString::iterator& startPosition, const VString::iterator& endPosition) {
01187     ASSERT_INVARIANT();
01188 
01189     for (VString::iterator pos = startPosition; pos != endPosition; ++pos) {
01190         if (*pos == cp) {
01191             return pos;
01192         }
01193     }
01194     
01195     return this->end();
01196 }
01197 
01198 int VString::indexOf(char c, int fromIndex) const {
01199     ASSERT_INVARIANT();
01200 
01201     if ((fromIndex >= 0) && (fromIndex < mU.mI.mStringLength)) {
01202         const char* buf = _get();
01203         for (int i = fromIndex; i < mU.mI.mStringLength; ++i) {
01204             if (buf[i] == c) {
01205                 return i;
01206             }
01207         }
01208     }
01209 
01210     return -1;
01211 }
01212 
01213 int VString::indexOfIgnoreCase(char c, int fromIndex) const {
01214     ASSERT_INVARIANT();
01215 
01216     if ((fromIndex >= 0) && (fromIndex < mU.mI.mStringLength)) {
01217         const char* buf = _get();
01218         for (int i = fromIndex; i < mU.mI.mStringLength; ++i) {
01219             if (VChar::equalsIgnoreCase(buf[i], c)) {
01220                 return i;
01221             }
01222         }
01223     }
01224 
01225     return -1;
01226 }
01227 
01228 int VString::indexOf(const VString& s, int fromIndex) const {
01229     ASSERT_INVARIANT();
01230 
01231     if (fromIndex < 0)
01232         return -1;
01233 
01234     int otherLength = s.length();
01235 
01236     for (int i = fromIndex; i < mU.mI.mStringLength; ++i) {
01237         if (this->regionMatches(i, s, 0, otherLength)) {
01238             return i;
01239         }
01240     }
01241 
01242     return -1;
01243 }
01244 
01245 int VString::indexOfIgnoreCase(const VString& s, int fromIndex) const {
01246     ASSERT_INVARIANT();
01247 
01248     if (fromIndex < 0) {
01249         return -1;
01250     }
01251 
01252     int otherLength = s.length();
01253 
01254     for (int i = fromIndex; i < mU.mI.mStringLength; ++i) {
01255         if (this->regionMatches(i, s, 0, otherLength, /* caseSensitive = */ false)) {
01256             return i;
01257         }
01258     }
01259 
01260     return -1;
01261 }
01262 
01263 int VString::lastIndexOf(char c, int fromIndex) const {
01264     ASSERT_INVARIANT();
01265 
01266     if (fromIndex == -1) {
01267         fromIndex = mU.mI.mStringLength - 1;
01268     }
01269 
01270     const char* buf = _get();
01271     for (int i = fromIndex; i >= 0; --i) {
01272         if (buf[i] == c) {
01273             return i;
01274         }
01275     }
01276 
01277     return -1;
01278 }
01279 
01280 int VString::lastIndexOfIgnoreCase(char c, int fromIndex) const {
01281     ASSERT_INVARIANT();
01282 
01283     if (fromIndex == -1) {
01284         fromIndex = mU.mI.mStringLength - 1;
01285     }
01286 
01287     const char* buf = _get();
01288     for (int i = fromIndex; i >= 0; --i) {
01289         if (VChar::equalsIgnoreCase(buf[i], c)) {
01290             return i;
01291         }
01292     }
01293 
01294     return -1;
01295 }
01296 
01297 int VString::lastIndexOf(const VString& s, int fromIndex) const {
01298     ASSERT_INVARIANT();
01299 
01300     int otherLength = s.length();
01301 
01302     if (fromIndex == -1) {
01303         fromIndex = mU.mI.mStringLength;
01304     }
01305 
01306     for (int i = fromIndex; i >= 0; --i) {
01307         if (this->regionMatches(i, s, 0, otherLength)) {
01308             return i;
01309         }
01310     }
01311 
01312     return -1;
01313 }
01314 
01315 int VString::lastIndexOfIgnoreCase(const VString& s, int fromIndex) const {
01316     ASSERT_INVARIANT();
01317 
01318     int otherLength = s.length();
01319 
01320     if (fromIndex == -1) {
01321         fromIndex = mU.mI.mStringLength;
01322     }
01323 
01324     for (int i = fromIndex; i >= 0; --i) {
01325         if (this->regionMatches(i, s, 0, otherLength, /* caseSensitive = */ false)) {
01326             return i;
01327         }
01328     }
01329 
01330     return -1;
01331 }
01332 
01333 bool VString::regionMatches(int thisOffset, const VString& otherString, int otherOffset, int regionLength, bool caseSensitive) const {
01334     ASSERT_INVARIANT();
01335 
01336     int result;
01337     int otherStringLength = otherString.length();
01338 
01339     // Buffer offset safety checks first. If they fail, return false.
01340     if ((thisOffset < 0) ||
01341             (thisOffset >= mU.mI.mStringLength) ||
01342             (thisOffset + regionLength > mU.mI.mStringLength) ||
01343             (otherOffset < 0) ||
01344             (otherOffset >= otherStringLength) ||
01345             (otherOffset + regionLength > otherStringLength)) {
01346         return false;
01347     }
01348 
01349     if (caseSensitive) {
01350         result = ::strncmp(this->chars() + thisOffset, otherString.chars() + otherOffset, static_cast<VSizeType>(regionLength));
01351     } else {
01352         result = vault::strncasecmp(this->chars() + thisOffset, otherString.chars() + otherOffset, static_cast<VSizeType>(regionLength));
01353     }
01354 
01355     return (result == 0);
01356 }
01357 
01358 bool VString::contains(char c, int fromIndex) const {
01359     ASSERT_INVARIANT();
01360 
01361     return this->indexOf(c, fromIndex) != -1;
01362 }
01363 
01364 bool VString::containsIgnoreCase(char c, int fromIndex) const {
01365     ASSERT_INVARIANT();
01366 
01367     return this->indexOfIgnoreCase(c, fromIndex) != -1;
01368 }
01369 
01370 bool VString::contains(const VString& s, int fromIndex) const {
01371     ASSERT_INVARIANT();
01372 
01373     return this->indexOf(s, fromIndex) != -1;
01374 }
01375 
01376 bool VString::containsIgnoreCase(const VString& s, int fromIndex) const {
01377     ASSERT_INVARIANT();
01378 
01379     return this->indexOfIgnoreCase(s, fromIndex) != -1;
01380 }
01381 
01382 int VString::replace(const VString& searchString, const VString& replacementString, bool caseSensitiveSearch) {
01383     ASSERT_INVARIANT();
01384 
01385     int searchLength = searchString.length();
01386 
01387     if (searchLength == 0) {
01388         return 0;
01389     }
01390 
01391     int replacementLength = replacementString.length();
01392     int numReplacements = 0;
01393     int currentOffset = caseSensitiveSearch ? this->indexOf(searchString) : this->indexOfIgnoreCase(searchString);
01394 
01395     while ((currentOffset != -1) && (mU.mI.mStringLength != 0)) {
01396         /*
01397         The optimization trick here is that we can place a zero byte to artificially
01398         terminate the C string buffer at the found index, creating the BEFORE part
01399         as a C string. The AFTER part remains intact. And we've been supplied the
01400         MIDDLE part. We simply format these 3 pieces together to form the new
01401         string, and then reassign it back to ourself. This relieves us of having
01402         to create multiple temporary buffers; we only create 1 temporary buffer as
01403         a result of using a VString to format into.
01404 
01405         We could further optimize by
01406         combining ourself with 3 memcpy calls instead of letting vsnprintf calculate
01407         the buffer length:
01408         char* buffer = new char[this->length() + replacementLength - searchLength + 1];
01409         1. memcpy from mBuffer[0] to buffer[0] length=currentOffset
01410         2. memcpy from mBuffer[currentOffset + searchLength] to buffer[currentOffset + replacementLength] length=(this->length() - currentOffset + searchLength)
01411         3. memcpy from replacementString.mBuffer to buffer[currentOffset] length=replacementLength
01412         4. null terminate the buffer: buffer[length of buffer] = 0
01413         (order of 1, 2, 3 is important for correct copying w/o incorrect overwriting)
01414         (something like that off the top of my head)
01415 
01416         And, if replacementLength <= searchLength we could just update in place.
01417 
01418         FIXME: On second thought, this in-place replacement is dangerous IF we run out of memory
01419         because we've broken the invariants. The problem is that we irrevocably alter our data
01420         before we're guaranteed we'll succeed. This is very unlikely to actually happen, but it's possible.
01421         */
01422 
01423         char* buf = _set();
01424         buf[currentOffset] = 0;    // terminate the C string buffer to create the BEFORE part
01425         char*   beforePart = buf;
01426         char*   afterPart = &buf[currentOffset + searchLength];
01427         VString alteredString(VSTRING_ARGS("%s%s%s", beforePart, replacementString.chars(), afterPart));
01428 
01429         // Assign the new string to ourself -- copies its buffer into ours correctly.
01430         // (Could be optimized to just swap buffers if we defined a new friend function or two.)
01431         *this = alteredString;
01432 
01433         // Finally we have to move currentOffset forward past the replacement part.
01434         currentOffset += replacementLength;
01435 
01436         ++numReplacements;
01437 
01438         // See if there is another occurrence to replace.
01439         currentOffset = caseSensitiveSearch ? this->indexOf(searchString, currentOffset) : this->indexOfIgnoreCase(searchString, currentOffset);
01440     }
01441 
01442     ASSERT_INVARIANT();
01443 
01444     return numReplacements;
01445 }
01446 
01447 int VString::replace(const VCodePoint& searchChar, const VCodePoint& replacementChar, bool caseSensitiveSearch) {
01448     ASSERT_INVARIANT();
01449     
01450     int numReplacements = this->replace(searchChar.toString(), replacementChar.toString(), caseSensitiveSearch);
01451 
01452     ASSERT_INVARIANT();
01453 
01454     return numReplacements;
01455 }
01456 
01457 void VString::toLowerCase() {
01458     ASSERT_INVARIANT();
01459 
01460     char* buf = _set();
01461     for (int i = 0; i < mU.mI.mStringLength; ++i) {
01462         buf[i] = static_cast<char>(::tolower(buf[i]));
01463     }
01464 
01465     ASSERT_INVARIANT();
01466 }
01467 
01468 void VString::toUpperCase() {
01469     ASSERT_INVARIANT();
01470 
01471     char* buf = _set();
01472     for (int i = 0; i < mU.mI.mStringLength; ++i) {
01473         buf[i] = static_cast<char>(::toupper(buf[i]));
01474     }
01475 
01476     ASSERT_INVARIANT();
01477 }
01478 
01479 int VString::parseInt() const {
01480     ASSERT_INVARIANT();
01481 
01482     Vs64 result = this->_parseSignedInteger();
01483     Vs64 maxValue = V_MAX_S32;
01484     Vs64 minValue = V_MIN_S32;
01485 
01486     if (sizeof(int) == 1) {
01487         maxValue = V_MAX_S8;
01488         minValue = V_MIN_S8;
01489     } else if (sizeof(int) == 2) {
01490         maxValue = V_MAX_S16;
01491         minValue = V_MIN_S16;
01492     } else if (sizeof(int) == 8) {
01493         maxValue = V_MAX_S64;
01494         minValue = V_MIN_S64;
01495     }
01496 
01497     if ((result < minValue) || (result > maxValue)) {
01498         throw VRangeException(VSTRING_FORMAT("VString::parseInt %s value is out of range.", _get()));
01499     }
01500 
01501     return static_cast<int>(result);
01502 }
01503 
01504 Vs64 VString::parseS64() const {
01505     ASSERT_INVARIANT();
01506 
01507     Vs64 result = this->_parseSignedInteger();
01508 
01509     return result;
01510 }
01511 
01512 Vu64 VString::parseU64() const {
01513     ASSERT_INVARIANT();
01514 
01515     Vu64 result = this->_parseUnsignedInteger();
01516 
01517     return result;
01518 }
01519 
01520 VDouble VString::parseDouble() const {
01521     ASSERT_INVARIANT();
01522 
01523     if (mU.mI.mStringLength == 0) {
01524         return 0.0;
01525     }
01526 
01527     VDouble result;
01528     int n = ::sscanf(_get(), VSTRING_FORMATTER_DOUBLE, &result);
01529     if (n == 0) {
01530         throw VRangeException(VSTRING_FORMAT("VString::parseDouble '%s' is invalid format.", _get()));
01531     }
01532 
01533     return result;
01534 }
01535 
01536 void VString::set(int i, const VChar& c) {
01537     ASSERT_INVARIANT();
01538 
01539     if (i >= mU.mI.mStringLength) {
01540         throw VRangeException(VSTRING_FORMAT("VString::set(%d,%c) index out of range for string length %d.", i, c.charValue(), mU.mI.mStringLength));
01541     }
01542 
01543     _set()[i] = c.charValue();
01544 
01545     ASSERT_INVARIANT();
01546 }
01547 
01548 void VString::getSubstring(VString& toString, int startIndex, int endIndex) const {
01549     ASSERT_INVARIANT();
01550 
01551     int theLength = this->length();
01552 
01553     startIndex = V_MAX(0, startIndex);        // prevent negative start index
01554     startIndex = V_MIN(theLength, startIndex);    // prevent start past end
01555 
01556     if (endIndex == -1) {    // -1 means to end of string
01557         endIndex = theLength;
01558     }
01559 
01560     endIndex = V_MIN(theLength, endIndex);        // prevent stop past end
01561     endIndex = V_MAX(startIndex, endIndex);    // prevent stop before start
01562 
01563     toString.copyFromBuffer(_get(), startIndex, endIndex);
01564 }
01565 
01566 void VString::getSubstring(VString& toString, VString::const_iterator rangeStart, VString::const_iterator rangeEnd) const {
01567     ASSERT_INVARIANT();
01568 
01569     this->getSubstring(toString, rangeStart.getCurrentOffset(), rangeEnd.getCurrentOffset());
01570 }
01571 
01572 void VString::substringInPlace(int startIndex, int endIndex) {
01573     ASSERT_INVARIANT();
01574 
01575     int theLength = this->length();
01576 
01577     startIndex = V_MAX(0, startIndex);        // prevent negative start index
01578     startIndex = V_MIN(theLength, startIndex);    // prevent start past end
01579 
01580     if (endIndex == -1) {    // -1 means to end of string
01581         endIndex = theLength;
01582     }
01583 
01584     endIndex = V_MIN(theLength, endIndex);        // prevent stop past end
01585     endIndex = V_MAX(startIndex, endIndex);    // prevent stop before start
01586 
01587     // Only do something if the start/stop are not the whole string.
01588     int newLength = endIndex - startIndex;
01589     if (newLength != theLength) {
01590         ::memmove(&(_set()[0]), &(_get()[startIndex]), static_cast<VSizeType>(newLength));
01591         this->_setLength(newLength);
01592     }
01593 
01594     ASSERT_INVARIANT();
01595 }
01596 
01597 void VString::split(VStringVector& result, const VCodePoint& delimiter, int limit, bool stripTrailingEmpties) const {
01598     ASSERT_INVARIANT();
01599 
01600     result.clear();
01601     VString nextItem;
01602     
01603     for (VString::const_iterator i = this->begin(); i != this->end(); ++i) {
01604         VCodePoint cp = (*i);
01605         if (cp == delimiter) {
01606             result.push_back(nextItem);
01607             nextItem = VString::EMPTY();
01608 
01609             if ((limit != 0) && (((int) result.size()) == limit - 1)) {
01610                 // We are 1 less than the limit, so the rest of the string is the remaining item.
01611                 this->getSubstring(nextItem, i + 1, this->end());
01612                 result.push_back(nextItem);
01613                 nextItem = VString::EMPTY();
01614                 break;
01615             }
01616         } else {
01617             nextItem += cp;
01618         }
01619     }
01620     
01621     if (nextItem.isNotEmpty()) {
01622         result.push_back(nextItem);
01623     }
01624 
01625     // Strip trailing empty strings if specified.
01626     if (stripTrailingEmpties) {
01627         while (result[result.size() - 1].isEmpty()) {
01628             result.erase(result.end() - 1);
01629         }
01630     }
01631 }
01632 
01633 VStringVector VString::split(const VCodePoint& delimiter, int limit, bool stripTrailingEmpties) const {
01634     ASSERT_INVARIANT();
01635 
01636     VStringVector result;
01637     this->split(result, delimiter, limit, stripTrailingEmpties);
01638     return result;
01639 }
01640 
01641 void VString::trim() {
01642     ASSERT_INVARIANT();
01643 
01644     int theLength = mU.mI.mStringLength;
01645 
01646     // optimize for empty string condition
01647     if (theLength == 0) {
01648         return;
01649     }
01650 
01651     int indexOfFirstNonWhitespace = -1;
01652     int indexOfLastNonWhitespace = -1;
01653 
01654     char* buf = _set();
01655 
01656     for (int i = 0; i < theLength; ++i) {
01657         if ((buf[i] > 0x20) && (buf[i] != 0x7F)) {
01658             indexOfFirstNonWhitespace = i;
01659             break;
01660         }
01661     }
01662 
01663     if (indexOfFirstNonWhitespace != -1) {
01664         for (int i = theLength - 1; i >= 0; --i) {
01665             if ((buf[i] > 0x20) && (buf[i] != 0x7F)) {
01666                 indexOfLastNonWhitespace = i;
01667                 break;
01668             }
01669         }
01670     }
01671 
01672     /*
01673     Case 1: all whitespace - set length to zero
01674     Case 2: no leading/trailing whitespace - nothing to do
01675     Case 3: some leanding and/or trailing whitespace - move data and change length
01676 
01677     Note: we assume at this point that the buffer exists and length>0 because of prior length check
01678     */
01679     if (indexOfFirstNonWhitespace == -1) {
01680         // all whitespace - set length to zero
01681         this->_setLength(0);
01682     } else if ((indexOfFirstNonWhitespace == 0) && (indexOfLastNonWhitespace == theLength - 1)) {
01683         // no leading/trailing whitespace - nothing to do
01684     } else if (buf != NULL) {
01685         // some leanding and/or trailing whitespace - move data and change length
01686 
01687         int    numBytesAfterTrimming = (indexOfLastNonWhitespace - indexOfFirstNonWhitespace) + 1;
01688 
01689         ::memmove(&(buf[0]), &(buf[indexOfFirstNonWhitespace]), static_cast<VSizeType>(numBytesAfterTrimming));
01690 
01691         this->_setLength(numBytesAfterTrimming);
01692     }
01693 
01694     ASSERT_INVARIANT();
01695 }
01696 
01697 void VString::copyToBuffer(char* toBuffer, int bufferSize) const {
01698     ASSERT_INVARIANT();
01699 
01700     if (toBuffer == NULL) {
01701         throw VRangeException("VString::copyToBuffer: target buffer pointer is null.");
01702     }
01703 
01704     if (mU.mI.mStringLength == 0) {
01705         toBuffer[0] = VCHAR_NULL_TERMINATOR;
01706     } else if (mU.mI.mStringLength < bufferSize) {
01707         ::memcpy(toBuffer, _get(), static_cast<VSizeType>(1 + mU.mI.mStringLength)); // includes our null terminator
01708     } else {
01709         ::memcpy(toBuffer, _get(), static_cast<VSizeType>(bufferSize - 1)); // only copying the part that will fit
01710         toBuffer[bufferSize-1] = VCHAR_NULL_TERMINATOR;
01711     }
01712 }
01713 
01714 void VString::copyFromBuffer(const char* fromBuffer, int startIndex, int endIndex) {
01715     ASSERT_INVARIANT();
01716 
01717     if (startIndex < 0) {
01718         throw VRangeException(VSTRING_FORMAT("VString::copyFromBuffer: out of range start index %d.", startIndex));
01719     }
01720 
01721     // We allow endIndex to be less than startIndex, and compensate for that
01722     if (endIndex < startIndex) {
01723         endIndex = startIndex;
01724     }
01725 
01726     this->preflight(endIndex - startIndex);
01727     ::memcpy(_set(), fromBuffer + startIndex, static_cast<VSizeType>(endIndex - startIndex));
01728     this->postflight(endIndex - startIndex);
01729 
01730     ASSERT_INVARIANT();
01731 }
01732 
01733 void VString::copyFromCString(const char* fromBuffer) {
01734     this->copyFromBuffer(fromBuffer, 0, (int) ::strlen(fromBuffer));
01735 }
01736 
01737 void VString::copyToPascalString(char* pascalBuffer) const {
01738     ASSERT_INVARIANT();
01739 
01740     if (mU.mI.mStringLength == 0) {
01741         pascalBuffer[0] = 0;
01742     } else {
01743         Vu8 constrainedLength = static_cast<Vu8>(V_MIN(255, mU.mI.mStringLength));
01744 
01745         pascalBuffer[0] = static_cast<char>(constrainedLength);
01746         ::memcpy(&(pascalBuffer[1]), _get(), constrainedLength);
01747     }
01748 }
01749 
01750 void VString::copyFromPascalString(const char* pascalBuffer) {
01751     ASSERT_INVARIANT();
01752 
01753     int theLength = static_cast<int>(static_cast<Vu8>(pascalBuffer[0]));
01754 
01755     this->preflight(theLength);
01756     ::memcpy(_set(), &(pascalBuffer[1]), static_cast<VSizeType>(theLength));
01757     this->postflight(theLength);
01758 
01759     ASSERT_INVARIANT();
01760 }
01761 
01762 void VString::setFourCharacterCode(Vu32 fourCharacterCode) {
01763     ASSERT_INVARIANT();
01764 
01765     char codeChars[4];
01766 
01767     for (int i = 0; i < 4; ++i) {
01768         int bitsToShift = 8 * (3 - i);
01769         Vu8 byteValue = static_cast<Vu8>((fourCharacterCode & (static_cast<Vu32>(0x000000FF) << bitsToShift)) >> bitsToShift);
01770         codeChars[i] = byteValue;
01771 
01772         if (codeChars[i] == 0) {
01773             throw VRangeException(VSTRING_FORMAT("VString::setFourCharacterCode: Code 0x%08X has a zero byte.", fourCharacterCode));
01774         }
01775     }
01776 
01777     this->copyFromBuffer(codeChars, 0, 4);
01778 
01779     ASSERT_INVARIANT();
01780 }
01781 
01782 Vu32 VString::getFourCharacterCode() const {
01783     ASSERT_INVARIANT();
01784 
01785     Vu32 result = 0;
01786 
01787     const char* buf = _get();
01788     for (int i = 0; i < 4; ++i) {
01789         Vu8 byteValue;
01790 
01791         if (mU.mI.mStringLength > i) {
01792             byteValue = static_cast<Vu8>(buf[i]);
01793         } else {
01794             byteValue = static_cast<Vu8>(' ');
01795         }
01796 
01797         int bitsToShift = 8 * (3 - i);
01798         Vu32 orValue = (byteValue << bitsToShift) & (0x000000FF << bitsToShift);
01799 
01800         result |= orValue;
01801     }
01802 
01803     return result;
01804 }
01805 
01806 static const int HEAP_BUFFER_EXPANSION_CHUNK_SIZE = 32;
01807 
01808 void VString::preflight(int stringLength) {
01809     ASSERT_INVARIANT();
01810 
01811     if (stringLength < 0) {
01812         throw VRangeException(VSTRING_FORMAT("VString::preflight: negative length %d.", stringLength));
01813     }
01814     
01815     if (mU.mI.mUsingInternalBuffer && (stringLength < VSTRING_INTERNAL_BUFFER_SIZE)) {
01816         return; // Our internal buffer is in use and it's big enough.
01817     }
01818     
01819     if ((!mU.mI.mUsingInternalBuffer) && (stringLength < mU.mX.mHeapBufferLength)) {
01820         return; // Our external buffer is in use and it's big enough.
01821     }
01822     
01823     // At this point, either we need to switch from internal to external, or the
01824     // external buffer is present but not big enough. So we need to allocate a new
01825     // buffer, copy the old buffer (internal or external) to it, and swap it in
01826     // or switch modes.
01827     
01828     try {
01829         // Allocate the buffer in reasonable sized chunks rather than using the exact size
01830         // requested; this easily yields an order of magnitude improvement when a string is
01831         // created with multiple appends.
01832         int newBufferLength = stringLength + 1;
01833         if (HEAP_BUFFER_EXPANSION_CHUNK_SIZE != 1) { // If static analyzer complains about constant comparison, disable it in the tool.
01834             int remainder = newBufferLength % HEAP_BUFFER_EXPANSION_CHUNK_SIZE;
01835             int extra = HEAP_BUFFER_EXPANSION_CHUNK_SIZE - remainder;
01836             newBufferLength += extra;
01837         }
01838 
01839         // This allocation will throw an exception if we run out of memory. Catch below.
01840         char* newBuffer = new char[newBufferLength];
01841 
01842         // Copy our old string, including the null terminator, to the new buffer.
01843         if (mU.mI.mStringLength == 0) {
01844             // If the old string length was zero, there are no characters to copy.
01845             // Just set the null terminator byte at the start of the new buffer.
01846             newBuffer[0] = '\0';
01847         } else {
01848             // Copy our old buffer, up to and including the null terminator byte, to the new buffer.
01849             // We know that stringLength is greater than mU.mI.mStringLength, or we wouldn't be growing
01850             // the buffer in the first place.
01851             ::memcpy(newBuffer, _get(), static_cast<VSizeType>(mU.mI.mStringLength + 1));
01852         }
01853 
01854         // Bookkeeping to switch to the new buffer.
01855         // If previously using the internal buffer, this means switching modes.
01856         // If previously using a heap buffer, this means deleting the old one and swapping pointers.
01857         // We haven't changed the mU.mI.mStringLength; we've merely copied data to a larger buffer.
01858         if (mU.mI.mUsingInternalBuffer) {
01859             mU.mI.mUsingInternalBuffer = false;
01860         } else {
01861             delete [] mU.mX.mHeapBufferPtr;
01862         }
01863 
01864         mU.mX.mHeapBufferPtr = newBuffer;
01865         mU.mX.mHeapBufferLength = newBufferLength;
01866 
01867     }
01868     // About the exceptions we catch here:
01869     // We don't know all the possible behaviors of the exceptions that might be thrown on different platforms.
01870     // There are really three uses cases to handle, and we can handle them uniformly with the two catch blocks
01871     // below. We may catch a VException if SEH translation is installed and a low-level failure occurred. The known
01872     // case for this is a garbage (but almost good-looking) VString, whereby we memcpy() above and that fails.
01873     // The SEH will kick in, we translate it to a VException and land here. Because VException inherits from
01874     // std::exception, that is covered in the std::exception catch block. The other likely failure mode is when
01875     // we run out of memory and cannot satisfy the request to allocate the buffer via "new char[]" above. This can
01876     // also be the case if the requested length is garbage and requests a huge amount of memory that we do not have.
01877     // Since we don't know for sure whether this will be a std::exception or something else, we also need a "..." catch
01878     // block so that we can re-throw with a little extra information about where we are. In both cases we test the
01879     // invariants to make sure that our VString remains in a good state as it did on entry.
01880     catch (const std::exception& ex) {
01881         ASSERT_INVARIANT();
01882         throw VStackTraceException(VSTRING_FORMAT("VString::preflight caught exception preflighting buffer of length %d: %s", (stringLength + 1), ex.what()));
01883     } catch (...) {
01884         ASSERT_INVARIANT();
01885         throw VStackTraceException(VSTRING_FORMAT("VString::preflight caught exception preflighting buffer of length %d.", (stringLength + 1)));
01886     }
01887 
01888     ASSERT_INVARIANT();
01889 }
01890 
01891 void VString::preflightWithSimulatedFailure() {
01892     ASSERT_INVARIANT();
01893 
01894     throw VStackTraceException("VString::preflight unable to allocate buffer. (Simulated failure)");
01895 }
01896 
01897 char* VString::buffer() {
01898     ASSERT_INVARIANT();
01899 
01900     return _set();
01901 }
01902 
01903 Vu8* VString::getDataBuffer() {
01904     ASSERT_INVARIANT();
01905 
01906     return reinterpret_cast<Vu8*>(_set());
01907 }
01908 
01909 const Vu8* VString::getDataBufferConst() const {
01910     ASSERT_INVARIANT();
01911 
01912     return reinterpret_cast<const Vu8*>(_get());
01913 }
01914 
01915 char* VString::orphanDataBuffer() {
01916     ASSERT_INVARIANT();
01917     
01918     char* orphanedBuffer = NULL;
01919 
01920     if (mU.mI.mUsingInternalBuffer) {
01921         // new[] a buffer to give back, and then make our internal buffer and state empty
01922         orphanedBuffer = new char[1 + mU.mI.mStringLength];
01923         ::memcpy(orphanedBuffer, _get(), static_cast<VSizeType>(1 + mU.mI.mStringLength));
01924 
01925         mU.mI.mInternalBuffer[0] = '\0';
01926         mU.mI.mStringLength = 0;
01927         mU.mI.mNumCodePoints = 0;
01928 
01929     } else {
01930         // hand back our heap buffer, and then switch to our internal buffer as empty
01931         orphanedBuffer = mU.mX.mHeapBufferPtr;
01932         mU.mX.mHeapBufferPtr = NULL;
01933         mU.mX.mHeapBufferLength = 0;
01934 
01935         mU.mI.mUsingInternalBuffer = true;
01936         mU.mI.mInternalBuffer[0] = '\0';
01937         mU.mI.mStringLength = 0;
01938         mU.mI.mNumCodePoints = 0;
01939     }
01940     
01941     ASSERT_INVARIANT();
01942 
01943     return orphanedBuffer;
01944 }
01945 
01946 void VString::postflight(int stringLength) {
01947     /*
01948     Do not assert invariant on entry -- postflight's job is to clean up
01949     after a buffer copy that presumably has made the invariant state
01950     invalid.
01951     */
01952 
01953     this->_setLength(stringLength);
01954 
01955     ASSERT_INVARIANT();
01956 }
01957 
01958 #ifdef VAULT_VARARG_STRING_FORMATTING_SUPPORT
01959 void VString::vaFormat(const char* formatText, va_list args) {
01960     ASSERT_INVARIANT();
01961 
01962     if (formatText == NULL) {
01963         this->_setLength(0);
01964     } else {
01965         va_list argsCopy;
01966         va_copy(argsCopy, args);
01967         int newStringLength = VString::_determineSprintfLength(formatText, args);
01968 
01969         if (newStringLength == -1) {
01970             // We were unable to determine the buffer length needed. Log an error and make the preflight
01971             // use as big a buffer as we dare: how about the size of the temporary formatting buffer.
01972             const int kTruncatedStringLength = 32768;
01973             VLOGGER_ERROR(VSTRING_FORMAT("VString: formatted string will be truncated to %d characaters.", kTruncatedStringLength));
01974             newStringLength = kTruncatedStringLength;
01975         }
01976 
01977         this->preflight(newStringLength);
01978 
01979         (void) vault::vsnprintf(_set(), static_cast<VSizeType>(this->_getBufferLength()), formatText, argsCopy);
01980 
01981         this->_setLength(newStringLength); // could call postflight, but would do extra assertion check
01982     }
01983 
01984     ASSERT_INVARIANT();
01985 }
01986 #endif /* VAULT_VARARG_STRING_FORMATTING_SUPPORT */
01987 
01988 void VString::_setLength(int stringLength) {
01989     if (stringLength < 0) {
01990         throw VRangeException(VSTRING_FORMAT("VString::_setLength: Out of bounds negative value %d.", stringLength));
01991     }
01992 
01993     if (stringLength >= this->_getBufferLength()) {
01994         throw VRangeException(VSTRING_FORMAT("VString::_setLength: Out of bounds value %d exceeds buffer length of %d.", stringLength, this->_getBufferLength()));
01995     }
01996 
01997     if ((stringLength == 0) && !mU.mI.mUsingInternalBuffer && (mU.mX.mHeapBufferPtr != NULL)) {
01998         // String length is being set to zero and we had a heap buffer. Delete the buffer and switch to a zero length internal buffer.
01999         // Note: We could consider also switching to the internal buffer (with a copy and a heap buffer delete) if we are changing length from large to small.
02000         delete [] mU.mX.mHeapBufferPtr;
02001         mU.mX.mHeapBufferPtr = NULL;
02002         mU.mX.mHeapBufferLength = 0;
02003         mU.mI.mUsingInternalBuffer = true;
02004         mU.mI.mInternalBuffer[0] = '\0';
02005     } else { /* */
02006         _set()[stringLength] = '\0';
02007     }
02008 
02009     // At this point we have validated the stringLength, even if mBuffer is NULL.
02010     mU.mI.mStringLength = stringLength;
02011     mU.mI.mNumCodePoints = -1; // force recalc by next call to getNumCodePoints() if ever called
02012 }
02013 
02014 Vs64 VString::_parseSignedInteger() const {
02015     Vs64 result = CONST_S64(0);
02016     Vs64 multiplier = CONST_S64(1);
02017 
02018     if (mU.mI.mStringLength != 0) {
02019         // Iterate over the characters backwards, building the result.
02020         // If we encounter something illegal, throw the VRangeException.
02021         const char* buf = _get();
02022         for (int i = mU.mI.mStringLength - 1; i >= 0; --i) {
02023             switch (buf[i]) {
02024                 case '-':
02025                     if (i != 0) {
02026                         throw VRangeException(VSTRING_FORMAT("VString::_parseSignedInteger %c at index %d is invalid format.", buf[i], i));
02027                     }
02028 
02029                     result = -result;
02030                     break;
02031 
02032                 case '+':
02033                     if (i != 0) {
02034                         throw VRangeException(VSTRING_FORMAT("VString::_parseSignedInteger %c at index %d is invalid format.", buf[i], i));
02035                     }
02036                     break;
02037 
02038                 case '0':
02039                 case '1':
02040                 case '2':
02041                 case '3':
02042                 case '4':
02043                 case '5':
02044                 case '6':
02045                 case '7':
02046                 case '8':
02047                 case '9':
02048                     result += (multiplier * (static_cast<int>(buf[i] - '0')));
02049                     break;
02050 
02051                 default:
02052                     throw VRangeException(VSTRING_FORMAT("VString::_parseSignedInteger %c at index %d is invalid format.", buf[i], i));
02053                     break;
02054             }
02055 
02056             multiplier *= 10;
02057         }
02058     }
02059 
02060     return result;
02061 }
02062 
02063 Vu64 VString::_parseUnsignedInteger() const {
02064     Vu64 result = CONST_U64(0);
02065     Vs64 multiplier = CONST_S64(1);
02066 
02067     if (mU.mI.mStringLength != 0) {
02068         // Iterate over the characters backwards, building the result.
02069         // If we encounter something illegal, throw the VRangeException.
02070         const char* buf = _get();
02071         for (int i = mU.mI.mStringLength - 1; i >= 0; --i) {
02072             switch (buf[i]) {
02073                 case '-':
02074                     throw VRangeException(VSTRING_FORMAT("VString::_parseUnsignedInteger %c at index %d is invalid format.", buf[i], i));
02075                     break;
02076 
02077                 case '+':
02078                     if (i != 0) {
02079                         throw VRangeException(VSTRING_FORMAT("VString::_parseUnsignedInteger %c at index %d is invalid format.", buf[i], i));
02080                     }
02081                     break;
02082 
02083                 case '0':
02084                 case '1':
02085                 case '2':
02086                 case '3':
02087                 case '4':
02088                 case '5':
02089                 case '6':
02090                 case '7':
02091                 case '8':
02092                 case '9':
02093                     result += (multiplier * (static_cast<int>(buf[i] - '0')));
02094                     break;
02095 
02096                 default:
02097                     throw VRangeException(VSTRING_FORMAT("VString::_parseUnsignedInteger %c at index %d is invalid format.", buf[i], i));
02098                     break;
02099             }
02100 
02101             multiplier *= 10;
02102         }
02103     }
02104 
02105     return result;
02106 }
02107 
02108 void VString::_assertInvariant() const {
02109     const char* buf = _get();
02110     VASSERT_NOT_NULL(buf);
02111     VASSERT_NOT_EQUAL(buf, VCPP_DEBUG_BAD_POINTER_VALUE);
02112     VASSERT_GREATER_THAN_OR_EQUAL(mU.mI.mStringLength, 0);
02113     VASSERT_GREATER_THAN(this->_getBufferLength(), mU.mI.mStringLength); // buffer must always have room for null terminator not included in string length
02114     VASSERT(buf[mU.mI.mStringLength] == VCHAR_NULL_TERMINATOR);
02115 }
02116 
02117 #ifdef VAULT_VARARG_STRING_FORMATTING_SUPPORT
02118 
02119 /*
02120 The IEEE 1003.1 standard states that we can call vsnprintf with
02121 a length of 0 and a null buffer pointer, and it shall return the
02122 number of bytes that would have been written had n been sufficiently
02123 large, excluding the terminating null byte. However, this does not
02124 work with all libraries, so we set V_EFFICIENT_SPRINTF in the
02125 platform header if we can use this feature.
02126 */
02127 #ifdef V_EFFICIENT_SPRINTF
02128 
02129 // static
02130 int VString::_determineSprintfLength(const char* formatText, va_list args) {
02131     return vault::vsnprintf(NULL, 0, formatText, args);
02132 }
02133 
02134 #else /* not V_EFFICIENT_SPRINTF, use inefficient method */
02135 
02136 static const int INEFFICIENT_SPRINTF_STATIC_BUFFER_SIZE = 32768;    
02137 static char _inefficientSprintfBuffer[INEFFICIENT_SPRINTF_STATIC_BUFFER_SIZE];
02138 static VMutex _inefficientSprintfBufferMutex("vsnprintf", true/*this mutex itself must not log*/);
02139 
02140 // static
02141 int VString::_determineSprintfLength(const char* formatText, va_list args) {
02142     VMutexLocker locker(&_inefficientSprintfBufferMutex, "VString::_determineSprintfLength");
02143     return vault::vsnprintf(_inefficientSprintfBuffer, INEFFICIENT_SPRINTF_STATIC_BUFFER_SIZE, formatText, args);
02144 }
02145 
02146 #endif /* V_EFFICIENT_SPRINTF */
02147 
02148 #endif /* VAULT_VARARG_STRING_FORMATTING_SUPPORT */
02149 
02150 void VString::_assignFromUTF16WideString(const std::wstring& utf16WideString) {
02151 
02152     *this = VString::EMPTY();
02153 
02154     int numCodeUnits = (int) utf16WideString.length();
02155     for (int i = 0; i < numCodeUnits; ++i) {
02156         VCodePoint cp(utf16WideString, i);
02157         if (cp.getUTF16Length() == 2) {
02158             ++i; // Skip past trail surrogate we just "consumed".
02159         }
02160         (*this) += cp;
02161     }
02162 }
02163 
02164 #ifdef VAULT_CORE_FOUNDATION_SUPPORT
02165 void VString::_assignFromCFString(const CFStringRef& s) {
02166     const char* cfStringBuffer = CFStringGetCStringPtr(s, kCFStringEncodingUTF8);
02167     if (cfStringBuffer != NULL) { // was able to get fast direct buffer access
02168         this->copyFromBuffer(cfStringBuffer, 0, (int) ::strlen(cfStringBuffer));
02169     } else {
02170         bool success = false;
02171         int originalLength = static_cast<int>(CFStringGetLength(s));
02172         int finalLength = originalLength;
02173 
02174         // Because of expansion that can happen during transcoding, the number of bytes we need
02175         // might be more than the number of "characters" in the CFString. We start by trying with
02176         // a buffer of the exact size, and if that fails, we try with double the space, and finally
02177         // with quadruple the space. The only way this will fail is if the string contains
02178         // mostly non-Roman characters and thus has lots of multi-byte data. (If CFString could
02179         // tell us the output length ahead of time or upon failure, we could use that. Or, we
02180         // could use a doubling factor and keep trying until we get it.)
02181         this->preflight(finalLength);
02182         success = CFStringGetCString(s, _set(), static_cast<CFIndex>(finalLength + 1), kCFStringEncodingUTF8);
02183 
02184         // try with a 2x buffer
02185         if (! success) {
02186             finalLength *= 2;
02187             this->preflight(finalLength);
02188             success = CFStringGetCString(s, _set(), static_cast<CFIndex>(finalLength + 1), kCFStringEncodingUTF8);
02189         }
02190 
02191         // try with a 4x buffer
02192         if (! success) {
02193             finalLength *= 2;
02194             this->preflight(finalLength);
02195             success = CFStringGetCString(s, _set(), static_cast<CFIndex>(finalLength + 1), kCFStringEncodingUTF8);
02196         }
02197 
02198         if (! success) {
02199             throw VStackTraceException(VSTRING_FORMAT("VString CFStringRef constructor allocated up to %d bytes, which was insufficient for CFStringRef of length %d.", finalLength, originalLength));
02200         }
02201 
02202         this->_setLength(finalLength);
02203     }
02204 }
02205 #endif /* VAULT_CORE_FOUNDATION_SUPPORT */
02206 
02207 void VString::_construct() {
02208     // Clearing the mX fields is just to have less garabage showing in the debugger from the get-go.
02209     // Not required, and will be defeated once the mU.mI.mInternalBuffer holds a non-empty string.
02210     mU.mX.mHeapBufferLength = 0;
02211     mU.mX.mHeapBufferPtr = NULL;
02212 
02213     mU.mI.mStringLength = 0;
02214     mU.mI.mNumCodePoints = 0;
02215     mU.mI.mUsingInternalBuffer = true;
02216     mU.mI.mPadBits = 0;
02217     mU.mI.mInternalBuffer[0] = '\0';
02218 }
02219 
02220 void VString::_determineNumCodePoints() const {
02221     if (this->isEmpty()) { // optimize away need to call countUTF8CodePoints() and have it set up counting loop in the first place
02222         mU.mI.mNumCodePoints = 0;
02223     } else {
02224         mU.mI.mNumCodePoints = VCodePoint::countUTF8CodePoints(this->getDataBufferConst(), this->length());
02225     }
02226 }

Copyright ©1997-2014 Trygve Isaacson. All rights reserved. This documentation was generated with Doxygen.