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.

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