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.

828 lines
22 KiB

  1. /*++
  2. Copyright (C) 1996-2001 Microsoft Corporation
  3. Module Name:
  4. FLEXARRAY.CPP
  5. Abstract:
  6. CFlexArray and CWStringArray implementation.
  7. These objects can operate from any allocator, and be constructed
  8. on arbitrary memory blocks.
  9. History:
  10. 11-Apr-96 a-raymcc Created.
  11. 24-Apr-96 a-raymcc Updated for CArena support.
  12. --*/
  13. #include "precomp.h"
  14. #include <stdio.h>
  15. #include <WT_flexarry.h>
  16. #include "WT_strutils.h"
  17. class CX_MemoryException
  18. {
  19. };
  20. //***************************************************************************
  21. //
  22. // CFlexArray::CFlexArray
  23. //
  24. // Constructs the array.
  25. //
  26. // Parameters:
  27. // <nSize> The starting preallocated size of the array.
  28. // <nGrowBy> The amount to grow by when the array fills up.
  29. //
  30. // Size() returns the number of elements in use, not the 'true' size.
  31. //
  32. //***************************************************************************
  33. // ok
  34. CFlexArray::CFlexArray(
  35. int nSize,
  36. int nGrowByPercent
  37. )
  38. {
  39. m_nExtent = nSize;
  40. m_nSize = 0;
  41. m_nGrowByPercent = nGrowByPercent;
  42. if(nSize > 0)
  43. {
  44. m_pArray =
  45. (void**)HeapAlloc(GetProcessHeap(), 0, sizeof(void *) * nSize);
  46. // Check for allocation failures
  47. if ( NULL == m_pArray )
  48. {
  49. throw CX_MemoryException();
  50. }
  51. }
  52. else
  53. m_pArray = NULL;
  54. }
  55. //***************************************************************************
  56. //
  57. // CFlexArray::~CFlexArray
  58. //
  59. //***************************************************************************
  60. // ok
  61. CFlexArray::~CFlexArray()
  62. {
  63. HeapFree(GetProcessHeap(), 0, m_pArray);
  64. }
  65. //***************************************************************************
  66. //
  67. // Copy constructor.
  68. //
  69. // Copies the pointers, not their contents.
  70. //
  71. //***************************************************************************
  72. // ok
  73. CFlexArray::CFlexArray(CFlexArray &Src)
  74. {
  75. m_pArray = 0;
  76. m_nSize = 0;
  77. m_nExtent = 0;
  78. m_nGrowByPercent = 0;
  79. *this = Src;
  80. }
  81. //***************************************************************************
  82. //
  83. // operator =
  84. //
  85. // Assignment operator.
  86. //
  87. // Arenas are not copied. This allows transfer of arrays between arenas.
  88. // Arrays are copied by pointer only.
  89. //
  90. //***************************************************************************
  91. // ok
  92. CFlexArray& CFlexArray::operator=(CFlexArray &Src)
  93. {
  94. m_nSize = Src.m_nSize;
  95. m_nExtent = Src.m_nExtent;
  96. m_nGrowByPercent = Src.m_nGrowByPercent;
  97. HeapFree(GetProcessHeap(), 0, m_pArray);
  98. if(m_nExtent > 0)
  99. {
  100. m_pArray =
  101. (void**)HeapAlloc(GetProcessHeap(), 0, sizeof(void *) * m_nExtent);
  102. // Check for allocation failures
  103. if ( NULL == m_pArray )
  104. {
  105. throw CX_MemoryException();
  106. }
  107. }
  108. else
  109. m_pArray = NULL;
  110. memcpy(m_pArray, Src.m_pArray, sizeof(void *) * m_nSize);
  111. return *this;
  112. }
  113. //***************************************************************************
  114. //
  115. // CFlexArray::RemoveAt
  116. //
  117. // Removes the element at the specified location. Does not
  118. // actually delete the pointer. Shrinks the array over the top of
  119. // the 'doomed' element.
  120. //
  121. // Parameters:
  122. // <nIndex> The location of the element.
  123. //
  124. // Return value:
  125. // range_error The index is not legal.
  126. // no_error Success.
  127. //
  128. //***************************************************************************
  129. // ok
  130. int CFlexArray::RemoveAt(int nIndex)
  131. {
  132. if (nIndex >= m_nSize)
  133. return range_error;
  134. // Account for the index being 0 based and size being 1 based
  135. MoveMemory( &m_pArray[nIndex], &m_pArray[nIndex+1], ( ( m_nSize - nIndex ) - 1 ) * sizeof(void *) );
  136. m_nSize--;
  137. m_pArray[m_nSize] = 0;
  138. return no_error;
  139. }
  140. int CFlexArray::EnsureExtent(int nExtent)
  141. {
  142. if(m_nExtent < nExtent)
  143. {
  144. m_nExtent = nExtent;
  145. if(m_pArray)
  146. {
  147. register void** pTmp = (void **) HeapReAlloc(GetProcessHeap(), 0, m_pArray, sizeof(void *) * m_nExtent);
  148. if (pTmp == 0)
  149. return out_of_memory;
  150. m_pArray = pTmp;
  151. }
  152. else
  153. m_pArray = (void **) HeapAlloc(GetProcessHeap(), 0, sizeof(void *) * m_nExtent);
  154. if (!m_pArray)
  155. return out_of_memory;
  156. }
  157. return no_error;
  158. }
  159. //***************************************************************************
  160. //
  161. // CFlexArray::InsertAt
  162. //
  163. // Inserts a new element at the specified location. The pointer is copied.
  164. //
  165. // Parameters:
  166. // <nIndex> The 0-origin location at which to insert the new element.
  167. // <pSrc> The pointer to copy. (contents are not copied).
  168. //
  169. // Return value:
  170. // array_full
  171. // out_of_memory
  172. // no_error
  173. //
  174. //***************************************************************************
  175. // ok
  176. int CFlexArray::InsertAt(int nIndex, void *pSrc)
  177. {
  178. // TEMP: fix for sparse functionality in stdprov
  179. // =============================================
  180. while(nIndex > m_nSize)
  181. Add(NULL);
  182. // If the array is full, we need to expand it.
  183. // ===========================================
  184. if (m_nSize == m_nExtent) {
  185. if (m_nGrowByPercent == 0)
  186. return array_full;
  187. register nTmpExtent = m_nExtent;
  188. m_nExtent += 1;
  189. m_nExtent *= (100 + m_nGrowByPercent);
  190. m_nExtent /= 100;
  191. if(m_pArray)
  192. {
  193. register void** pTmp = (void **) HeapReAlloc(GetProcessHeap(), 0, m_pArray, sizeof(void *) * m_nExtent);
  194. if (pTmp == 0)
  195. {
  196. m_nExtent = nTmpExtent; //Change it back, otherwise the extent could constantly grow even though it keeps failing...
  197. return out_of_memory;
  198. }
  199. m_pArray = pTmp;
  200. }
  201. else
  202. m_pArray = (void **) HeapAlloc(GetProcessHeap(), 0, sizeof(void *) * m_nExtent);
  203. if (!m_pArray)
  204. return out_of_memory;
  205. }
  206. // Special case of appending. This is so frequent
  207. // compared to true insertion that we want to optimize.
  208. // ====================================================
  209. if (nIndex == m_nSize) {
  210. m_pArray[m_nSize++] = pSrc;
  211. return no_error;
  212. }
  213. // If here, we are inserting at some random location.
  214. // We start at the end of the array and copy all the elements
  215. // one position farther to the end to make a 'hole' for
  216. // the new element.
  217. // ==========================================================
  218. // Account for nIndex being 0 based and m_nSize being 1 based
  219. MoveMemory( &m_pArray[nIndex+1], &m_pArray[nIndex], ( m_nSize - nIndex ) * sizeof(void *) );
  220. m_pArray[nIndex] = pSrc;
  221. m_nSize++;
  222. return no_error;
  223. }
  224. void CFlexArray::Sort()
  225. {
  226. if(m_pArray)
  227. qsort((void*)m_pArray, m_nSize, sizeof(void*), CFlexArray::CompareEls);
  228. }
  229. int __cdecl CFlexArray::CompareEls(const void* pelem1, const void* pelem2)
  230. {
  231. return *(int*)pelem1 - *(int*)pelem2;
  232. }
  233. //***************************************************************************
  234. //
  235. // CFlexArray::DebugDump
  236. //
  237. //***************************************************************************
  238. void CFlexArray::DebugDump()
  239. {
  240. printf("----CFlexArray Debug Dump----\n");
  241. printf("m_pArray = 0x%P\n", m_pArray);
  242. printf("m_nSize = %d\n", m_nSize);
  243. printf("m_nExtent = %d\n", m_nExtent);
  244. printf("m_nGrowByPercent = %d\n", m_nGrowByPercent);
  245. for (int i = 0; i < m_nExtent; i++)
  246. {
  247. if (i < m_nSize)
  248. printf("![%P] = %X\n", i, m_pArray[i]);
  249. else
  250. printf("?[%P] = %X\n", i, m_pArray[i]);
  251. }
  252. }
  253. //***************************************************************************
  254. //
  255. // CFlexArray::Compress
  256. //
  257. // Removes NULL elements by moving all non-NULL pointers to the beginning
  258. // of the array. The array "Size" changes, but the extent is untouched.
  259. //
  260. //***************************************************************************
  261. // ok
  262. void CFlexArray::Compress()
  263. {
  264. int nLeftCursor = 0, nRightCursor = 0;
  265. while (nLeftCursor < m_nSize - 1) {
  266. if (m_pArray[nLeftCursor]) {
  267. nLeftCursor++;
  268. continue;
  269. }
  270. else {
  271. nRightCursor = nLeftCursor + 1;
  272. while (m_pArray[nRightCursor] == 0 && nRightCursor < m_nSize)
  273. nRightCursor++;
  274. if (nRightCursor == m_nSize)
  275. break; // Short circuit, no more nonzero elements.
  276. m_pArray[nLeftCursor] = m_pArray[nRightCursor];
  277. m_pArray[nRightCursor] = 0;
  278. }
  279. }
  280. Trim();
  281. }
  282. void CFlexArray::Trim()
  283. {
  284. while (m_nSize > 0 && m_pArray[m_nSize - 1] == NULL) m_nSize--;
  285. }
  286. //***************************************************************************
  287. //
  288. // CFlexArray::Empty
  289. //
  290. // Clears the array of all pointers (does not deallocate them) and sets
  291. // its apparent size to zero.
  292. //
  293. //***************************************************************************
  294. // ok
  295. void CFlexArray::Empty()
  296. {
  297. HeapFree(GetProcessHeap(), 0, m_pArray);
  298. m_pArray = NULL;
  299. m_nSize = 0;
  300. m_nExtent = 0;
  301. }
  302. //***************************************************************************
  303. //
  304. // CFlexArray::UnbindPtr
  305. //
  306. // Empties the array and returns the pointer to the data it contained
  307. //
  308. //***************************************************************************
  309. void** CFlexArray::UnbindPtr()
  310. {
  311. void** pp = m_pArray;
  312. m_pArray = NULL;
  313. Empty();
  314. return pp;
  315. }
  316. //***************************************************************************
  317. //
  318. // CFlexArray::CopyData
  319. //
  320. // Copies the data but not the settings of another flexarray
  321. //
  322. //***************************************************************************
  323. int CFlexArray::CopyDataFrom(const CFlexArray& aOther)
  324. {
  325. // Check if there is enough room
  326. // =============================
  327. if(aOther.m_nSize > m_nExtent)
  328. {
  329. // Extend the array to the requisite size
  330. // ======================================
  331. m_nExtent = aOther.m_nSize;
  332. if(m_pArray)
  333. {
  334. register void** pTmp = (void **) HeapReAlloc(GetProcessHeap(), 0, m_pArray, sizeof(void *) * m_nExtent);
  335. if (pTmp == 0)
  336. return out_of_memory;
  337. m_pArray = pTmp;
  338. }
  339. else
  340. m_pArray = (void **) HeapAlloc(GetProcessHeap(), 0, sizeof(void *) * m_nExtent);
  341. if (!m_pArray)
  342. return out_of_memory;
  343. }
  344. // Copy the data
  345. // =============
  346. m_nSize = aOther.m_nSize;
  347. memcpy(m_pArray, aOther.m_pArray, sizeof(void*) * m_nSize);
  348. return no_error;
  349. }
  350. //***************************************************************************
  351. //
  352. // CWStringArray::CWStringArray
  353. //
  354. // Constructs a wide-string array.
  355. //
  356. // Parameters:
  357. // <nSize> The starting preallocated size of the array.
  358. // <nGrowBy> The amount to grow by when the array fills up.
  359. //
  360. // Size() returns the number of elements in use, not the 'true' size.
  361. //
  362. //***************************************************************************
  363. CWStringArray::CWStringArray(
  364. int nSize,
  365. int nGrowBy
  366. )
  367. :
  368. m_Array(nSize, nGrowBy)
  369. {
  370. }
  371. //***************************************************************************
  372. //
  373. // Copy constructor.
  374. //
  375. //***************************************************************************
  376. CWStringArray::CWStringArray(CWStringArray &Src)
  377. {
  378. *this = Src;
  379. }
  380. //***************************************************************************
  381. //
  382. // Destructor. Cleans up all the strings.
  383. //
  384. //***************************************************************************
  385. CWStringArray::~CWStringArray()
  386. {
  387. Empty();
  388. }
  389. //***************************************************************************
  390. //
  391. // CWStringArray::DeleteStr
  392. //
  393. // Frees the string at the specified index and sets the element to NULL.
  394. // Does not compress array.
  395. //
  396. // Does not currently do a range check.
  397. //
  398. // Parameters:
  399. // <nIndex> The 0-origin index of the string to remove.
  400. //
  401. // Return values:
  402. // no_error
  403. //
  404. //***************************************************************************
  405. int CWStringArray::DeleteStr(int nIndex)
  406. {
  407. HeapFree(GetProcessHeap(), 0, m_Array[nIndex]);
  408. m_Array[nIndex] = 0;
  409. return no_error;
  410. }
  411. //***************************************************************************
  412. //
  413. // CWStringArray::FindStr
  414. //
  415. // Finds the specified string and returns its location.
  416. //
  417. // Parameters:
  418. // <pTarget> The string to find.
  419. // <nFlags> <no_case> or <with_case>
  420. //
  421. // Return value:
  422. // The 0-origin location of the string, or -1 if not found.
  423. //
  424. //***************************************************************************
  425. int CWStringArray::FindStr(const wchar_t *pTarget, int nFlags)
  426. {
  427. if (nFlags == no_case) {
  428. for (int i = 0; i < m_Array.Size(); i++)
  429. if (wbem_wcsicmp((wchar_t *) m_Array[i], pTarget) == 0)
  430. return i;
  431. }
  432. else {
  433. for (int i = 0; i < m_Array.Size(); i++)
  434. if (wcscmp((wchar_t *) m_Array[i], pTarget) == 0)
  435. return i;
  436. }
  437. return not_found;
  438. }
  439. //***************************************************************************
  440. //
  441. // operator =
  442. //
  443. //***************************************************************************
  444. // Heap handle & allocation functions are not copied. This allows
  445. // transfer of arrays between heaps.
  446. CWStringArray& CWStringArray::operator =(CWStringArray &Src)
  447. {
  448. Empty();
  449. for (int i = 0; i < Src.Size(); i++)
  450. {
  451. wchar_t *pSrc = (wchar_t *) Src.m_Array[i];
  452. wchar_t *pCopy = (wchar_t *) HeapAlloc(GetProcessHeap, 0, (wcslen(pSrc) + 1) * 2);
  453. // Check for allocation failures
  454. if ( NULL == pCopy )
  455. {
  456. throw CX_MemoryException();
  457. }
  458. wcscpy(pCopy, pSrc);
  459. if ( m_Array.Add(pCopy) != CFlexArray::no_error )
  460. {
  461. throw CX_MemoryException();
  462. }
  463. }
  464. return *this;
  465. }
  466. //***************************************************************************
  467. //
  468. // CWStringArray::Add
  469. //
  470. // Appends a new string to the end of the array.
  471. //
  472. // Parameters:
  473. // <pSrc> The string to copy.
  474. //
  475. // Return value:
  476. // The return values of CFlexArray::Add.
  477. //
  478. //***************************************************************************
  479. int CWStringArray::Add(const wchar_t *pSrc)
  480. {
  481. wchar_t *pNewStr = (wchar_t *) HeapAlloc(GetProcessHeap(), 0, (wcslen(pSrc) + 1) * 2);
  482. // Check for allocation failures
  483. if ( NULL == pNewStr )
  484. {
  485. return out_of_memory;
  486. }
  487. wcscpy(pNewStr, pSrc);
  488. return m_Array.Add(pNewStr);
  489. }
  490. //***************************************************************************
  491. //
  492. // CWStringArray::InsertAt
  493. //
  494. // Inserts a copy of a string in the array.
  495. //
  496. // Parameters:
  497. // <nIndex> The 0-origin location at which to insert the string.
  498. // <pSrc> The string to copy.
  499. //
  500. // Return values:
  501. // The return values of CFlexArray::InsertAt
  502. //
  503. //***************************************************************************
  504. int CWStringArray::InsertAt(int nIndex, const wchar_t *pSrc)
  505. {
  506. wchar_t *pNewStr = (wchar_t *) HeapAlloc(GetProcessHeap(), 0, (wcslen(pSrc) + 1) * 2);
  507. // Check for allocation failures
  508. if ( NULL == pNewStr )
  509. {
  510. return out_of_memory;
  511. }
  512. wcscpy(pNewStr, pSrc);
  513. return m_Array.InsertAt(nIndex, pNewStr);
  514. }
  515. //***************************************************************************
  516. //
  517. // CWStringArray::RemoveAt
  518. //
  519. // Removes and deallocates the string at the specified location.
  520. // Shrinks the array.
  521. //
  522. // Parameters:
  523. // <nIndex> The 0-origin index of the 'doomed' string.
  524. //
  525. // Return value:
  526. // Same as CFlexArray::RemoveAt.
  527. //
  528. //***************************************************************************
  529. int CWStringArray::RemoveAt(int nIndex)
  530. {
  531. wchar_t *pDoomedString = (wchar_t *) m_Array[nIndex];
  532. HeapFree(GetProcessHeap, 0, pDoomedString);
  533. return m_Array.RemoveAt(nIndex);
  534. }
  535. //***************************************************************************
  536. //
  537. // CWStringArray::SetAt
  538. //
  539. // Replaces the string at the targeted location with the new one.
  540. // The old string at the location is cleaned up.
  541. //
  542. // No range checking or out-of-memory checks at present.
  543. //
  544. // Parameters:
  545. // <nIndex> The 0-origin location at which to replace the string.
  546. // <pSrc> The string to copy.
  547. //
  548. // Return value:
  549. // no_error
  550. //
  551. //***************************************************************************
  552. int CWStringArray::SetAt(int nIndex, const wchar_t *pSrc)
  553. {
  554. wchar_t *pNewStr = (wchar_t *) HeapAlloc(GetProcessHeap(), 0, (wcslen(pSrc) + 1) * 2);
  555. // Check for allocation failures
  556. if ( NULL == pNewStr )
  557. {
  558. return out_of_memory;
  559. }
  560. wchar_t *pDoomedString = (wchar_t *) m_Array[nIndex];
  561. if (pDoomedString)
  562. delete [] pDoomedString;
  563. wcscpy(pNewStr, pSrc);
  564. m_Array[nIndex] = pNewStr;
  565. return no_error;
  566. }
  567. //***************************************************************************
  568. //
  569. // CWStringArray::ReplaceAt
  570. //
  571. // Directly replaces the pointer at the specified location with the
  572. // one in the parameter. No copy or cleanup.
  573. //
  574. // Parameters:
  575. // <nIndex> The 0-origin location at which to replace.
  576. // <pSrc> The new pointer to copy over the old one.
  577. //
  578. // Return value:
  579. // no_error (No checking done at present).
  580. //
  581. //***************************************************************************
  582. int CWStringArray::ReplaceAt(int nIndex, wchar_t *pSrc)
  583. {
  584. m_Array[nIndex] = pSrc;
  585. return no_error;
  586. }
  587. //***************************************************************************
  588. //
  589. // CWStringArray::Empty
  590. //
  591. // Empties the array, deallocates all strings, and sets the apparent
  592. // array size to zero.
  593. //
  594. //***************************************************************************
  595. void CWStringArray::Empty()
  596. {
  597. for (int i = 0; i < m_Array.Size(); i++)
  598. HeapFree(GetProcessHeap(), 0, m_Array[i]);
  599. m_Array.Empty();
  600. }
  601. //***************************************************************************
  602. //
  603. // CWStringArray::Sort
  604. //
  605. // Sorts the array according to UNICODE order.
  606. // (Shell sort).
  607. //
  608. //***************************************************************************
  609. void CWStringArray::Sort()
  610. {
  611. for (int nInterval = 1; nInterval < m_Array.Size() / 9; nInterval = nInterval * 3 + 1);
  612. while (nInterval)
  613. {
  614. for (int iCursor = nInterval; iCursor < m_Array.Size(); iCursor++)
  615. {
  616. int iBackscan = iCursor;
  617. while (iBackscan - nInterval >= 0 &&
  618. wbem_wcsicmp((const wchar_t *) m_Array[iBackscan],
  619. (const wchar_t *) m_Array[iBackscan-nInterval]) < 0)
  620. {
  621. wchar_t *pTemp = (wchar_t *) m_Array[iBackscan - nInterval];
  622. m_Array[iBackscan - nInterval] = m_Array[iBackscan];
  623. m_Array[iBackscan] = pTemp;
  624. iBackscan -= nInterval;
  625. }
  626. }
  627. nInterval /= 3;
  628. }
  629. }
  630. //***************************************************************************
  631. //
  632. // CWStringArray::Difference
  633. //
  634. // Set-theoretic difference operation on the arrays.
  635. //
  636. // Parameters:
  637. // <Src1> First array (not modified).
  638. // <Src2> Second array which is 'subtracted' from first (not modified).
  639. // <Diff> Receives the difference. Should be an empty array on entry.
  640. //
  641. //***************************************************************************
  642. void CWStringArray::Difference(
  643. CWStringArray &Src1,
  644. CWStringArray &Src2,
  645. CWStringArray &Diff
  646. )
  647. {
  648. for (int i = 0; i < Src1.Size(); i++)
  649. {
  650. if (Src2.FindStr(Src1[i], no_case) == -1)
  651. {
  652. if ( Diff.Add(Src1[i]) != no_error )
  653. {
  654. throw CX_MemoryException();
  655. }
  656. }
  657. }
  658. }
  659. //***************************************************************************
  660. //
  661. // CWStringArray::Intersection
  662. //
  663. // Set-theoretic intersection operation on the arrays.
  664. //
  665. // Parameters:
  666. // <Src1> First array (not modified).
  667. // <Src2> Second array (not modified).
  668. // <Diff> Receives the intersection. Should be an empty array on entry.
  669. //***************************************************************************
  670. void CWStringArray::Intersection(
  671. CWStringArray &Src1,
  672. CWStringArray &Src2,
  673. CWStringArray &Output
  674. )
  675. {
  676. for (int i = 0; i < Src1.Size(); i++)
  677. {
  678. if (Src2.FindStr(Src1[i], no_case) != -1)
  679. {
  680. if ( Output.Add(Src1[i]) != no_error )
  681. {
  682. throw CX_MemoryException();
  683. }
  684. }
  685. }
  686. }
  687. //***************************************************************************
  688. //
  689. // CWStringArray::Union
  690. //
  691. // Set-theoretic union operation on the arrays.
  692. //
  693. // Parameters:
  694. // <Src1> First array (not modified).
  695. // <Src2> Second array (not modified).
  696. // <Diff> Receives the union. Should be an empty array on entry.
  697. //
  698. //***************************************************************************
  699. void CWStringArray::Union(
  700. CWStringArray &Src1,
  701. CWStringArray &Src2,
  702. CWStringArray &Output
  703. )
  704. {
  705. Output = Src1;
  706. for (int i = 0; i < Src2.Size(); i++)
  707. {
  708. if (Output.FindStr(Src2[i], no_case) == not_found)
  709. {
  710. if ( Output.Add(Src2[i]) != no_error )
  711. {
  712. throw CX_MemoryException();
  713. }
  714. }
  715. }
  716. }