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
));
166 throw; // ThrowMemoryException();
170 CopyChars(m_pszData
, nLength
, pszSrc
, nLength
);
174 _In_count_(nLength
) const XCHAR
* pchSrc
,
176 _Inout_ IAtlStringMgr
* pStringMgr
)
178 if (pchSrc
== NULL
&& nLength
!= 0)
181 CStringData
* pData
= pStringMgr
->Allocate(nLength
, sizeof(XCHAR
));
184 throw; // ThrowMemoryException();
188 CopyChars(m_pszData
, nLength
, pchSrc
, nLength
);
191 ~CSimpleStringT() throw()
193 CStringData
* pData
= GetData();
197 CSimpleStringT
& operator=(_In_opt_z_ PCXSTR pszSrc
)
203 CSimpleStringT
& operator=(_In_
const CSimpleStringT
& strSrc
)
205 CStringData
* pData
= GetData();
206 CStringData
* pNewData
= strSrc
.GetData();
208 if (pNewData
!= pData
)
210 if (!pData
->IsLocked() && (pNewData
->pStringMgr
== pData
->pStringMgr
))
212 pNewData
= CloneData(pNewData
);
218 SetString(strSrc
.GetString(), strSrc
.GetLength());
225 CSimpleStringT
& operator+=(_In_
const CSimpleStringT
& strSrc
)
231 CSimpleStringT
& operator+=(_In_z_ PCXSTR pszSrc
)
237 CSimpleStringT
& operator+=(XCHAR ch
)
243 operator PCXSTR() const throw()
250 CStringData
* pOldData
= GetData();
251 IAtlStringMgr
* pStringMgr
= pOldData
->pStringMgr
;
252 if (pOldData
->nDataLength
== 0) return;
254 if (pOldData
->IsLocked())
261 CStringData
* pNewData
= pStringMgr
->GetNilString();
267 _In_count_(nLength
) PCXSTR pszSrc
,
270 UINT_PTR nOffset
= pszSrc
- GetString();
272 int nOldLength
= GetLength();
276 ATLASSERT(nLength
>= 0);
278 #if 0 // FIXME: See comment for StringLengthN below.
279 nLength
= StringLengthN(pszSrc
, nLength
);
280 if (!(INT_MAX
- nLength
>= nOldLength
))
284 int nNewLength
= nOldLength
+ nLength
;
285 PXSTR pszBuffer
= GetBuffer(nNewLength
);
286 if (nOffset
<= (UINT_PTR
)nOldLength
)
288 pszSrc
= pszBuffer
+ nOffset
;
290 CopyChars(pszBuffer
+ nOldLength
, nLength
, pszSrc
, nLength
);
291 ReleaseBufferSetLength(nNewLength
);
294 void Append(_In_z_ PCXSTR pszSrc
)
296 Append(pszSrc
, StringLength(pszSrc
));
299 void Append(_In_
const CSimpleStringT
& strSrc
)
301 Append(strSrc
.GetString(), strSrc
.GetLength());
304 void SetString(_In_opt_z_ PCXSTR pszSrc
)
306 SetString(pszSrc
, StringLength(pszSrc
));
309 void SetString(_In_reads_opt_(nLength
) PCXSTR pszSrc
,
318 UINT nOldLength
= GetLength();
319 UINT_PTR nOffset
= pszSrc
- GetString();
321 PXSTR pszBuffer
= GetBuffer(nLength
);
322 if (nOffset
<= nOldLength
)
324 CopyCharsOverlapped(pszBuffer
, GetAllocLength(),
325 pszBuffer
+ nOffset
, nLength
);
329 CopyChars(pszBuffer
, GetAllocLength(), pszSrc
, nLength
);
331 ReleaseBufferSetLength(nLength
);
337 CStringData
* pData
= GetData();
338 if (pData
->IsShared())
340 // We should fork here
341 Fork(pData
->nDataLength
);
347 _Ret_notnull_
_Post_writable_size_(nMinBufferLength
+ 1) PXSTR
GetBuffer(_In_
int nMinBufferLength
)
349 return PrepareWrite(nMinBufferLength
);
352 int GetAllocLength() const throw()
354 return GetData()->nAllocLength
;
357 int GetLength() const throw()
359 return GetData()->nDataLength
;
362 PCXSTR
GetString() const throw()
367 void ReleaseBufferSetLength(_In_
int nNewLength
)
369 ATLASSERT(nNewLength
>= 0);
370 SetLength(nNewLength
);
373 void ReleaseBuffer(_In_
int nNewLength
= -1)
376 nNewLength
= StringLength(m_pszData
);
377 ReleaseBufferSetLength(nNewLength
);
380 bool IsEmpty() const throw()
382 return (GetLength() == 0);
385 CStringData
* GetData() const throw()
387 return (reinterpret_cast<CStringData
*>(m_pszData
) - 1);
390 IAtlStringMgr
* GetManager() const throw()
392 IAtlStringMgr
* pStringMgr
= GetData()->pStringMgr
;
393 return (pStringMgr
? pStringMgr
->Clone() : NULL
);
397 friend CSimpleStringT
operator+(
398 _In_
const CSimpleStringT
& str1
,
399 _In_
const CSimpleStringT
& str2
)
401 CSimpleStringT
s(str1
.GetManager());
402 Concatenate(s
, str1
, str1
.GetLength(), str2
, str2
.GetLength());
406 friend CSimpleStringT
operator+(
407 _In_
const CSimpleStringT
& str1
,
410 CSimpleStringT
s(str1
.GetManager());
411 Concatenate(s
, str1
, str1
.GetLength(), psz2
, StringLength(psz2
));
415 friend CSimpleStringT
operator+(
417 _In_
const CSimpleStringT
& str2
)
419 CSimpleStringT
s(str2
.GetManager());
420 Concatenate(s
, psz1
, StringLength(psz1
), str2
, str2
.GetLength());
424 static void __cdecl
CopyChars(
425 _Out_writes_to_(nDestLen
, nChars
) XCHAR
* pchDest
,
426 _In_
size_t nDestLen
,
427 _In_reads_opt_(nChars
) const XCHAR
* pchSrc
,
428 _In_
int nChars
) throw()
430 memcpy(pchDest
, pchSrc
, nChars
* sizeof(XCHAR
));
433 static void __cdecl
CopyCharsOverlapped(
434 _Out_writes_to_(nDestLen
, nDestLen
) XCHAR
* pchDest
,
435 _In_
size_t nDestLen
,
436 _In_reads_(nChars
) const XCHAR
* pchSrc
,
437 _In_
int nChars
) throw()
439 memmove(pchDest
, pchSrc
, nChars
* sizeof(XCHAR
));
442 static int __cdecl
StringLength(_In_opt_z_
const char* psz
) throw()
444 if (psz
== NULL
) return 0;
445 return (int)strlen(psz
);
448 static int __cdecl
StringLength(_In_opt_z_
const wchar_t* psz
) throw()
450 if (psz
== NULL
) return 0;
451 return (int)wcslen(psz
);
454 #if 0 // For whatever reason we do not link with strnlen / wcsnlen. Please investigate!
455 // strnlen / wcsnlen are available in MSVCRT starting Vista+.
456 static int __cdecl
StringLengthN(
457 _In_opt_z_count_(sizeInXChar
) const char* psz
,
458 _In_
size_t sizeInXChar
) throw()
460 if (psz
== NULL
) return 0;
461 return (int)strnlen(psz
, sizeInXChar
);
464 static int __cdecl
StringLengthN(
465 _In_opt_z_count_(sizeInXChar
) const wchar_t* psz
,
466 _In_
size_t sizeInXChar
) throw()
468 if (psz
== NULL
) return 0;
469 return (int)wcsnlen(psz
, sizeInXChar
);
474 static void __cdecl
Concatenate(
475 _Inout_ CSimpleStringT
& strResult
,
476 _In_count_(nLength1
) PCXSTR psz1
,
478 _In_count_(nLength2
) PCXSTR psz2
,
481 int nNewLength
= nLength1
+ nLength2
;
482 PXSTR pszBuffer
= strResult
.GetBuffer(nNewLength
);
483 CopyChars(pszBuffer
, nLength1
, psz1
, nLength1
);
484 CopyChars(pszBuffer
+ nLength1
, nLength2
, psz2
, nLength2
);
485 strResult
.ReleaseBufferSetLength(nNewLength
);
489 void Attach(_Inout_ CStringData
* pData
) throw()
491 m_pszData
= static_cast<PXSTR
>(pData
->data());
494 __declspec(noinline
) void Fork(_In_
int nLength
)
496 CStringData
* pOldData
= GetData();
497 int nOldLength
= pOldData
->nDataLength
;
498 CStringData
* pNewData
= pOldData
->pStringMgr
->Clone()->Allocate(nLength
, sizeof(XCHAR
));
499 if (pNewData
== NULL
)
501 ThrowMemoryException();
503 int nCharsToCopy
= ((nOldLength
< nLength
) ? nOldLength
: nLength
) + 1;
504 CopyChars(PXSTR(pNewData
->data()), nCharsToCopy
,
505 PCXSTR(pOldData
->data()), nCharsToCopy
);
506 pNewData
->nDataLength
= nOldLength
;
511 PXSTR
PrepareWrite(_In_
int nLength
)
513 CStringData
* pOldData
= GetData();
514 int nShared
= 1 - pOldData
->nRefs
;
515 int nTooShort
= pOldData
->nAllocLength
- nLength
;
516 if ((nShared
| nTooShort
) < 0)
518 PrepareWrite2(nLength
);
523 void PrepareWrite2(_In_
int nLength
)
525 CStringData
* pOldData
= GetData();
526 if (pOldData
->nDataLength
> nLength
)
528 nLength
= pOldData
->nDataLength
;
530 if (pOldData
->IsShared())
535 else if (pOldData
->nAllocLength
< nLength
)
537 int nNewLength
= pOldData
->nAllocLength
;
538 if (nNewLength
> 1024 * 1024 * 1024)
540 nNewLength
+= 1024 * 1024;
544 nNewLength
= nNewLength
+ nNewLength
/ 2;
546 if (nNewLength
< nLength
)
548 nNewLength
= nLength
;
550 Reallocate(nNewLength
);
554 void Reallocate(_In_
int nLength
)
556 CStringData
* pOldData
= GetData();
557 ATLASSERT(pOldData
->nAllocLength
< nLength
);
558 IAtlStringMgr
* pStringMgr
= pOldData
->pStringMgr
;
559 if (pOldData
->nAllocLength
>= nLength
|| nLength
<= 0)
563 CStringData
* pNewData
= pStringMgr
->Reallocate(pOldData
, nLength
, sizeof(XCHAR
));
564 if (pNewData
== NULL
)
566 ThrowMemoryException();
572 void SetLength(_In_
int nLength
)
574 ATLASSERT(nLength
>= 0);
575 ATLASSERT(nLength
<= GetData()->nAllocLength
);
577 if (nLength
< 0 || nLength
> GetData()->nAllocLength
)
579 AtlThrow(E_INVALIDARG
);
582 GetData()->nDataLength
= nLength
;
583 m_pszData
[nLength
] = 0;
586 static CStringData
* __cdecl
CloneData(_Inout_ CStringData
* pData
)
588 CStringData
* pNewData
= NULL
;
590 IAtlStringMgr
* pNewStringMgr
= pData
->pStringMgr
->Clone();
591 if (!pData
->IsLocked() && (pNewStringMgr
== pData
->pStringMgr
))
598 pNewData
= pNewStringMgr
->Allocate(pData
->nDataLength
, sizeof(XCHAR
));
599 if (pNewData
== NULL
)
601 ThrowMemoryException();
604 pNewData
->nDataLength
= pData
->nDataLength
;
605 CopyChars(PXSTR(pNewData
->data()), pData
->nDataLength
+ 1,
606 PCXSTR(pData
->data()), pData
->nDataLength
+ 1);
613 static void ThrowMemoryException()
615 AtlThrow(E_OUTOFMEMORY
);
621 typedef CSimpleStringT
<WCHAR
> CSimpleString
;
623 typedef CSimpleStringT
<CHAR
> CSimpleString
;