Source code of Windows XP (NT5)
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.

371 lines
9.8 KiB

  1. //***************************************************************************
  2. //
  3. // Copyright (c) 1997-2001 Microsoft Corporation, All Rights Reserved
  4. //
  5. // ChStrArr.CPP
  6. //
  7. // Purpose: utility library version of MFC CStringArray
  8. //
  9. //***************************************************************************
  10. /////////////////////////////////////////////////////////////////////////////
  11. // NOTE: we allocate an array of 'm_nMaxSize' elements, but only
  12. // the current size 'm_nSize' contains properly constructed
  13. // objects.
  14. /////////////////////////////////////////////////////////////////////////////
  15. #include "precomp.h"
  16. #pragma warning( disable : 4290 )
  17. #include <chstring.h>
  18. #include <chstrarr.h>
  19. #include <AssertBreak.h>
  20. extern LPCWSTR afxPchNil;
  21. extern const CHString& afxGetEmptyCHString();
  22. #define afxEmptyCHString afxGetEmptyCHString()
  23. /////////////////////////////////////////////////////////////////////////////
  24. // Special implementations for CHStrings
  25. // it is faster to bit-wise copy a CHString than to call an official
  26. // constructor - since an empty CHString can be bit-wise copied
  27. /////////////////////////////////////////////////////////////////////////////
  28. static inline void ConstructElement(CHString* pNewData)
  29. {
  30. memcpy(pNewData, &afxEmptyCHString, sizeof(CHString));
  31. }
  32. /////////////////////////////////////////////////////////////////////////////
  33. static inline void DestructElement(CHString* pOldData)
  34. {
  35. pOldData->~CHString();
  36. }
  37. /////////////////////////////////////////////////////////////////////////////
  38. static inline void CopyElement(CHString* pSrc, CHString* pDest)
  39. {
  40. *pSrc = *pDest;
  41. }
  42. /////////////////////////////////////////////////////////////////////////////
  43. static void ConstructElements(CHString* pNewData, int nCount)
  44. {
  45. ASSERT_BREAK(nCount >= 0);
  46. while (nCount--)
  47. {
  48. ConstructElement(pNewData);
  49. pNewData++;
  50. }
  51. }
  52. /////////////////////////////////////////////////////////////////////////////
  53. static void DestructElements(CHString* pOldData, int nCount)
  54. {
  55. ASSERT_BREAK(nCount >= 0);
  56. while (nCount--)
  57. {
  58. DestructElement(pOldData);
  59. pOldData++;
  60. }
  61. }
  62. /////////////////////////////////////////////////////////////////////////////
  63. static void CopyElements(CHString* pDest, CHString* pSrc, int nCount)
  64. {
  65. ASSERT_BREAK(nCount >= 0);
  66. while (nCount--)
  67. {
  68. *pDest = *pSrc;
  69. ++pDest;
  70. ++pSrc;
  71. }
  72. }
  73. /////////////////////////////////////////////////////////////////////////////
  74. CHStringArray::CHStringArray() : m_pData ( NULL ) ,
  75. m_nSize ( 0 ) ,
  76. m_nMaxSize ( 0 ) ,
  77. m_nGrowBy ( 0 )
  78. {
  79. }
  80. /////////////////////////////////////////////////////////////////////////////
  81. CHStringArray::~CHStringArray()
  82. {
  83. DestructElements(m_pData, m_nSize);
  84. delete[] (BYTE*)m_pData;
  85. }
  86. /////////////////////////////////////////////////////////////////////////////
  87. void CHStringArray::SetSize(int nNewSize, int nGrowBy)
  88. {
  89. ASSERT_BREAK(nNewSize >= 0);
  90. if (nGrowBy != -1)
  91. {
  92. m_nGrowBy = nGrowBy; // set new size
  93. }
  94. if (nNewSize == 0)
  95. {
  96. // shrink to nothing
  97. DestructElements(m_pData, m_nSize);
  98. delete[] (BYTE*)m_pData;
  99. m_pData = NULL;
  100. m_nSize = m_nMaxSize = 0;
  101. }
  102. else if (m_pData == NULL)
  103. {
  104. #ifdef SIZE_T_MAX
  105. ASSERT_BREAK(nNewSize <= SIZE_T_MAX/sizeof(CHString)); // no overflow
  106. #endif
  107. // create one with exact size
  108. m_pData = (CHString*) new BYTE[nNewSize * sizeof(CHString)];
  109. if ( m_pData )
  110. {
  111. ConstructElements(m_pData, nNewSize);
  112. m_nSize = m_nMaxSize = nNewSize;
  113. }
  114. else
  115. {
  116. throw CHeap_Exception ( CHeap_Exception :: E_ALLOCATION_ERROR ) ;
  117. }
  118. }
  119. else if (nNewSize <= m_nMaxSize)
  120. {
  121. // it fits
  122. if (nNewSize > m_nSize)
  123. {
  124. // initialize the new elements
  125. ConstructElements(&m_pData[m_nSize], nNewSize-m_nSize);
  126. }
  127. else if (m_nSize > nNewSize) // destroy the old elements
  128. {
  129. DestructElements(&m_pData[nNewSize], m_nSize-nNewSize);
  130. }
  131. m_nSize = nNewSize;
  132. }
  133. else
  134. {
  135. // otherwise, grow array
  136. int nGrowBy = m_nGrowBy;
  137. if (nGrowBy == 0)
  138. {
  139. // heuristically determine growth when nGrowBy == 0
  140. // (this avoids heap fragmentation in many situations)
  141. nGrowBy = min(1024, max(4, m_nSize / 8));
  142. }
  143. int nNewMax;
  144. if (nNewSize < m_nMaxSize + nGrowBy)
  145. {
  146. nNewMax = m_nMaxSize + nGrowBy; // granularity
  147. }
  148. else
  149. {
  150. nNewMax = nNewSize; // no slush
  151. }
  152. ASSERT_BREAK(nNewMax >= m_nMaxSize); // no wrap around
  153. #ifdef SIZE_T_MAX
  154. ASSERT_BREAK(nNewMax <= SIZE_T_MAX/sizeof(CHString)); // no overflow
  155. #endif
  156. CHString* pNewData = (CHString*) new BYTE[nNewMax * sizeof(CHString)];
  157. if ( pNewData )
  158. {
  159. // copy new data from old
  160. memcpy(pNewData, m_pData, m_nSize * sizeof(CHString));
  161. // construct remaining elements
  162. ASSERT_BREAK(nNewSize > m_nSize);
  163. ConstructElements(&pNewData[m_nSize], nNewSize-m_nSize);
  164. // get rid of old stuff (note: no destructors called)
  165. delete[] (BYTE*)m_pData;
  166. m_pData = pNewData;
  167. m_nSize = nNewSize;
  168. m_nMaxSize = nNewMax;
  169. }
  170. else
  171. {
  172. throw CHeap_Exception ( CHeap_Exception :: E_ALLOCATION_ERROR ) ;
  173. }
  174. }
  175. }
  176. /////////////////////////////////////////////////////////////////////////////
  177. int CHStringArray::Append(const CHStringArray& src)
  178. {
  179. ASSERT_BREAK(this != &src); // cannot append to itself
  180. int nOldSize = m_nSize;
  181. SetSize(m_nSize + src.m_nSize);
  182. CopyElements(m_pData + nOldSize, src.m_pData, src.m_nSize);
  183. return nOldSize;
  184. }
  185. /////////////////////////////////////////////////////////////////////////////
  186. void CHStringArray::Copy(const CHStringArray& src)
  187. {
  188. ASSERT_BREAK(this != &src); // cannot append to itself
  189. SetSize(src.m_nSize);
  190. CopyElements(m_pData, src.m_pData, src.m_nSize);
  191. }
  192. /////////////////////////////////////////////////////////////////////////////
  193. void CHStringArray::FreeExtra()
  194. {
  195. if (m_nSize != m_nMaxSize)
  196. {
  197. // shrink to desired size
  198. #ifdef SIZE_T_MAX
  199. ASSERT_BREAK(m_nSize <= SIZE_T_MAX/sizeof(CHString)); // no overflow
  200. #endif
  201. CHString* pNewData = NULL;
  202. if (m_nSize != 0)
  203. {
  204. pNewData = (CHString*) new BYTE[m_nSize * sizeof(CHString)];
  205. if ( pNewData )
  206. {
  207. // copy new data from old
  208. memcpy(pNewData, m_pData, m_nSize * sizeof(CHString));
  209. }
  210. else
  211. {
  212. throw CHeap_Exception ( CHeap_Exception :: E_ALLOCATION_ERROR ) ;
  213. }
  214. }
  215. // get rid of old stuff (note: no destructors called)
  216. delete[] (BYTE*)m_pData;
  217. m_pData = pNewData;
  218. m_nMaxSize = m_nSize;
  219. }
  220. }
  221. /////////////////////////////////////////////////////////////////////////////
  222. void CHStringArray::SetAtGrow(int nIndex, LPCWSTR newElement)
  223. {
  224. ASSERT_BREAK(nIndex >= 0);
  225. if (nIndex >= m_nSize)
  226. {
  227. SetSize(nIndex+1);
  228. }
  229. m_pData[nIndex] = newElement;
  230. }
  231. /////////////////////////////////////////////////////////////////////////////
  232. void CHStringArray::InsertAt(int nIndex, LPCWSTR newElement, int nCount)
  233. {
  234. ASSERT_BREAK(nIndex >= 0); // will expand to meet need
  235. ASSERT_BREAK(nCount > 0); // zero or negative size not allowed
  236. if (nIndex >= m_nSize)
  237. {
  238. // adding after the end of the array
  239. SetSize(nIndex + nCount); // grow so nIndex is valid
  240. }
  241. else
  242. {
  243. // inserting in the middle of the array
  244. int nOldSize = m_nSize;
  245. SetSize(m_nSize + nCount); // grow it to new size
  246. // shift old data up to fill gap
  247. memmove(&m_pData[nIndex+nCount], &m_pData[nIndex],
  248. (nOldSize-nIndex) * sizeof(CHString));
  249. // re-init slots we copied from
  250. ConstructElements(&m_pData[nIndex], nCount);
  251. }
  252. // insert new value in the gap
  253. ASSERT_BREAK(nIndex + nCount <= m_nSize);
  254. while (nCount--)
  255. {
  256. m_pData[nIndex++] = newElement;
  257. }
  258. }
  259. /////////////////////////////////////////////////////////////////////////////
  260. void CHStringArray::RemoveAt(int nIndex, int nCount)
  261. {
  262. ASSERT_BREAK(nIndex >= 0);
  263. ASSERT_BREAK(nCount >= 0);
  264. ASSERT_BREAK(nIndex + nCount <= m_nSize);
  265. // just remove a range
  266. int nMoveCount = m_nSize - (nIndex + nCount);
  267. DestructElements(&m_pData[nIndex], nCount);
  268. if (nMoveCount)
  269. {
  270. memcpy(&m_pData[nIndex], &m_pData[nIndex + nCount],
  271. nMoveCount * sizeof(CHString));
  272. }
  273. m_nSize -= nCount;
  274. }
  275. /////////////////////////////////////////////////////////////////////////////
  276. void CHStringArray::InsertAt(int nStartIndex, CHStringArray* pNewArray)
  277. {
  278. ASSERT_BREAK(pNewArray != NULL);
  279. ASSERT_BREAK(nStartIndex >= 0);
  280. if (pNewArray->GetSize() > 0)
  281. {
  282. InsertAt(nStartIndex, pNewArray->GetAt(0), pNewArray->GetSize());
  283. for (int i = 0; i < pNewArray->GetSize(); i++)
  284. {
  285. SetAt(nStartIndex + i, pNewArray->GetAt(i));
  286. }
  287. }
  288. }
  289. #if (defined DEBUG || defined _DEBUG)
  290. CHString CHStringArray::GetAt(int nIndex) const
  291. {
  292. ASSERT_BREAK(nIndex >= 0 && nIndex < m_nSize);
  293. return m_pData[nIndex];
  294. }
  295. void CHStringArray::SetAt(int nIndex, LPCWSTR newElement)
  296. {
  297. ASSERT_BREAK(nIndex >= 0 && nIndex < m_nSize);
  298. m_pData[nIndex] = newElement;
  299. }
  300. CHString& CHStringArray::ElementAt(int nIndex)
  301. {
  302. ASSERT_BREAK(nIndex >= 0 && nIndex < m_nSize);
  303. return m_pData[nIndex];
  304. }
  305. #endif