Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

539 lines
13 KiB

  1. /*++
  2. Copyright (c) 1985 - 1999, Microsoft Corporation
  3. Module Name:
  4. cstring.h
  5. Abstract:
  6. This file defines the CString Class.
  7. and CMapStringToOb<VALUE, ARG_VALUE> template class.
  8. Author:
  9. Revision History:
  10. Notes:
  11. --*/
  12. #ifndef _CSTRING_H_
  13. #define _CSTRING_H_
  14. #include "template.h"
  15. /////////////////////////////////////////////////////////////////////////////
  16. // Globals
  17. extern TCHAR afxChNil;
  18. extern LPCTSTR _afxPchNil;
  19. #define afxEmptyString ((CString&)*(CString*)&_afxPchNil)
  20. /////////////////////////////////////////////////////////////////////////////
  21. // CStringData
  22. struct CStringData
  23. {
  24. long nRefs; // reference count
  25. int nDataLength; // length of data (including terminator)
  26. int nAllocLength; // length of allocation
  27. // TCHAR data[nAllocLength]
  28. TCHAR* data() // TCHAR* to managed data
  29. {
  30. return (TCHAR*)(this+1);
  31. }
  32. };
  33. /////////////////////////////////////////////////////////////////////////////
  34. // CString
  35. class CString
  36. {
  37. public:
  38. // Constructors
  39. // constructs empty CString
  40. CString();
  41. // copy constructor
  42. CString(const CString& stringSrc);
  43. // from an ANSI string (converts to TCHAR)
  44. CString(LPCSTR lpsz);
  45. // subset of characters from an ANSI string (converts to TCHAR)
  46. CString(LPCSTR lpch, int nLength);
  47. // return pointer to const string
  48. operator LPCTSTR() const;
  49. // overloaded assignment
  50. // ref-counted copy from another CString
  51. const CString& operator=(const CString& stringSrc);
  52. // set string content to single character
  53. const CString& operator=(TCHAR ch);
  54. // copy string content from ANSI string (converts to TCHAR)
  55. const CString& operator=(LPCSTR lpsz);
  56. // Attributes & Operations
  57. // string comparison
  58. // straight character comparison
  59. int Compare(LPCTSTR lpsz) const;
  60. // compare ignoring case
  61. int CompareNoCase(LPCTSTR lpsz) const;
  62. // simple sub-string extraction
  63. // return nCount characters starting at zero-based nFirst
  64. CString Mid(int nFirst, int nCount) const;
  65. // return all characters starting at zero-based nFirst
  66. CString Mid(int nFirst) const;
  67. // searching
  68. // find character starting at left, -1 if not found
  69. int Find(TCHAR ch) const;
  70. // find character starting at zero-based index and going right
  71. int Find(TCHAR ch, int nStart) const;
  72. // Implementation
  73. public:
  74. ~CString();
  75. private:
  76. LPTSTR m_pchData; // pointer to ref counted string data
  77. // implementation helpers
  78. CStringData* GetData() const;
  79. void Init();
  80. void AllocCopy(CString& dest, int nCopyLen, int nCopyIndex, int nExtraLen) const;
  81. void AllocBuffer(int nLen);
  82. void AssignCopy(int nSrcLen, LPCTSTR lpszSrcData);
  83. void AllocBeforeWrite(int nLen);
  84. void Release();
  85. static void PASCAL Release(CStringData* pData);
  86. static int PASCAL SafeStrlen(LPCTSTR lpsz);
  87. static void FreeData(CStringData* pData);
  88. };
  89. inline
  90. CStringData*
  91. CString::GetData(
  92. ) const
  93. {
  94. ASSERT(m_pchData != NULL);
  95. return ((CStringData*)m_pchData)-1;
  96. }
  97. inline
  98. void
  99. CString::Init(
  100. )
  101. {
  102. m_pchData = afxEmptyString.m_pchData;
  103. }
  104. // Compare helpers
  105. bool operator==(const CString& s1, const CString& s2);
  106. bool operator==(const CString& s1, LPCTSTR s2);
  107. bool operator==(LPCTSTR s1, const CString& s2);
  108. /////////////////////////////////////////////////////////////////////////////
  109. // Special implementation for CStrings
  110. // it is faster to bit-wise copy a CString than to call an offical
  111. // constructor - since an empty CString can be bit-wise copied
  112. static
  113. void
  114. ConstructElement(
  115. CString* pNewData
  116. )
  117. {
  118. memcpy(pNewData, &afxEmptyString, sizeof(CString));
  119. }
  120. static
  121. void
  122. DestructElement(
  123. CString* pOldData
  124. )
  125. {
  126. pOldData->~CString();
  127. }
  128. /////////////////////////////////////////////////////////////////////////////
  129. // CMapStringToOb<VALUE, ARG_VALUE>
  130. template<class VALUE, class ARG_VALUE>
  131. class CMapStringToOb
  132. {
  133. public:
  134. CMapStringToOb(int nBlockSize = 10);
  135. ~CMapStringToOb();
  136. INT_PTR GetCount() const;
  137. BOOL Lookup(LPCTSTR key, VALUE& rValue) const;
  138. VALUE& operator[](LPCTSTR key);
  139. void SetAt(LPCTSTR key, ARG_VALUE newValue);
  140. BOOL RemoveKey(LPCTSTR key);
  141. void RemoveAll();
  142. POSITION GetStartPosition() const;
  143. void GetNextAssoc(POSITION& rNextPosition, CString& rKey, VALUE& rValue) const;
  144. void InitHashTable(UINT hashSize, BOOL bAllocNow = TRUE);
  145. protected:
  146. // Overridables: special non-virtual (see map implementation for details)
  147. // Routine used to user-provided hash keys
  148. UINT HashKey(LPCTSTR key) const;
  149. private:
  150. // Association
  151. struct CAssoc {
  152. CAssoc* pNext;
  153. UINT nHashValue; // needed for efficient iteration
  154. CString key;
  155. VALUE value;
  156. };
  157. private:
  158. CAssoc* NewAssoc();
  159. void FreeAssoc(CAssoc*);
  160. CAssoc* GetAssocAt(LPCTSTR, UINT&) const;
  161. private:
  162. CAssoc** m_pHashTable;
  163. UINT m_nHashTableSize;
  164. INT_PTR m_nCount;
  165. CAssoc* m_pFreeList;
  166. struct CPlex* m_pBlocks;
  167. int m_nBlockSize;
  168. };
  169. template<class VALUE, class ARG_VALUE>
  170. INT_PTR
  171. CMapStringToOb<VALUE, ARG_VALUE>::GetCount(
  172. ) const
  173. {
  174. return m_nCount;
  175. }
  176. template<class VALUE, class ARG_VALUE>
  177. void
  178. CMapStringToOb<VALUE, ARG_VALUE>::SetAt(
  179. LPCTSTR key,
  180. ARG_VALUE newValue
  181. )
  182. {
  183. (*this)[key] = newValue;
  184. }
  185. template<class VALUE, class ARG_VALUE>
  186. CMapStringToOb<VALUE, ARG_VALUE>::CMapStringToOb(
  187. int nBlockSize
  188. )
  189. {
  190. ASSERT(nBlockSize > 0);
  191. m_pHashTable = NULL;
  192. m_nHashTableSize = 17; // default size
  193. m_nCount = 0;
  194. m_pFreeList = NULL;
  195. m_pBlocks = NULL;
  196. m_nBlockSize = nBlockSize;
  197. }
  198. template<class VALUE, class ARG_VALUE>
  199. UINT
  200. CMapStringToOb<VALUE, ARG_VALUE>::HashKey(
  201. LPCTSTR key
  202. ) const
  203. {
  204. UINT nHash = 0;
  205. while (*key)
  206. nHash = (nHash<<5) + nHash + *key++;
  207. return nHash;
  208. }
  209. template<class VALUE, class ARG_VALUE>
  210. void
  211. CMapStringToOb<VALUE, ARG_VALUE>::InitHashTable(
  212. UINT nHashSize,
  213. BOOL bAllocNow
  214. )
  215. {
  216. ASSERT(m_nCount == 0);
  217. ASSERT(nHashSize > 0);
  218. if (m_pHashTable != NULL) {
  219. // free hash table
  220. delete[] m_pHashTable;
  221. m_pHashTable = NULL;
  222. }
  223. if (bAllocNow) {
  224. m_pHashTable = new CAssoc* [nHashSize];
  225. memset(m_pHashTable, 0, sizeof(CAssoc*) * nHashSize);
  226. }
  227. m_nHashTableSize = nHashSize;
  228. }
  229. template<class VALUE, class ARG_VALUE>
  230. void
  231. CMapStringToOb<VALUE, ARG_VALUE>::RemoveAll(
  232. )
  233. {
  234. if (m_pHashTable != NULL) {
  235. // destroy elements (values and keys)
  236. for (UINT nHash = 0; nHash < m_nHashTableSize; nHash++) {
  237. CAssoc* pAssoc;
  238. for (pAssoc = m_pHashTable[nHash]; pAssoc != NULL; pAssoc = pAssoc->pNext) {
  239. DestructElements<VALUE>(&pAssoc->value, 1);
  240. DestructElement(&pAssoc->key); // free up string data
  241. }
  242. }
  243. }
  244. // free hash table
  245. delete[] m_pHashTable;
  246. m_pHashTable = NULL;
  247. m_nCount = 0;
  248. m_pFreeList = NULL;
  249. m_pBlocks->FreeDataChain();
  250. m_pBlocks = NULL;
  251. }
  252. template<class VALUE, class ARG_VALUE>
  253. CMapStringToOb<VALUE, ARG_VALUE>::~CMapStringToOb(
  254. )
  255. {
  256. RemoveAll();
  257. ASSERT(m_nCount == 0);
  258. }
  259. template<class VALUE, class ARG_VALUE>
  260. typename CMapStringToOb<VALUE, ARG_VALUE>::CAssoc*
  261. CMapStringToOb<VALUE, ARG_VALUE>::NewAssoc(
  262. )
  263. {
  264. if (m_pFreeList == NULL) {
  265. // add another block
  266. CPlex* newBlock = CPlex::Create(m_pBlocks, m_nBlockSize, sizeof(CMapStringToOb::CAssoc));
  267. // chain them into free list;
  268. CMapStringToOb::CAssoc* pAssoc = (CMapStringToOb::CAssoc*) newBlock->data();
  269. // free in reverse order to make it easier to debug
  270. pAssoc += m_nBlockSize - 1;
  271. for (int i = m_nBlockSize-1; i >= 0; i--, pAssoc--) {
  272. pAssoc->pNext = m_pFreeList;
  273. m_pFreeList = pAssoc;
  274. }
  275. }
  276. ASSERT(m_pFreeList != NULL); // we must have something
  277. CMapStringToOb::CAssoc* pAssoc = m_pFreeList;
  278. m_pFreeList = m_pFreeList->pNext;
  279. m_nCount++;
  280. ASSERT(m_nCount > 0); // make sure we don't overflow
  281. memcpy(&pAssoc->key, &afxEmptyString, sizeof(CString));
  282. ConstructElements<VALUE>(&pAssoc->value, 1); // special construct values
  283. return pAssoc;
  284. }
  285. template<class VALUE, class ARG_VALUE>
  286. void
  287. CMapStringToOb<VALUE, ARG_VALUE>::FreeAssoc(
  288. CAssoc* pAssoc
  289. )
  290. {
  291. DestructElements<VALUE>(&pAssoc->value, 1);
  292. DestructElement(&pAssoc->key); // free up string data
  293. pAssoc->pNext = m_pFreeList;
  294. m_pFreeList = pAssoc;
  295. m_nCount--;
  296. ASSERT(m_nCount >= 0); // make sure we don't underflow
  297. // if no more elements, cleanup completely
  298. if (m_nCount == 0)
  299. RemoveAll();
  300. }
  301. template<class VALUE, class ARG_VALUE>
  302. typename CMapStringToOb<VALUE, ARG_VALUE>::CAssoc*
  303. CMapStringToOb<VALUE, ARG_VALUE>::GetAssocAt(
  304. LPCTSTR key,
  305. UINT& nHash
  306. ) const
  307. {
  308. nHash = HashKey(key) % m_nHashTableSize;
  309. if (m_pHashTable == NULL)
  310. return NULL;
  311. // see if it exists
  312. CAssoc* pAssoc;
  313. for (pAssoc = m_pHashTable[nHash]; pAssoc != NULL; pAssoc = pAssoc->pNext) {
  314. if (pAssoc->key == key)
  315. return pAssoc;
  316. }
  317. return NULL;
  318. }
  319. template<class VALUE, class ARG_VALUE>
  320. BOOL
  321. CMapStringToOb<VALUE, ARG_VALUE>::Lookup(
  322. LPCTSTR key,
  323. VALUE& rValue
  324. ) const
  325. {
  326. UINT nHash;
  327. CAssoc* pAssoc = GetAssocAt(key, nHash);
  328. if (pAssoc == NULL)
  329. return FALSE; // not in map
  330. rValue = pAssoc->value;
  331. return TRUE;
  332. }
  333. template<class VALUE, class ARG_VALUE>
  334. VALUE&
  335. CMapStringToOb<VALUE, ARG_VALUE>::operator[](
  336. LPCTSTR key
  337. )
  338. {
  339. UINT nHash;
  340. CAssoc* pAssoc;
  341. if ((pAssoc = GetAssocAt(key, nHash)) == NULL) {
  342. if (m_pHashTable == NULL)
  343. InitHashTable(m_nHashTableSize);
  344. // it doesn't exist, add a new Association
  345. pAssoc = NewAssoc();
  346. pAssoc->nHashValue = nHash;
  347. pAssoc->key = key;
  348. // 'pAssoc->value' is a constructed object, nothing more
  349. // put into hash table
  350. pAssoc->pNext = m_pHashTable[nHash];
  351. m_pHashTable[nHash] = pAssoc;
  352. }
  353. return pAssoc->value; // return new reference
  354. }
  355. template<class VALUE, class ARG_VALUE>
  356. BOOL
  357. CMapStringToOb<VALUE, ARG_VALUE>::RemoveKey(
  358. LPCTSTR key
  359. )
  360. {
  361. if (m_pHashTable == NULL)
  362. return FALSE; // nothing in the table
  363. CAssoc** ppAssocPrev;
  364. ppAssocPrev = &m_pHashTable[HashKey(key) % m_nHashTableSize];
  365. CAssoc* pAssoc;
  366. for (pAssoc = *ppAssocPrev; pAssoc != NULL; pAssoc = pAssoc->pNext) {
  367. if (pAssoc->key == key)) {
  368. // remove it
  369. *ppAssocPrev = pAssoc->pNext; // remove from list
  370. FreeAssoc(pAssoc);
  371. return TRUE;
  372. }
  373. ppAssocPrev = &pAssoc->pNext;
  374. }
  375. return FALSE; // not found
  376. }
  377. template<class VALUE, class ARG_VALUE>
  378. POSITION
  379. CMapStringToOb<VALUE, ARG_VALUE>::GetStartPosition(
  380. ) const
  381. {
  382. return (m_nCount == 0) ? NULL : BEFORE_START_POSITION;
  383. }
  384. template<class VALUE, class ARG_VALUE>
  385. void
  386. CMapStringToOb<VALUE, ARG_VALUE>::GetNextAssoc(
  387. POSITION& rNextPosition,
  388. CString& rKey,
  389. VALUE& rValue
  390. ) const
  391. {
  392. ASSERT(m_pHashTable != NULL); // never call on empty map
  393. CAssoc* pAssocRet = (CAssoc*)rNextPosition;
  394. ASSERT(pAssocRet != NULL);
  395. if (pAssocRet == (CAssoc*) BEFORE_START_POSITION) {
  396. // find the first association
  397. for (UINT nBucket = 0; nBucket < m_nHashTableSize; nBucket++)
  398. if ((pAssocRet = m_pHashTable[nBucket]) != NULL)
  399. break;
  400. ASSERT(pAssocRet != NULL); // must find something
  401. }
  402. // find next association
  403. CAssoc* pAssocNext;
  404. if ((pAssocNext = pAssocRet->pNext) == NULL) {
  405. // go to next bucket
  406. for (UINT nBucket = pAssocRet->nHashValue + 1; nBucket < m_nHashTableSize; nBucket++)
  407. if ((pAssocNext = m_pHashTable[nBucket]) != NULL)
  408. break;
  409. }
  410. rNextPosition = (POSITION) pAssocNext;
  411. // fill in return data
  412. rKey = pAssocRet->key;
  413. rValue = pAssocRet->value;
  414. }
  415. #endif // _CSTRING_H_