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.

920 lines
22 KiB

  1. //---------------------------------------------------------------------------
  2. //
  3. // Copyright (c) Microsoft Corporation 1993-1994
  4. //
  5. // File: da.c
  6. //
  7. // This file contains dynamic array functions.
  8. //
  9. // History:
  10. // 09-27-94 ScottH Taken from commctrl
  11. //
  12. //---------------------------------------------------------------------------
  13. #include "brfprv.h" // common headers
  14. //
  15. // Heapsort is a bit slower, but it doesn't use any stack or memory...
  16. // Mergesort takes a bit of memory (O(n)) and stack (O(log(n)), but very fast...
  17. //
  18. #ifdef WIN32
  19. #define MERGESORT
  20. #else
  21. #define USEHEAPSORT
  22. #endif
  23. #ifdef DEBUG
  24. #define DSA_MAGIC (TEXT('S') | (TEXT('A') << 256))
  25. #define IsDSA(pdsa) ((pdsa) && (pdsa)->magic == DSA_MAGIC)
  26. #define DPA_MAGIC (TEXT('P') | (TEXT('A') << 256))
  27. #define IsDPA(pdpa) ((pdpa) && (pdpa)->magic == DPA_MAGIC)
  28. #else
  29. #define IsDSA(pdsa)
  30. #define IsDPA(pdsa)
  31. #endif
  32. typedef struct {
  33. void * * pp;
  34. PFNDPACOMPARE pfnCmp;
  35. LPARAM lParam;
  36. int cp;
  37. #ifdef MERGESORT
  38. void * * ppT;
  39. #endif
  40. } SORTPARAMS;
  41. BOOL DPA_QuickSort(SORTPARAMS * psp);
  42. BOOL DPA_QuickSort2(int i, int j, SORTPARAMS * psp);
  43. BOOL DPA_HeapSort(SORTPARAMS * psp);
  44. void DPA_HeapSortPushDown(int first, int last, SORTPARAMS * psp);
  45. BOOL DPA_MergeSort(SORTPARAMS * psp);
  46. void DPA_MergeSort2(SORTPARAMS * psp, int iFirst, int cItems);
  47. //========== Dynamic structure array ====================================
  48. // Dynamic structure array
  49. typedef struct _DSA {
  50. // NOTE: The following field MUST be defined at the beginning of the
  51. // structure in order for GetItemCount() to work.
  52. //
  53. int cItem; // # of elements in dsa
  54. void * aItem; // memory for elements
  55. int cItemAlloc; // # items which fit in aItem
  56. int cbItem; // size of each item
  57. int cItemGrow; // # items to grow cItemAlloc by
  58. #ifdef DEBUG
  59. UINT magic;
  60. #endif
  61. } DSA;
  62. #define DSA_PITEM(pdsa, index) ((void *)(((BYTE *)(pdsa)->aItem) + ((index) * (pdsa)->cbItem)))
  63. HDSA PUBLIC DSA_Create(int cbItem, int cItemGrow)
  64. {
  65. HDSA pdsa = SharedAlloc(sizeof(DSA));
  66. ASSERT(cbItem);
  67. if (pdsa)
  68. {
  69. pdsa->cItem = 0;
  70. pdsa->cItemAlloc = 0;
  71. pdsa->cbItem = cbItem;
  72. pdsa->cItemGrow = (cItemGrow == 0 ? 1 : cItemGrow);
  73. pdsa->aItem = NULL;
  74. #ifdef DEBUG
  75. pdsa->magic = DSA_MAGIC;
  76. #endif
  77. }
  78. return pdsa;
  79. }
  80. BOOL PUBLIC DSA_Destroy(HDSA pdsa)
  81. {
  82. ASSERT(IsDSA(pdsa));
  83. if (pdsa == NULL) // allow NULL for low memory cases, still assert
  84. return TRUE;
  85. #ifdef DEBUG
  86. pdsa->cItem = 0;
  87. pdsa->cItemAlloc = 0;
  88. pdsa->cbItem = 0;
  89. pdsa->magic = 0;
  90. #endif
  91. if (pdsa->aItem && !SharedFree(&pdsa->aItem))
  92. return FALSE;
  93. return SharedFree(&pdsa);
  94. }
  95. BOOL PUBLIC DSA_GetItem(HDSA pdsa, int index, void * pitem)
  96. {
  97. ASSERT(IsDSA(pdsa));
  98. ASSERT(pitem);
  99. if (index < 0 || index >= pdsa->cItem)
  100. {
  101. DebugMsg(DM_ERROR, TEXT("DSA: Invalid index: %d"), index);
  102. return FALSE;
  103. }
  104. hmemcpy(pitem, DSA_PITEM(pdsa, index), pdsa->cbItem);
  105. return TRUE;
  106. }
  107. void * PUBLIC DSA_GetItemPtr(HDSA pdsa, int index)
  108. {
  109. ASSERT(IsDSA(pdsa));
  110. if (index < 0 || index >= pdsa->cItem)
  111. {
  112. DebugMsg(DM_ERROR, TEXT("DSA: Invalid index: %d"), index);
  113. return NULL;
  114. }
  115. return DSA_PITEM(pdsa, index);
  116. }
  117. BOOL PUBLIC DSA_SetItem(HDSA pdsa, int index, void * pitem)
  118. {
  119. ASSERT(pitem);
  120. ASSERT(IsDSA(pdsa));
  121. if (index < 0)
  122. {
  123. DebugMsg(DM_ERROR, TEXT("DSA: Invalid index: %d"), index);
  124. return FALSE;
  125. }
  126. if (index >= pdsa->cItem)
  127. {
  128. if (index + 1 > pdsa->cItemAlloc)
  129. {
  130. int cItemAlloc = (((index + 1) + pdsa->cItemGrow - 1) / pdsa->cItemGrow) * pdsa->cItemGrow;
  131. void * aItemNew = SharedReAlloc(pdsa->aItem, cItemAlloc * pdsa->cbItem);
  132. if (!aItemNew)
  133. return FALSE;
  134. pdsa->aItem = aItemNew;
  135. pdsa->cItemAlloc = cItemAlloc;
  136. }
  137. pdsa->cItem = index + 1;
  138. }
  139. hmemcpy(DSA_PITEM(pdsa, index), pitem, pdsa->cbItem);
  140. return TRUE;
  141. }
  142. int PUBLIC DSA_InsertItem(HDSA pdsa, int index, void * pitem)
  143. {
  144. ASSERT(pitem);
  145. ASSERT(IsDSA(pdsa));
  146. if (index < 0)
  147. {
  148. DebugMsg(DM_ERROR, TEXT("DSA: Invalid index: %d"), index);
  149. return -1;
  150. }
  151. if (index > pdsa->cItem)
  152. index = pdsa->cItem;
  153. if (pdsa->cItem + 1 > pdsa->cItemAlloc)
  154. {
  155. void * aItemNew = SharedReAlloc(pdsa->aItem,
  156. (pdsa->cItemAlloc + pdsa->cItemGrow) * pdsa->cbItem);
  157. if (!aItemNew)
  158. return -1;
  159. pdsa->aItem = aItemNew;
  160. pdsa->cItemAlloc += pdsa->cItemGrow;
  161. }
  162. if (index < pdsa->cItem)
  163. {
  164. hmemcpy(DSA_PITEM(pdsa, index + 1), DSA_PITEM(pdsa, index),
  165. (pdsa->cItem - index) * pdsa->cbItem);
  166. }
  167. pdsa->cItem++;
  168. hmemcpy(DSA_PITEM(pdsa, index), pitem, pdsa->cbItem);
  169. return index;
  170. }
  171. BOOL PUBLIC DSA_DeleteItem(HDSA pdsa, int index)
  172. {
  173. ASSERT(IsDSA(pdsa));
  174. if (index < 0 || index >= pdsa->cItem)
  175. {
  176. DebugMsg(DM_ERROR, TEXT("DSA: Invalid index: %d"), index);
  177. return FALSE;
  178. }
  179. if (index < pdsa->cItem - 1)
  180. {
  181. hmemcpy(DSA_PITEM(pdsa, index), DSA_PITEM(pdsa, index + 1),
  182. (pdsa->cItem - (index + 1)) * pdsa->cbItem);
  183. }
  184. pdsa->cItem--;
  185. if (pdsa->cItemAlloc - pdsa->cItem > pdsa->cItemGrow)
  186. {
  187. void * aItemNew = SharedReAlloc(pdsa->aItem,
  188. (pdsa->cItemAlloc - pdsa->cItemGrow) * pdsa->cbItem);
  189. ASSERT(aItemNew);
  190. pdsa->aItem = aItemNew;
  191. pdsa->cItemAlloc -= pdsa->cItemGrow;
  192. }
  193. return TRUE;
  194. }
  195. BOOL PUBLIC DSA_DeleteAllItems(HDSA pdsa)
  196. {
  197. ASSERT(IsDSA(pdsa));
  198. if (pdsa->aItem && !SharedFree(&pdsa->aItem))
  199. return FALSE;
  200. pdsa->aItem = NULL;
  201. pdsa->cItem = pdsa->cItemAlloc = 0;
  202. return TRUE;
  203. }
  204. //================== Dynamic pointer array implementation ===========
  205. typedef struct _DPA {
  206. // NOTE: The following two fields MUST be defined in this order, at
  207. // the beginning of the structure in order for the macro APIs to work.
  208. //
  209. int cp;
  210. void * * pp;
  211. HANDLE hheap; // Heap to allocate from if NULL use shared
  212. int cpAlloc;
  213. int cpGrow;
  214. #ifdef DEBUG
  215. UINT magic;
  216. #endif
  217. } DPA;
  218. HDPA PUBLIC DPA_Create(int cpGrow)
  219. {
  220. HDPA pdpa = SharedAlloc(sizeof(DPA));
  221. if (pdpa)
  222. {
  223. pdpa->cp = 0;
  224. pdpa->cpAlloc = 0;
  225. pdpa->cpGrow = (cpGrow < 8 ? 8 : cpGrow);
  226. pdpa->pp = NULL;
  227. #ifdef WIN32
  228. pdpa->hheap = g_hSharedHeap; // Defaults to use shared one (for now...)
  229. #else
  230. pdpa->hheap = NULL; // Defaults to use shared one (for now...)
  231. #endif
  232. #ifdef DEBUG
  233. pdpa->magic = DPA_MAGIC;
  234. #endif
  235. }
  236. return pdpa;
  237. }
  238. // Should nuke the standard DPA above...
  239. HDPA PUBLIC DPA_CreateEx(int cpGrow, HANDLE hheap)
  240. {
  241. HDPA pdpa;
  242. if (hheap == NULL)
  243. {
  244. pdpa = SharedAlloc(sizeof(DPA));
  245. #ifdef WIN32
  246. hheap = g_hSharedHeap;
  247. #endif
  248. }
  249. else
  250. pdpa = MemAlloc(hheap, sizeof(DPA));
  251. if (pdpa)
  252. {
  253. pdpa->cp = 0;
  254. pdpa->cpAlloc = 0;
  255. pdpa->cpGrow = (cpGrow < 8 ? 8 : cpGrow);
  256. pdpa->pp = NULL;
  257. pdpa->hheap = hheap;
  258. #ifdef DEBUG
  259. pdpa->magic = DPA_MAGIC;
  260. #endif
  261. }
  262. return pdpa;
  263. }
  264. BOOL PUBLIC DPA_Destroy(HDPA pdpa)
  265. {
  266. ASSERT(IsDPA(pdpa));
  267. if (pdpa == NULL) // allow NULL for low memory cases, still assert
  268. return TRUE;
  269. #ifdef WIN32
  270. ASSERT (pdpa->hheap);
  271. #endif
  272. #ifdef DEBUG
  273. pdpa->cp = 0;
  274. pdpa->cpAlloc = 0;
  275. pdpa->magic = 0;
  276. #endif
  277. if (pdpa->pp && !MemFree(pdpa->hheap, pdpa->pp))
  278. return FALSE;
  279. return MemFree(pdpa->hheap, pdpa);
  280. }
  281. HDPA PUBLIC DPA_Clone(HDPA pdpa, HDPA pdpaNew)
  282. {
  283. BOOL fAlloc = FALSE;
  284. if (!pdpaNew)
  285. {
  286. pdpaNew = DPA_CreateEx(pdpa->cpGrow, pdpa->hheap);
  287. if (!pdpaNew)
  288. return NULL;
  289. fAlloc = TRUE;
  290. }
  291. if (!DPA_Grow(pdpaNew, pdpa->cpAlloc)) {
  292. if (!fAlloc)
  293. DPA_Destroy(pdpaNew);
  294. return NULL;
  295. }
  296. pdpaNew->cp = pdpa->cp;
  297. hmemcpy(pdpaNew->pp, pdpa->pp, pdpa->cp * sizeof(void *));
  298. return pdpaNew;
  299. }
  300. void * PUBLIC DPA_GetPtr(HDPA pdpa, int index)
  301. {
  302. ASSERT(IsDPA(pdpa));
  303. if (index < 0 || index >= pdpa->cp)
  304. return NULL;
  305. return pdpa->pp[index];
  306. }
  307. int PUBLIC DPA_GetPtrIndex(HDPA pdpa, void * p)
  308. {
  309. void * * pp;
  310. void * * ppMax;
  311. ASSERT(IsDPA(pdpa));
  312. if (pdpa->pp)
  313. {
  314. pp = pdpa->pp;
  315. ppMax = pp + pdpa->cp;
  316. for ( ; pp < ppMax; pp++)
  317. {
  318. if (*pp == p)
  319. return (pp - pdpa->pp);
  320. }
  321. }
  322. return -1;
  323. }
  324. BOOL PUBLIC DPA_Grow(HDPA pdpa, int cpAlloc)
  325. {
  326. ASSERT(IsDPA(pdpa));
  327. if (cpAlloc > pdpa->cpAlloc)
  328. {
  329. void * * ppNew;
  330. cpAlloc = ((cpAlloc + pdpa->cpGrow - 1) / pdpa->cpGrow) * pdpa->cpGrow;
  331. if (pdpa->pp)
  332. ppNew = (void * *)MemReAlloc(pdpa->hheap, pdpa->pp, cpAlloc * sizeof(void *));
  333. else
  334. ppNew = (void * *)MemAlloc(pdpa->hheap, cpAlloc * sizeof(void *));
  335. if (!ppNew)
  336. return FALSE;
  337. pdpa->pp = ppNew;
  338. pdpa->cpAlloc = cpAlloc;
  339. }
  340. return TRUE;
  341. }
  342. BOOL PUBLIC DPA_SetPtr(HDPA pdpa, int index, void * p)
  343. {
  344. ASSERT(IsDPA(pdpa));
  345. if (index < 0)
  346. {
  347. DebugMsg(DM_ERROR, TEXT("DPA: Invalid index: %d"), index);
  348. return FALSE;
  349. }
  350. if (index >= pdpa->cp)
  351. {
  352. if (!DPA_Grow(pdpa, index + 1))
  353. return FALSE;
  354. pdpa->cp = index + 1;
  355. }
  356. pdpa->pp[index] = p;
  357. return TRUE;
  358. }
  359. int PUBLIC DPA_InsertPtr(HDPA pdpa, int index, void * p)
  360. {
  361. ASSERT(IsDPA(pdpa));
  362. if (index < 0)
  363. {
  364. DebugMsg(DM_ERROR, TEXT("DPA: Invalid index: %d"), index);
  365. return -1;
  366. }
  367. if (index > pdpa->cp)
  368. index = pdpa->cp;
  369. // Make sure we have room for one more item
  370. //
  371. if (pdpa->cp + 1 > pdpa->cpAlloc)
  372. {
  373. if (!DPA_Grow(pdpa, pdpa->cp + 1))
  374. return -1;
  375. }
  376. // If we are inserting, we need to slide everybody up
  377. //
  378. if (index < pdpa->cp)
  379. {
  380. hmemcpy(&pdpa->pp[index + 1], &pdpa->pp[index],
  381. (pdpa->cp - index) * sizeof(void *));
  382. }
  383. pdpa->pp[index] = p;
  384. pdpa->cp++;
  385. return index;
  386. }
  387. void * PUBLIC DPA_DeletePtr(HDPA pdpa, int index)
  388. {
  389. void * p;
  390. ASSERT(IsDPA(pdpa));
  391. if (index < 0 || index >= pdpa->cp)
  392. {
  393. DebugMsg(DM_ERROR, TEXT("DPA: Invalid index: %d"), index);
  394. return NULL;
  395. }
  396. p = pdpa->pp[index];
  397. if (index < pdpa->cp - 1)
  398. {
  399. hmemcpy(&pdpa->pp[index], &pdpa->pp[index + 1],
  400. (pdpa->cp - (index + 1)) * sizeof(void *));
  401. }
  402. pdpa->cp--;
  403. if (pdpa->cpAlloc - pdpa->cp > pdpa->cpGrow)
  404. {
  405. void * * ppNew;
  406. ppNew = MemReAlloc(pdpa->hheap, pdpa->pp, (pdpa->cpAlloc - pdpa->cpGrow) * sizeof(void *));
  407. ASSERT(ppNew);
  408. pdpa->pp = ppNew;
  409. pdpa->cpAlloc -= pdpa->cpGrow;
  410. }
  411. return p;
  412. }
  413. BOOL PUBLIC DPA_DeleteAllPtrs(HDPA pdpa)
  414. {
  415. ASSERT(IsDPA(pdpa));
  416. if (pdpa->pp && !MemFree(pdpa->hheap, pdpa->pp))
  417. return FALSE;
  418. pdpa->pp = NULL;
  419. pdpa->cp = pdpa->cpAlloc = 0;
  420. return TRUE;
  421. }
  422. BOOL PUBLIC DPA_Sort(HDPA pdpa, PFNDPACOMPARE pfnCmp, LPARAM lParam)
  423. {
  424. SORTPARAMS sp;
  425. sp.cp = pdpa->cp;
  426. sp.pp = pdpa->pp;
  427. sp.pfnCmp = pfnCmp;
  428. sp.lParam = lParam;
  429. #ifdef USEQUICKSORT
  430. return DPA_QuickSort(&sp);
  431. #endif
  432. #ifdef USEHEAPSORT
  433. return DPA_HeapSort(&sp);
  434. #endif
  435. #ifdef MERGESORT
  436. return DPA_MergeSort(&sp);
  437. #endif
  438. }
  439. #ifdef USEQUICKSORT
  440. BOOL DPA_QuickSort(SORTPARAMS * psp)
  441. {
  442. return DPA_QuickSort2(0, psp->cp - 1, psp);
  443. }
  444. BOOL DPA_QuickSort2(int i, int j, SORTPARAMS * psp)
  445. {
  446. void * * pp = psp->pp;
  447. LPARAM lParam = psp->lParam;
  448. PFNDPACOMPARE pfnCmp = psp->pfnCmp;
  449. int iPivot;
  450. void * pFirst;
  451. int k;
  452. int result;
  453. iPivot = -1;
  454. pFirst = pp[i];
  455. for (k = i + 1; k <= j; k++)
  456. {
  457. result = (*pfnCmp)(pp[k], pFirst, lParam);
  458. if (result > 0)
  459. {
  460. iPivot = k;
  461. break;
  462. }
  463. else if (result < 0)
  464. {
  465. iPivot = i;
  466. break;
  467. }
  468. }
  469. if (iPivot != -1)
  470. {
  471. int l = i;
  472. int r = j;
  473. void * pivot = pp[iPivot];
  474. do
  475. {
  476. void * p;
  477. p = pp[l];
  478. pp[l] = pp[r];
  479. pp[r] = p;
  480. while ((*pfnCmp)(pp[l], pivot, lParam) < 0)
  481. l++;
  482. while ((*pfnCmp)(pp[r], pivot, lParam) >= 0)
  483. r--;
  484. } while (l <= r);
  485. if (l - 1 > i)
  486. DPA_QuickSort2(i, l - 1, psp);
  487. if (j > l)
  488. DPA_QuickSort2(l, j, psp);
  489. }
  490. return TRUE;
  491. }
  492. #endif // USEQUICKSORT
  493. #ifdef USEHEAPSORT
  494. void DPA_HeapSortPushDown(int first, int last, SORTPARAMS * psp)
  495. {
  496. void * * pp = psp->pp;
  497. LPARAM lParam = psp->lParam;
  498. PFNDPACOMPARE pfnCmp = psp->pfnCmp;
  499. int r;
  500. int r2;
  501. void * p;
  502. r = first;
  503. while (r <= last / 2)
  504. {
  505. int wRTo2R;
  506. r2 = r * 2;
  507. wRTo2R = (*pfnCmp)(pp[r-1], pp[r2-1], lParam);
  508. if (r2 == last)
  509. {
  510. if (wRTo2R < 0)
  511. {
  512. p = pp[r-1]; pp[r-1] = pp[r2-1]; pp[r2-1] = p;
  513. }
  514. break;
  515. }
  516. else
  517. {
  518. int wR2toR21 = (*pfnCmp)(pp[r2-1], pp[r2+1-1], lParam);
  519. if (wRTo2R < 0 && wR2toR21 >= 0)
  520. {
  521. p = pp[r-1]; pp[r-1] = pp[r2-1]; pp[r2-1] = p;
  522. r = r2;
  523. }
  524. else if ((*pfnCmp)(pp[r-1], pp[r2+1-1], lParam) < 0 && wR2toR21 < 0)
  525. {
  526. p = pp[r-1]; pp[r-1] = pp[r2+1-1]; pp[r2+1-1] = p;
  527. r = r2 + 1;
  528. }
  529. else
  530. {
  531. break;
  532. }
  533. }
  534. }
  535. }
  536. BOOL DPA_HeapSort(SORTPARAMS * psp)
  537. {
  538. void * * pp = psp->pp;
  539. int c = psp->cp;
  540. int i;
  541. for (i = c / 2; i >= 1; i--)
  542. DPA_HeapSortPushDown(i, c, psp);
  543. for (i = c; i >= 2; i--)
  544. {
  545. void * p = pp[0]; pp[0] = pp[i-1]; pp[i-1] = p;
  546. DPA_HeapSortPushDown(1, i - 1, psp);
  547. }
  548. return TRUE;
  549. }
  550. #endif // USEHEAPSORT
  551. #if defined(MERGESORT) && defined(WIN32)
  552. #define SortCompare(psp, pp1, i1, pp2, i2) \
  553. (psp->pfnCmp(pp1[i1], pp2[i2], psp->lParam))
  554. //
  555. // This function merges two sorted lists and makes one sorted list.
  556. // psp->pp[iFirst, iFirst+cItes/2-1], psp->pp[iFirst+cItems/2, iFirst+cItems-1]
  557. //
  558. void DPA_MergeThem(SORTPARAMS * psp, int iFirst, int cItems)
  559. {
  560. //
  561. // Notes:
  562. // This function is separated from DPA_MergeSort2() to avoid comsuming
  563. // stack variables. Never inline this.
  564. //
  565. int cHalf = cItems/2;
  566. int iIn1, iIn2, iOut;
  567. LPVOID * ppvSrc = &psp->pp[iFirst];
  568. // Copy the first part to temp storage so we can write directly into
  569. // the final buffer. Note that this takes at most psp->cp/2 DWORD's
  570. hmemcpy(psp->ppT, ppvSrc, cHalf*sizeof(LPVOID));
  571. for (iIn1=0, iIn2=cHalf, iOut=0;;)
  572. {
  573. if (SortCompare(psp, psp->ppT, iIn1, ppvSrc, iIn2) <= 0) {
  574. ppvSrc[iOut++] = psp->ppT[iIn1++];
  575. if (iIn1==cHalf) {
  576. // We used up the first half; the rest of the second half
  577. // should already be in place
  578. break;
  579. }
  580. } else {
  581. ppvSrc[iOut++] = ppvSrc[iIn2++];
  582. if (iIn2==cItems) {
  583. // We used up the second half; copy the rest of the first half
  584. // into place
  585. hmemcpy(&ppvSrc[iOut], &psp->ppT[iIn1], (cItems-iOut)*sizeof(LPVOID));
  586. break;
  587. }
  588. }
  589. }
  590. }
  591. //
  592. // This function sorts a give list (psp->pp[iFirst,iFirst-cItems-1]).
  593. //
  594. void DPA_MergeSort2(SORTPARAMS * psp, int iFirst, int cItems)
  595. {
  596. //
  597. // Notes:
  598. // This function is recursively called. Therefore, we should minimize
  599. // the number of local variables and parameters. At this point, we
  600. // use one local variable and three parameters.
  601. //
  602. int cHalf;
  603. switch(cItems)
  604. {
  605. case 1:
  606. return;
  607. case 2:
  608. // Swap them, if they are out of order.
  609. if (SortCompare(psp, psp->pp, iFirst, psp->pp, iFirst+1) > 0)
  610. {
  611. psp->ppT[0] = psp->pp[iFirst];
  612. psp->pp[iFirst] = psp->pp[iFirst+1];
  613. psp->pp[iFirst+1] = psp->ppT[0];
  614. }
  615. break;
  616. default:
  617. cHalf = cItems/2;
  618. // Sort each half
  619. DPA_MergeSort2(psp, iFirst, cHalf);
  620. DPA_MergeSort2(psp, iFirst+cHalf, cItems-cHalf);
  621. // Then, merge them.
  622. DPA_MergeThem(psp, iFirst, cItems);
  623. break;
  624. }
  625. }
  626. BOOL DPA_MergeSort(SORTPARAMS * psp)
  627. {
  628. if (psp->cp==0)
  629. return TRUE;
  630. // Note that we divide by 2 below; we want to round down
  631. psp->ppT = LocalAlloc(LPTR, psp->cp/2 * sizeof(LPVOID));
  632. if (!psp->ppT)
  633. return FALSE;
  634. DPA_MergeSort2(psp, 0, psp->cp);
  635. LocalFree(psp->ppT);
  636. return TRUE;
  637. }
  638. #endif // MERGESORT
  639. // Search function
  640. //
  641. int PUBLIC DPA_Search(HDPA pdpa, void * pFind, int iStart,
  642. PFNDPACOMPARE pfnCompare, LPARAM lParam, UINT options)
  643. {
  644. int cp = DPA_GetPtrCount(pdpa);
  645. ASSERT(pfnCompare);
  646. ASSERT(0 <= iStart);
  647. // Only allow these wierd flags if the list is sorted
  648. ASSERT((options & DPAS_SORTED) || !(options & (DPAS_INSERTBEFORE | DPAS_INSERTAFTER)));
  649. if (!(options & DPAS_SORTED))
  650. {
  651. // Not sorted: do linear search.
  652. int i;
  653. for (i = iStart; i < cp; i++)
  654. {
  655. if (0 == pfnCompare(pFind, DPA_FastGetPtr(pdpa, i), lParam))
  656. return i;
  657. }
  658. return -1;
  659. }
  660. else
  661. {
  662. // Search the array using binary search. If several adjacent
  663. // elements match the target element, the index of the first
  664. // matching element is returned.
  665. int iRet = -1; // assume no match
  666. BOOL bFound = FALSE;
  667. int nCmp = 0;
  668. int iLow = 0; // Don't bother using iStart for binary search
  669. int iMid = 0;
  670. int iHigh = cp - 1;
  671. // (OK for cp == 0)
  672. while (iLow <= iHigh)
  673. {
  674. iMid = (iLow + iHigh) / 2;
  675. nCmp = pfnCompare(pFind, DPA_FastGetPtr(pdpa, iMid), lParam);
  676. if (0 > nCmp)
  677. iHigh = iMid - 1; // First is smaller
  678. else if (0 < nCmp)
  679. iLow = iMid + 1; // First is larger
  680. else
  681. {
  682. // Match; search back for first match
  683. bFound = TRUE;
  684. while (0 < iMid)
  685. {
  686. if (0 != pfnCompare(pFind, DPA_FastGetPtr(pdpa, iMid-1), lParam))
  687. break;
  688. else
  689. iMid--;
  690. }
  691. break;
  692. }
  693. }
  694. if (bFound)
  695. {
  696. ASSERT(0 <= iMid);
  697. iRet = iMid;
  698. }
  699. // Did the search fail AND
  700. // is one of the strange search flags set?
  701. if (!bFound && (options & (DPAS_INSERTAFTER | DPAS_INSERTBEFORE)))
  702. {
  703. // Yes; return the index where the target should be inserted
  704. // if not found
  705. if (0 < nCmp) // First is larger
  706. iRet = iLow;
  707. else
  708. iRet = iMid;
  709. // (We don't distinguish between the two flags anymore)
  710. }
  711. else if ( !(options & (DPAS_INSERTAFTER | DPAS_INSERTBEFORE)) )
  712. {
  713. // Sanity check with linear search
  714. ASSERT(DPA_Search(pdpa, pFind, iStart, pfnCompare, lParam, options & ~DPAS_SORTED) == iRet);
  715. }
  716. return iRet;
  717. }
  718. }
  719. //===========================================================================
  720. //
  721. // String ptr management routines
  722. //
  723. // Copy as much of *psz to *pszBuf as will fit
  724. //
  725. int PUBLIC Str_GetPtr(LPCTSTR psz, LPTSTR pszBuf, int cchBuf)
  726. {
  727. int cch = 0;
  728. // if pszBuf is NULL, just return length of string.
  729. //
  730. if (!pszBuf && psz)
  731. return lstrlen(psz);
  732. if (cchBuf)
  733. {
  734. if (psz)
  735. {
  736. cch = lstrlen(psz);
  737. if (cch > cchBuf - 1)
  738. cch = cchBuf - 1;
  739. hmemcpy(pszBuf, psz, cch * sizeof(TCHAR));
  740. }
  741. pszBuf[cch] = 0;
  742. }
  743. return cch;
  744. }
  745. // Set *ppsz to a copy of psz, reallocing as needed
  746. //
  747. BOOL PUBLIC Str_SetPtr(LPTSTR * ppsz, LPCTSTR psz)
  748. {
  749. if (!psz)
  750. {
  751. if (*ppsz)
  752. {
  753. SharedFree(ppsz);
  754. *ppsz = NULL;
  755. }
  756. }
  757. else
  758. {
  759. LPTSTR pszNew = (LPTSTR)SharedReAlloc(*ppsz, (lstrlen(psz) + 1) * sizeof(TCHAR));
  760. if (!pszNew)
  761. return FALSE;
  762. // pszNew is allocated above with enough space so lstrcpy will do
  763. lstrcpy(pszNew, psz);
  764. *ppsz = pszNew;
  765. }
  766. return TRUE;
  767. }