]> git.saurik.com Git - wxWidgets.git/blame - src/common/stringimpl.cpp
Implemented the same simple API for creating customized
[wxWidgets.git] / src / common / stringimpl.cpp
CommitLineData
a7ea63e2 1/////////////////////////////////////////////////////////////////////////////
81727065 2// Name: src/common/stringimpl.cpp
a7ea63e2
VS
3// Purpose: wxString class
4// Author: Vadim Zeitlin, Ryan Norton
5// Modified by:
6// Created: 29/01/98
7// RCS-ID: $Id$
8// Copyright: (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
9// (c) 2004 Ryan Norton <wxprojects@comcast.net>
10// Licence: wxWindows licence
11/////////////////////////////////////////////////////////////////////////////
12
13/*
14 * About ref counting:
15 * 1) all empty strings use g_strEmpty, nRefs = -1 (set in Init())
16 * 2) AllocBuffer() sets nRefs to 1, Lock() increments it by one
17 * 3) Unlock() decrements nRefs and frees memory if it goes to 0
18 */
19
20// ===========================================================================
21// headers, declarations, constants
22// ===========================================================================
23
24// For compilers that support precompilation, includes "wx.h".
25#include "wx/wxprec.h"
26
27#ifdef __BORLANDC__
28 #pragma hdrstop
29#endif
30
31#ifndef WX_PRECOMP
32 #include "wx/stringimpl.h"
33#endif
34
35#include <ctype.h>
36
37#ifndef __WXWINCE__
38 #include <errno.h>
39#endif
40
41#include <string.h>
42#include <stdlib.h>
43
44#ifdef __SALFORDC__
45 #include <clib.h>
46#endif
47
48// allocating extra space for each string consumes more memory but speeds up
49// the concatenation operations (nLen is the current string's length)
50// NB: EXTRA_ALLOC must be >= 0!
51#define EXTRA_ALLOC (19 - nLen % 16)
52
53
54// string handling functions used by wxString:
55#if wxUSE_UNICODE_UTF8
56 #define wxStringMemcpy memcpy
57 #define wxStringMemcmp memcmp
58 #define wxStringMemchr memchr
a7ea63e2
VS
59#else
60 #define wxStringMemcpy wxTmemcpy
61 #define wxStringMemcmp wxTmemcmp
62 #define wxStringMemchr wxTmemchr
a7ea63e2
VS
63#endif
64
65
66// ---------------------------------------------------------------------------
67// static class variables definition
68// ---------------------------------------------------------------------------
69
70#if !wxUSE_STL_BASED_WXSTRING
71//According to STL _must_ be a -1 size_t
72const size_t wxStringImpl::npos = (size_t) -1;
73#endif
74
75// ----------------------------------------------------------------------------
76// static data
77// ----------------------------------------------------------------------------
78
79#if wxUSE_STL_BASED_WXSTRING
80
81727065
VS
81// FIXME-UTF8: get rid of this, have only one wxEmptyString
82#if wxUSE_UNICODE_UTF8
83extern const wxStringCharType WXDLLIMPEXP_BASE *wxEmptyStringImpl = "";
84#endif
a7ea63e2
VS
85extern const wxChar WXDLLIMPEXP_BASE *wxEmptyString = _T("");
86
87#else
88
89// for an empty string, GetStringData() will return this address: this
90// structure has the same layout as wxStringData and it's data() method will
91// return the empty string (dummy pointer)
92static const struct
93{
94 wxStringData data;
81727065 95 wxStringCharType dummy;
a7ea63e2
VS
96} g_strEmpty = { {-1, 0, 0}, wxT('\0') };
97
98// empty C style string: points to 'string data' byte of g_strEmpty
81727065
VS
99#if wxUSE_UNICODE_UTF8
100// FIXME-UTF8: get rid of this, have only one wxEmptyString
101extern const wxStringCharType WXDLLIMPEXP_BASE *wxEmptyStringImpl = &g_strEmpty.dummy;
102extern const wxChar WXDLLIMPEXP_BASE *wxEmptyString = _T("");
103#else
104extern const wxStringCharType WXDLLIMPEXP_BASE *wxEmptyString = &g_strEmpty.dummy;
105#endif
a7ea63e2
VS
106
107#endif
108
109
110#if !wxUSE_STL_BASED_WXSTRING
111
112// ----------------------------------------------------------------------------
113// private classes
114// ----------------------------------------------------------------------------
115
116// this small class is used to gather statistics for performance tuning
117//#define WXSTRING_STATISTICS
118#ifdef WXSTRING_STATISTICS
119 class Averager
120 {
121 public:
81727065 122 Averager(const wxStringCharType *sz) { m_sz = sz; m_nTotal = m_nCount = 0; }
a7ea63e2
VS
123 ~Averager()
124 { wxPrintf("wxString: average %s = %f\n", m_sz, ((float)m_nTotal)/m_nCount); }
125
126 void Add(size_t n) { m_nTotal += n; m_nCount++; }
127
128 private:
129 size_t m_nCount, m_nTotal;
81727065 130 const wxStringCharType *m_sz;
a7ea63e2
VS
131 } g_averageLength("allocation size"),
132 g_averageSummandLength("summand length"),
133 g_averageConcatHit("hit probability in concat"),
134 g_averageInitialLength("initial string length");
135
136 #define STATISTICS_ADD(av, val) g_average##av.Add(val)
137#else
138 #define STATISTICS_ADD(av, val)
139#endif // WXSTRING_STATISTICS
140
141// ===========================================================================
142// wxStringData class deallocation
143// ===========================================================================
144
145#if defined(__VISUALC__) && defined(_MT) && !defined(_DLL)
146# pragma message (__FILE__ ": building with Multithreaded non DLL runtime has a performance impact on wxString!")
147void wxStringData::Free()
148{
149 free(this);
150}
151#endif
152
153// ===========================================================================
154// wxStringImpl
155// ===========================================================================
156
157// takes nLength elements of psz starting at nPos
81727065
VS
158void wxStringImpl::InitWith(const wxStringCharType *psz,
159 size_t nPos, size_t nLength)
a7ea63e2
VS
160{
161 Init();
162
163 // if the length is not given, assume the string to be NUL terminated
164 if ( nLength == npos ) {
81727065 165 wxASSERT_MSG( nPos <= Strsize(psz), _T("index out of bounds") );
a7ea63e2 166
81727065 167 nLength = Strsize(psz + nPos);
a7ea63e2
VS
168 }
169
170 STATISTICS_ADD(InitialLength, nLength);
171
172 if ( nLength > 0 ) {
173 // trailing '\0' is written in AllocBuffer()
174 if ( !AllocBuffer(nLength) ) {
175 wxFAIL_MSG( _T("out of memory in wxStringImpl::InitWith") );
176 return;
177 }
178 wxStringMemcpy(m_pchData, psz + nPos, nLength);
179 }
180}
181
f2a1b1bd 182wxStringImpl::wxStringImpl(const_iterator first, const_iterator last)
a7ea63e2 183{
f2a1b1bd 184 if ( last >= first )
a7ea63e2 185 {
f2a1b1bd 186 InitWith(first, 0, last - first);
a7ea63e2
VS
187 }
188 else
189 {
f2a1b1bd 190 wxFAIL_MSG( _T("first must be before last") );
a7ea63e2
VS
191 Init();
192 }
193}
194
195wxStringImpl::wxStringImpl(size_type n, wxStringCharType ch)
196{
197 Init();
198 append(n, ch);
199}
200
201// ---------------------------------------------------------------------------
202// memory allocation
203// ---------------------------------------------------------------------------
204
205// allocates memory needed to store a C string of length nLen
206bool wxStringImpl::AllocBuffer(size_t nLen)
207{
208 // allocating 0 sized buffer doesn't make sense, all empty strings should
209 // reuse g_strEmpty
210 wxASSERT( nLen > 0 );
211
212 // make sure that we don't overflow
81727065 213 wxASSERT( nLen < (INT_MAX / sizeof(wxStringCharType)) -
a7ea63e2
VS
214 (sizeof(wxStringData) + EXTRA_ALLOC + 1) );
215
216 STATISTICS_ADD(Length, nLen);
217
218 // allocate memory:
219 // 1) one extra character for '\0' termination
220 // 2) sizeof(wxStringData) for housekeeping info
221 wxStringData* pData = (wxStringData*)
81727065 222 malloc(sizeof(wxStringData) + (nLen + EXTRA_ALLOC + 1)*sizeof(wxStringCharType));
a7ea63e2
VS
223
224 if ( pData == NULL ) {
225 // allocation failures are handled by the caller
226 return false;
227 }
228
229 pData->nRefs = 1;
230 pData->nDataLength = nLen;
231 pData->nAllocLength = nLen + EXTRA_ALLOC;
232 m_pchData = pData->data(); // data starts after wxStringData
233 m_pchData[nLen] = wxT('\0');
234 return true;
235}
236
237// must be called before changing this string
238bool wxStringImpl::CopyBeforeWrite()
239{
240 wxStringData* pData = GetStringData();
241
242 if ( pData->IsShared() ) {
243 pData->Unlock(); // memory not freed because shared
244 size_t nLen = pData->nDataLength;
245 if ( !AllocBuffer(nLen) ) {
246 // allocation failures are handled by the caller
247 return false;
248 }
249 wxStringMemcpy(m_pchData, pData->data(), nLen);
250 }
251
252 wxASSERT( !GetStringData()->IsShared() ); // we must be the only owner
253
254 return true;
255}
256
257// must be called before replacing contents of this string
258bool wxStringImpl::AllocBeforeWrite(size_t nLen)
259{
260 wxASSERT( nLen != 0 ); // doesn't make any sense
261
262 // must not share string and must have enough space
263 wxStringData* pData = GetStringData();
264 if ( pData->IsShared() || pData->IsEmpty() ) {
265 // can't work with old buffer, get new one
266 pData->Unlock();
267 if ( !AllocBuffer(nLen) ) {
268 // allocation failures are handled by the caller
269 return false;
270 }
271 }
272 else {
273 if ( nLen > pData->nAllocLength ) {
274 // realloc the buffer instead of calling malloc() again, this is more
275 // efficient
276 STATISTICS_ADD(Length, nLen);
277
278 nLen += EXTRA_ALLOC;
279
280 pData = (wxStringData*)
81727065
VS
281 realloc(pData,
282 sizeof(wxStringData) + (nLen + 1)*sizeof(wxStringCharType));
a7ea63e2
VS
283
284 if ( pData == NULL ) {
285 // allocation failures are handled by the caller
286 // keep previous data since reallocation failed
287 return false;
288 }
289
290 pData->nAllocLength = nLen;
291 m_pchData = pData->data();
292 }
293 }
294
295 wxASSERT( !GetStringData()->IsShared() ); // we must be the only owner
296
297 // it doesn't really matter what the string length is as it's going to be
298 // overwritten later but, for extra safety, set it to 0 for now as we may
299 // have some junk in m_pchData
300 GetStringData()->nDataLength = 0;
301
302 return true;
303}
304
305wxStringImpl& wxStringImpl::append(size_t n, wxStringCharType ch)
306{
307 size_type len = length();
308
309 if ( !Alloc(len + n) || !CopyBeforeWrite() ) {
310 wxFAIL_MSG( _T("out of memory in wxStringImpl::append") );
6859e6fc 311 return *this;
a7ea63e2
VS
312 }
313 GetStringData()->nDataLength = len + n;
314 m_pchData[len + n] = '\0';
315 for ( size_t i = 0; i < n; ++i )
316 m_pchData[len + i] = ch;
317 return *this;
318}
319
320void wxStringImpl::resize(size_t nSize, wxStringCharType ch)
321{
322 size_t len = length();
323
324 if ( nSize < len )
325 {
326 erase(begin() + nSize, end());
327 }
328 else if ( nSize > len )
329 {
330 append(nSize - len, ch);
331 }
332 //else: we have exactly the specified length, nothing to do
333}
334
335// allocate enough memory for nLen characters
336bool wxStringImpl::Alloc(size_t nLen)
337{
338 wxStringData *pData = GetStringData();
339 if ( pData->nAllocLength <= nLen ) {
340 if ( pData->IsEmpty() ) {
341 nLen += EXTRA_ALLOC;
342
343 pData = (wxStringData *)
81727065 344 malloc(sizeof(wxStringData) + (nLen + 1)*sizeof(wxStringCharType));
a7ea63e2
VS
345
346 if ( pData == NULL ) {
347 // allocation failure handled by caller
348 return false;
349 }
350
351 pData->nRefs = 1;
352 pData->nDataLength = 0;
353 pData->nAllocLength = nLen;
354 m_pchData = pData->data(); // data starts after wxStringData
355 m_pchData[0u] = wxT('\0');
356 }
357 else if ( pData->IsShared() ) {
358 pData->Unlock(); // memory not freed because shared
359 size_t nOldLen = pData->nDataLength;
360 if ( !AllocBuffer(nLen) ) {
361 // allocation failure handled by caller
362 return false;
363 }
364 // +1 to copy the terminator, too
81727065 365 memcpy(m_pchData, pData->data(), (nOldLen+1)*sizeof(wxStringCharType));
a7ea63e2
VS
366 GetStringData()->nDataLength = nOldLen;
367 }
368 else {
369 nLen += EXTRA_ALLOC;
370
371 pData = (wxStringData *)
81727065 372 realloc(pData, sizeof(wxStringData) + (nLen + 1)*sizeof(wxStringCharType));
a7ea63e2
VS
373
374 if ( pData == NULL ) {
375 // allocation failure handled by caller
376 // keep previous data since reallocation failed
377 return false;
378 }
379
380 // it's not important if the pointer changed or not (the check for this
381 // is not faster than assigning to m_pchData in all cases)
382 pData->nAllocLength = nLen;
383 m_pchData = pData->data();
384 }
385 }
386 //else: we've already got enough
387 return true;
388}
389
390wxStringImpl::iterator wxStringImpl::begin()
391{
392 if (length() > 0)
393 CopyBeforeWrite();
394 return m_pchData;
395}
396
397wxStringImpl::iterator wxStringImpl::end()
398{
399 if (length() > 0)
400 CopyBeforeWrite();
401 return m_pchData + length();
402}
403
404wxStringImpl::iterator wxStringImpl::erase(iterator it)
405{
406 size_type idx = it - begin();
407 erase(idx, 1);
408 return begin() + idx;
409}
410
411wxStringImpl& wxStringImpl::erase(size_t nStart, size_t nLen)
412{
413 wxASSERT(nStart <= length());
414 size_t strLen = length() - nStart;
415 // delete nLen or up to the end of the string characters
416 nLen = strLen < nLen ? strLen : nLen;
417 wxStringImpl strTmp(c_str(), nStart);
418 strTmp.append(c_str() + nStart + nLen, length() - nStart - nLen);
419
420 swap(strTmp);
421 return *this;
422}
423
81727065
VS
424wxStringImpl& wxStringImpl::insert(size_t nPos,
425 const wxStringCharType *sz, size_t n)
a7ea63e2
VS
426{
427 wxASSERT( nPos <= length() );
428
81727065 429 if ( n == npos ) n = Strsize(sz);
a7ea63e2
VS
430 if ( n == 0 ) return *this;
431
432 if ( !Alloc(length() + n) || !CopyBeforeWrite() ) {
433 wxFAIL_MSG( _T("out of memory in wxStringImpl::insert") );
6859e6fc 434 return *this;
a7ea63e2
VS
435 }
436
437 memmove(m_pchData + nPos + n, m_pchData + nPos,
81727065
VS
438 (length() - nPos) * sizeof(wxStringCharType));
439 memcpy(m_pchData + nPos, sz, n * sizeof(wxStringCharType));
a7ea63e2
VS
440 GetStringData()->nDataLength = length() + n;
441 m_pchData[length()] = '\0';
442
443 return *this;
444}
445
446void wxStringImpl::swap(wxStringImpl& str)
447{
448 wxStringCharType* tmp = str.m_pchData;
449 str.m_pchData = m_pchData;
450 m_pchData = tmp;
451}
452
453size_t wxStringImpl::find(const wxStringImpl& str, size_t nStart) const
454{
455 // deal with the special case of empty string first
456 const size_t nLen = length();
457 const size_t nLenOther = str.length();
458
459 if ( !nLenOther )
460 {
461 // empty string is a substring of anything
462 return 0;
463 }
464
465 if ( !nLen )
466 {
467 // the other string is non empty so can't be our substring
468 return npos;
469 }
470
471 wxASSERT( str.GetStringData()->IsValid() );
472 wxASSERT( nStart <= nLen );
473
474 const wxStringCharType * const other = str.c_str();
475
476 // anchor
477 const wxStringCharType* p =
478 (const wxStringCharType*)wxStringMemchr(c_str() + nStart,
479 *other,
480 nLen - nStart);
481
482 if ( !p )
483 return npos;
484
485 while ( p - c_str() + nLenOther <= nLen &&
486 wxStringMemcmp(p, other, nLenOther) )
487 {
488 p++;
489
490 // anchor again
491 p = (const wxStringCharType*)
492 wxStringMemchr(p, *other, nLen - (p - c_str()));
493
494 if ( !p )
495 return npos;
496 }
497
498 return p - c_str() + nLenOther <= nLen ? p - c_str() : npos;
499}
500
81727065
VS
501size_t wxStringImpl::find(const wxStringCharType* sz,
502 size_t nStart, size_t n) const
a7ea63e2
VS
503{
504 return find(wxStringImpl(sz, n), nStart);
505}
506
507size_t wxStringImpl::find(wxStringCharType ch, size_t nStart) const
508{
509 wxASSERT( nStart <= length() );
510
511 const wxStringCharType *p = (const wxStringCharType*)
512 wxStringMemchr(c_str() + nStart, ch, length() - nStart);
513
514 return p == NULL ? npos : p - c_str();
515}
516
517size_t wxStringImpl::rfind(const wxStringImpl& str, size_t nStart) const
518{
519 wxASSERT( str.GetStringData()->IsValid() );
520 wxASSERT( nStart == npos || nStart <= length() );
521
522 if ( length() >= str.length() )
523 {
524 // avoids a corner case later
525 if ( length() == 0 && str.length() == 0 )
526 return 0;
527
528 // "top" is the point where search starts from
529 size_t top = length() - str.length();
530
531 if ( nStart == npos )
532 nStart = length() - 1;
533 if ( nStart < top )
534 top = nStart;
535
536 const wxStringCharType *cursor = c_str() + top;
537 do
538 {
539 if ( wxStringMemcmp(cursor, str.c_str(), str.length()) == 0 )
540 {
541 return cursor - c_str();
542 }
543 } while ( cursor-- > c_str() );
544 }
545
546 return npos;
547}
548
81727065
VS
549size_t wxStringImpl::rfind(const wxStringCharType* sz,
550 size_t nStart, size_t n) const
a7ea63e2
VS
551{
552 return rfind(wxStringImpl(sz, n), nStart);
553}
554
555size_t wxStringImpl::rfind(wxStringCharType ch, size_t nStart) const
556{
557 if ( nStart == npos )
558 {
559 nStart = length();
560 }
561 else
562 {
563 wxASSERT( nStart <= length() );
564 }
565
566 const wxStringCharType *actual;
567 for ( actual = c_str() + ( nStart == npos ? length() : nStart + 1 );
568 actual > c_str(); --actual )
569 {
570 if ( *(actual - 1) == ch )
571 return (actual - 1) - c_str();
572 }
573
574 return npos;
575}
576
577wxStringImpl& wxStringImpl::replace(size_t nStart, size_t nLen,
81727065 578 const wxStringCharType *sz)
a7ea63e2
VS
579{
580 wxASSERT_MSG( nStart <= length(),
581 _T("index out of bounds in wxStringImpl::replace") );
582 size_t strLen = length() - nStart;
583 nLen = strLen < nLen ? strLen : nLen;
584
585 wxStringImpl strTmp;
586 strTmp.reserve(length()); // micro optimisation to avoid multiple mem allocs
587
588 //This is kind of inefficient, but its pretty good considering...
589 //we don't want to use character access operators here because on STL
590 //it will freeze the reference count of strTmp, which means a deep copy
591 //at the end when swap is called
592 //
593 //Also, we can't use append with the full character pointer and must
594 //do it manually because this string can contain null characters
595 for(size_t i1 = 0; i1 < nStart; ++i1)
596 strTmp.append(1, this->c_str()[i1]);
597
598 //its safe to do the full version here because
599 //sz must be a normal c string
600 strTmp.append(sz);
601
602 for(size_t i2 = nStart + nLen; i2 < length(); ++i2)
603 strTmp.append(1, this->c_str()[i2]);
604
605 swap(strTmp);
606 return *this;
607}
608
609wxStringImpl& wxStringImpl::replace(size_t nStart, size_t nLen,
610 size_t nCount, wxStringCharType ch)
611{
612 return replace(nStart, nLen, wxStringImpl(nCount, ch).c_str());
613}
614
615wxStringImpl& wxStringImpl::replace(size_t nStart, size_t nLen,
616 const wxStringImpl& str,
617 size_t nStart2, size_t nLen2)
618{
619 return replace(nStart, nLen, str.substr(nStart2, nLen2));
620}
621
622wxStringImpl& wxStringImpl::replace(size_t nStart, size_t nLen,
81727065 623 const wxStringCharType* sz, size_t nCount)
a7ea63e2
VS
624{
625 return replace(nStart, nLen, wxStringImpl(sz, nCount).c_str());
626}
627
628wxStringImpl wxStringImpl::substr(size_t nStart, size_t nLen) const
629{
630 if ( nLen == npos )
631 nLen = length() - nStart;
632 return wxStringImpl(*this, nStart, nLen);
633}
634
635// assigns one string to another
636wxStringImpl& wxStringImpl::operator=(const wxStringImpl& stringSrc)
637{
638 wxASSERT( stringSrc.GetStringData()->IsValid() );
639
640 // don't copy string over itself
641 if ( m_pchData != stringSrc.m_pchData ) {
642 if ( stringSrc.GetStringData()->IsEmpty() ) {
643 Reinit();
644 }
645 else {
646 // adjust references
647 GetStringData()->Unlock();
648 m_pchData = stringSrc.m_pchData;
649 GetStringData()->Lock();
650 }
651 }
652
653 return *this;
654}
655
656// assigns a single character
657wxStringImpl& wxStringImpl::operator=(wxStringCharType ch)
658{
81727065 659 wxStringCharType c(ch);
a7ea63e2 660 if ( !AssignCopy(1, &c) ) {
81727065 661 wxFAIL_MSG( _T("out of memory in wxStringImpl::operator=(wxStringCharType)") );
a7ea63e2
VS
662 }
663 return *this;
664}
665
666// assigns C string
81727065 667wxStringImpl& wxStringImpl::operator=(const wxStringCharType *psz)
a7ea63e2 668{
81727065
VS
669 if ( !AssignCopy(Strsize(psz), psz) ) {
670 wxFAIL_MSG( _T("out of memory in wxStringImpl::operator=(const wxStringCharType *)") );
a7ea63e2
VS
671 }
672 return *this;
673}
674
675// helper function: does real copy
81727065
VS
676bool wxStringImpl::AssignCopy(size_t nSrcLen,
677 const wxStringCharType *pszSrcData)
a7ea63e2
VS
678{
679 if ( nSrcLen == 0 ) {
680 Reinit();
681 }
682 else {
683 if ( !AllocBeforeWrite(nSrcLen) ) {
684 // allocation failure handled by caller
685 return false;
686 }
81727065 687 memcpy(m_pchData, pszSrcData, nSrcLen*sizeof(wxStringCharType));
a7ea63e2
VS
688 GetStringData()->nDataLength = nSrcLen;
689 m_pchData[nSrcLen] = wxT('\0');
690 }
691 return true;
692}
693
694// ---------------------------------------------------------------------------
695// string concatenation
696// ---------------------------------------------------------------------------
697
698// add something to this string
81727065
VS
699bool wxStringImpl::ConcatSelf(size_t nSrcLen,
700 const wxStringCharType *pszSrcData,
a7ea63e2
VS
701 size_t nMaxLen)
702{
703 STATISTICS_ADD(SummandLength, nSrcLen);
704
705 nSrcLen = nSrcLen < nMaxLen ? nSrcLen : nMaxLen;
706
707 // concatenating an empty string is a NOP
708 if ( nSrcLen > 0 ) {
709 wxStringData *pData = GetStringData();
710 size_t nLen = pData->nDataLength;
711 size_t nNewLen = nLen + nSrcLen;
712
713 // alloc new buffer if current is too small
714 if ( pData->IsShared() ) {
715 STATISTICS_ADD(ConcatHit, 0);
716
717 // we have to allocate another buffer
718 wxStringData* pOldData = GetStringData();
719 if ( !AllocBuffer(nNewLen) ) {
720 // allocation failure handled by caller
721 return false;
722 }
81727065 723 memcpy(m_pchData, pOldData->data(), nLen*sizeof(wxStringCharType));
a7ea63e2
VS
724 pOldData->Unlock();
725 }
726 else if ( nNewLen > pData->nAllocLength ) {
727 STATISTICS_ADD(ConcatHit, 0);
728
729 reserve(nNewLen);
730 // we have to grow the buffer
731 if ( capacity() < nNewLen ) {
732 // allocation failure handled by caller
733 return false;
734 }
735 }
736 else {
737 STATISTICS_ADD(ConcatHit, 1);
738
739 // the buffer is already big enough
740 }
741
742 // should be enough space
743 wxASSERT( nNewLen <= GetStringData()->nAllocLength );
744
745 // fast concatenation - all is done in our buffer
81727065 746 memcpy(m_pchData + nLen, pszSrcData, nSrcLen*sizeof(wxStringCharType));
a7ea63e2
VS
747
748 m_pchData[nNewLen] = wxT('\0'); // put terminating '\0'
749 GetStringData()->nDataLength = nNewLen; // and fix the length
750 }
751 //else: the string to append was empty
752 return true;
753}
754
755#if !wxUSE_UNICODE_UTF8
756// get the pointer to writable buffer of (at least) nLen bytes
757wxChar *wxStringImpl::DoGetWriteBuf(size_t nLen)
758{
759 if ( !AllocBeforeWrite(nLen) ) {
760 // allocation failure handled by caller
761 return NULL;
762 }
763
764 wxASSERT( GetStringData()->nRefs == 1 );
765 GetStringData()->Validate(false);
766
767 return m_pchData;
768}
769
770// put string back in a reasonable state after GetWriteBuf
771void wxStringImpl::DoUngetWriteBuf()
772{
81727065 773 DoUngetWriteBuf(Strsize(m_pchData));
a7ea63e2
VS
774}
775
776void wxStringImpl::DoUngetWriteBuf(size_t nLen)
777{
778 wxStringData * const pData = GetStringData();
779
780 wxASSERT_MSG( nLen < pData->nAllocLength, _T("buffer overrun") );
781
782 // the strings we store are always NUL-terminated
783 pData->data()[nLen] = _T('\0');
784 pData->nDataLength = nLen;
785 pData->Validate(true);
786}
787#endif // !wxUSE_UNICODE_UTF8
788
789#endif // !wxUSE_STL_BASED_WXSTRING