1 #ifndef __ATLSIMPSTR_H__
2 #define __ATLSIMPSTR_H__
13 // Pure virtual interface
18 virtual ~IAtlStringMgr() {}
20 virtual _Ret_maybenull_
_Post_writable_byte_size_(sizeof(CStringData
) + nAllocLength
*nCharSize
)
21 CStringData
* Allocate(
22 _In_
int nAllocLength
,
27 _Inout_ CStringData
* pData
30 virtual _Ret_maybenull_
_Post_writable_byte_size_(sizeof(CStringData
) + nAllocLength
*nCharSize
)
31 CStringData
* Reallocate(
32 _Inout_ CStringData
* pData
,
33 _In_
int nAllocLength
,
37 virtual CStringData
* GetNilString(void) = 0;
38 virtual IAtlStringMgr
* Clone(void) = 0;
44 IAtlStringMgr
* pStringMgr
;
57 _InterlockedIncrement(&nRefs
);
60 void Release() throw()
62 ATLASSERT(nRefs
!= 0);
64 if (_InterlockedDecrement(&nRefs
) <= 0)
66 pStringMgr
->Free(this);
70 bool IsLocked() const throw()
75 bool IsShared() const throw()
81 class CNilStringData
:
85 CNilStringData() throw()
95 void SetManager(_In_ IAtlStringMgr
* pMgr
) throw()
97 ATLASSERT(pStringMgr
== NULL
);
106 template< typename BaseType
= char >
112 typedef LPCSTR PCXSTR
;
113 typedef wchar_t YCHAR
;
114 typedef LPWSTR PYSTR
;
115 typedef LPCWSTR PCYSTR
;
119 class ChTraitsBase
<wchar_t>
122 typedef wchar_t XCHAR
;
123 typedef LPWSTR PXSTR
;
124 typedef LPCWSTR PCXSTR
;
127 typedef LPCSTR PCYSTR
;
130 template< typename BaseType
, bool t_bMFCDLL
= false>
134 typedef typename ChTraitsBase
<BaseType
>::XCHAR XCHAR
;
135 typedef typename ChTraitsBase
<BaseType
>::PXSTR PXSTR
;
136 typedef typename ChTraitsBase
<BaseType
>::PCXSTR PCXSTR
;
137 typedef typename ChTraitsBase
<BaseType
>::YCHAR YCHAR
;
138 typedef typename ChTraitsBase
<BaseType
>::PYSTR PYSTR
;
139 typedef typename ChTraitsBase
<BaseType
>::PCYSTR PCYSTR
;
145 explicit CSimpleStringT(_Inout_ IAtlStringMgr
* pStringMgr
)
147 CStringData
* pData
= pStringMgr
->GetNilString();
151 CSimpleStringT(_In_
const CSimpleStringT
& strSrc
)
153 CStringData
* pSrcData
= strSrc
.GetData();
154 CStringData
* pNewData
= CloneData(pSrcData
);
159 _In_z_ PCXSTR pszSrc
,
160 _Inout_ IAtlStringMgr
* pStringMgr
)
162 int nLength
= StringLength(pszSrc
);
163 CStringData
* pData
= pStringMgr
->Allocate(nLength
, sizeof(XCHAR
));
165 ThrowMemoryException();
169 CopyChars(m_pszData
, nLength
, pszSrc
, nLength
);
173 _In_count_(nLength
) const XCHAR
* pchSrc
,
175 _Inout_ IAtlStringMgr
* pStringMgr
)
177 if (pchSrc
== NULL
&& nLength
!= 0)
178 ThrowInvalidArgException();
180 CStringData
* pData
= pStringMgr
->Allocate(nLength
, sizeof(XCHAR
));
183 ThrowMemoryException();
187 CopyChars(m_pszData
, nLength
, pchSrc
, nLength
);
190 ~CSimpleStringT() throw()
192 CStringData
* pData
= GetData();
196 CSimpleStringT
& operator=(_In_opt_z_ PCXSTR pszSrc
)
202 CSimpleStringT
& operator=(_In_
const CSimpleStringT
& strSrc
)
204 CStringData
* pData
= GetData();
205 CStringData
* pNewData
= strSrc
.GetData();
207 if (pNewData
!= pData
)
209 if (!pData
->IsLocked() && (pNewData
->pStringMgr
== pData
->pStringMgr
))
211 pNewData
= CloneData(pNewData
);
217 SetString(strSrc
.GetString(), strSrc
.GetLength());
224 CSimpleStringT
& operator+=(_In_
const CSimpleStringT
& strSrc
)
230 CSimpleStringT
& operator+=(_In_z_ PCXSTR pszSrc
)
236 CSimpleStringT
& operator+=(XCHAR ch
)
242 operator PCXSTR() const throw()
249 CStringData
* pOldData
= GetData();
250 IAtlStringMgr
* pStringMgr
= pOldData
->pStringMgr
;
251 if (pOldData
->nDataLength
== 0) return;
253 if (pOldData
->IsLocked())
260 CStringData
* pNewData
= pStringMgr
->GetNilString();
266 _In_count_(nLength
) PCXSTR pszSrc
,
269 UINT_PTR nOffset
= pszSrc
- GetString();
271 int nOldLength
= GetLength();
275 ATLASSERT(nLength
>= 0);
277 #if 0 // FIXME: See comment for StringLengthN below.
278 nLength
= StringLengthN(pszSrc
, nLength
);
279 if (!(INT_MAX
- nLength
>= nOldLength
))
283 int nNewLength
= nOldLength
+ nLength
;
284 PXSTR pszBuffer
= GetBuffer(nNewLength
);
285 if (nOffset
<= (UINT_PTR
)nOldLength
)
287 pszSrc
= pszBuffer
+ nOffset
;
289 CopyChars(pszBuffer
+ nOldLength
, nLength
, pszSrc
, nLength
);
290 ReleaseBufferSetLength(nNewLength
);
293 void Append(_In_z_ PCXSTR pszSrc
)
295 Append(pszSrc
, StringLength(pszSrc
));
298 void Append(_In_
const CSimpleStringT
& strSrc
)
300 Append(strSrc
.GetString(), strSrc
.GetLength());
303 void SetString(_In_opt_z_ PCXSTR pszSrc
)
305 SetString(pszSrc
, StringLength(pszSrc
));
308 void SetString(_In_reads_opt_(nLength
) PCXSTR pszSrc
,
317 UINT nOldLength
= GetLength();
318 UINT_PTR nOffset
= pszSrc
- GetString();
320 PXSTR pszBuffer
= GetBuffer(nLength
);
321 if (nOffset
<= nOldLength
)
323 CopyCharsOverlapped(pszBuffer
, GetAllocLength(),
324 pszBuffer
+ nOffset
, nLength
);
328 CopyChars(pszBuffer
, GetAllocLength(), pszSrc
, nLength
);
330 ReleaseBufferSetLength(nLength
);
336 CStringData
* pData
= GetData();
337 if (pData
->IsShared())
339 // We should fork here
340 Fork(pData
->nDataLength
);
346 _Ret_notnull_
_Post_writable_size_(nMinBufferLength
+ 1) PXSTR
GetBuffer(_In_
int nMinBufferLength
)
348 return PrepareWrite(nMinBufferLength
);
351 int GetAllocLength() const throw()
353 return GetData()->nAllocLength
;
356 int GetLength() const throw()
358 return GetData()->nDataLength
;
361 PCXSTR
GetString() const throw()
366 void ReleaseBufferSetLength(_In_
int nNewLength
)
368 ATLASSERT(nNewLength
>= 0);
369 SetLength(nNewLength
);
372 void ReleaseBuffer(_In_
int nNewLength
= -1)
375 nNewLength
= StringLength(m_pszData
);
376 ReleaseBufferSetLength(nNewLength
);
379 bool IsEmpty() const throw()
381 return (GetLength() == 0);
384 CStringData
* GetData() const throw()
386 return (reinterpret_cast<CStringData
*>(m_pszData
) - 1);
389 IAtlStringMgr
* GetManager() const throw()
391 IAtlStringMgr
* pStringMgr
= GetData()->pStringMgr
;
392 return (pStringMgr
? pStringMgr
->Clone() : NULL
);
396 friend CSimpleStringT
operator+(
397 _In_
const CSimpleStringT
& str1
,
398 _In_
const CSimpleStringT
& str2
)
400 CSimpleStringT
s(str1
.GetManager());
401 Concatenate(s
, str1
, str1
.GetLength(), str2
, str2
.GetLength());
405 friend CSimpleStringT
operator+(
406 _In_
const CSimpleStringT
& str1
,
409 CSimpleStringT
s(str1
.GetManager());
410 Concatenate(s
, str1
, str1
.GetLength(), psz2
, StringLength(psz2
));
414 friend CSimpleStringT
operator+(
416 _In_
const CSimpleStringT
& str2
)
418 CSimpleStringT
s(str2
.GetManager());
419 Concatenate(s
, psz1
, StringLength(psz1
), str2
, str2
.GetLength());
423 static void __cdecl
CopyChars(
424 _Out_writes_to_(nDestLen
, nChars
) XCHAR
* pchDest
,
425 _In_
size_t nDestLen
,
426 _In_reads_opt_(nChars
) const XCHAR
* pchSrc
,
427 _In_
int nChars
) throw()
429 memcpy(pchDest
, pchSrc
, nChars
* sizeof(XCHAR
));
432 static void __cdecl
CopyCharsOverlapped(
433 _Out_writes_to_(nDestLen
, nDestLen
) XCHAR
* pchDest
,
434 _In_
size_t nDestLen
,
435 _In_reads_(nChars
) const XCHAR
* pchSrc
,
436 _In_
int nChars
) throw()
438 memmove(pchDest
, pchSrc
, nChars
* sizeof(XCHAR
));
441 static int __cdecl
StringLength(_In_opt_z_
const char* psz
) throw()
443 if (psz
== NULL
) return 0;
444 return (int)strlen(psz
);
447 static int __cdecl
StringLength(_In_opt_z_
const wchar_t* psz
) throw()
449 if (psz
== NULL
) return 0;
450 return (int)wcslen(psz
);
453 #if 0 // For whatever reason we do not link with strnlen / wcsnlen. Please investigate!
454 // strnlen / wcsnlen are available in MSVCRT starting Vista+.
455 static int __cdecl
StringLengthN(
456 _In_opt_z_count_(sizeInXChar
) const char* psz
,
457 _In_
size_t sizeInXChar
) throw()
459 if (psz
== NULL
) return 0;
460 return (int)strnlen(psz
, sizeInXChar
);
463 static int __cdecl
StringLengthN(
464 _In_opt_z_count_(sizeInXChar
) const wchar_t* psz
,
465 _In_
size_t sizeInXChar
) throw()
467 if (psz
== NULL
) return 0;
468 return (int)wcsnlen(psz
, sizeInXChar
);
473 static void __cdecl
Concatenate(
474 _Inout_ CSimpleStringT
& strResult
,
475 _In_count_(nLength1
) PCXSTR psz1
,
477 _In_count_(nLength2
) PCXSTR psz2
,
480 int nNewLength
= nLength1
+ nLength2
;
481 PXSTR pszBuffer
= strResult
.GetBuffer(nNewLength
);
482 CopyChars(pszBuffer
, nLength1
, psz1
, nLength1
);
483 CopyChars(pszBuffer
+ nLength1
, nLength2
, psz2
, nLength2
);
484 strResult
.ReleaseBufferSetLength(nNewLength
);
488 void Attach(_Inout_ CStringData
* pData
) throw()
490 m_pszData
= static_cast<PXSTR
>(pData
->data());
493 __declspec(noinline
) void Fork(_In_
int nLength
)
495 CStringData
* pOldData
= GetData();
496 int nOldLength
= pOldData
->nDataLength
;
497 CStringData
* pNewData
= pOldData
->pStringMgr
->Clone()->Allocate(nLength
, sizeof(XCHAR
));
498 if (pNewData
== NULL
)
500 ThrowMemoryException();
502 int nCharsToCopy
= ((nOldLength
< nLength
) ? nOldLength
: nLength
) + 1;
503 CopyChars(PXSTR(pNewData
->data()), nCharsToCopy
,
504 PCXSTR(pOldData
->data()), nCharsToCopy
);
505 pNewData
->nDataLength
= nOldLength
;
510 PXSTR
PrepareWrite(_In_
int nLength
)
512 CStringData
* pOldData
= GetData();
513 int nShared
= 1 - pOldData
->nRefs
;
514 int nTooShort
= pOldData
->nAllocLength
- nLength
;
515 if ((nShared
| nTooShort
) < 0)
517 PrepareWrite2(nLength
);
522 void PrepareWrite2(_In_
int nLength
)
524 CStringData
* pOldData
= GetData();
525 if (pOldData
->nDataLength
> nLength
)
527 nLength
= pOldData
->nDataLength
;
529 if (pOldData
->IsShared())
534 else if (pOldData
->nAllocLength
< nLength
)
536 int nNewLength
= pOldData
->nAllocLength
;
537 if (nNewLength
> 1024 * 1024 * 1024)
539 nNewLength
+= 1024 * 1024;
543 nNewLength
= nNewLength
+ nNewLength
/ 2;
545 if (nNewLength
< nLength
)
547 nNewLength
= nLength
;
549 Reallocate(nNewLength
);
553 void Reallocate(_In_
int nLength
)
555 CStringData
* pOldData
= GetData();
556 ATLASSERT(pOldData
->nAllocLength
< nLength
);
557 IAtlStringMgr
* pStringMgr
= pOldData
->pStringMgr
;
558 if (pOldData
->nAllocLength
>= nLength
|| nLength
<= 0)
562 CStringData
* pNewData
= pStringMgr
->Reallocate(pOldData
, nLength
, sizeof(XCHAR
));
563 if (pNewData
== NULL
)
565 ThrowMemoryException();
571 void SetLength(_In_
int nLength
)
573 ATLASSERT(nLength
>= 0);
574 ATLASSERT(nLength
<= GetData()->nAllocLength
);
576 if (nLength
< 0 || nLength
> GetData()->nAllocLength
)
578 AtlThrow(E_INVALIDARG
);
581 GetData()->nDataLength
= nLength
;
582 m_pszData
[nLength
] = 0;
585 static CStringData
* __cdecl
CloneData(_Inout_ CStringData
* pData
)
587 CStringData
* pNewData
= NULL
;
589 IAtlStringMgr
* pNewStringMgr
= pData
->pStringMgr
->Clone();
590 if (!pData
->IsLocked() && (pNewStringMgr
== pData
->pStringMgr
))
597 pNewData
= pNewStringMgr
->Allocate(pData
->nDataLength
, sizeof(XCHAR
));
598 if (pNewData
== NULL
)
600 ThrowMemoryException();
603 pNewData
->nDataLength
= pData
->nDataLength
;
604 CopyChars(PXSTR(pNewData
->data()), pData
->nDataLength
+ 1,
605 PCXSTR(pData
->data()), pData
->nDataLength
+ 1);
612 static void ThrowMemoryException()
614 AtlThrow(E_OUTOFMEMORY
);
617 static void ThrowInvalidArgException()
619 AtlThrow(E_INVALIDARG
);
625 typedef CSimpleStringT
<WCHAR
> CSimpleString
;
627 typedef CSimpleStringT
<CHAR
> CSimpleString
;