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.

610 lines
13 KiB

  1. // Dynamic Array APIs
  2. //*******************************************************************************************
  3. //
  4. // Filename : Da.c
  5. //
  6. // Implementation of DPAs
  7. //
  8. // Copyright (c) 1994 - 1996 Microsoft Corporation. All rights reserved
  9. //
  10. //*******************************************************************************************
  11. #include "pch.h"
  12. #include "dpda.h"
  13. #include <assert.h>
  14. #ifdef DEBUG
  15. #define DPA_MAGIC ('P' | ('A' << 256))
  16. #define IsDPA(pdpa) ((pdpa) && (pdpa)->magic == DPA_MAGIC)
  17. #else
  18. #define IsDPA(pdsa)
  19. #endif
  20. #define ControlAlloc(hheap, cb) HeapAlloc((hheap), HEAP_ZERO_MEMORY, (cb))
  21. #define ControlReAlloc(hheap, pb, cb) HeapReAlloc((hheap), HEAP_ZERO_MEMORY, (pb),(cb))
  22. #define ControlFree(hheap, pb) HeapFree((hheap), 0, (pb))
  23. #define ControlSize(hheap, pb) HeapSize((hheap), 0, (LPCVOID)(pb))
  24. typedef struct {
  25. void **pp;
  26. PFNDPACOMPARE pfnCmp;
  27. LPARAM lParam;
  28. int cp;
  29. void **ppT;
  30. } SORTPARAMS;
  31. BOOL DPA_MergeSort(SORTPARAMS * psp);
  32. void DPA_MergeSort2(SORTPARAMS * psp, int iFirst, int cItems);
  33. //================== Dynamic pointer array implementation ===========
  34. typedef struct _DPA {
  35. // NOTE: The following two fields MUST be defined in this order, at
  36. // the beginning of the structure in order for the macro APIs to work.
  37. //
  38. int cp;
  39. void **pp;
  40. HANDLE hheap; // Heap to allocate from if NULL use shared
  41. int cpAlloc;
  42. int cpGrow;
  43. #ifdef DEBUG
  44. UINT magic;
  45. #endif
  46. } DPA;
  47. HANDLE g_hSharedHeap = NULL;
  48. void * Alloc(long cb)
  49. {
  50. // I will assume that this is the only one that needs the checks to
  51. // see if the heap has been previously created or not
  52. if (g_hSharedHeap == NULL)
  53. {
  54. g_hSharedHeap = HeapCreate(0, 1, 0);
  55. // If still NULL we have problems!
  56. if (g_hSharedHeap == NULL)
  57. return(NULL);
  58. }
  59. return HeapAlloc(g_hSharedHeap, HEAP_ZERO_MEMORY, cb);
  60. }
  61. void * ReAlloc(void * pb, long cb)
  62. {
  63. if (pb == NULL)
  64. return Alloc(cb);
  65. return HeapReAlloc(g_hSharedHeap, HEAP_ZERO_MEMORY, pb, cb);
  66. }
  67. BOOL Free(void * pb)
  68. {
  69. return HeapFree(g_hSharedHeap, 0, pb);
  70. }
  71. DWORD GetSize(void * pb)
  72. {
  73. return HeapSize(g_hSharedHeap, 0, pb);
  74. }
  75. HDPA DPA_Create(int cpGrow)
  76. {
  77. HDPA pdpa = Alloc(sizeof(DPA));
  78. if (pdpa)
  79. {
  80. pdpa->cp = 0;
  81. pdpa->cpAlloc = 0;
  82. pdpa->cpGrow = (cpGrow < 8 ? 8 : cpGrow);
  83. pdpa->pp = NULL;
  84. pdpa->hheap = g_hSharedHeap; // Defaults to use shared one (for now...)
  85. #ifdef DEBUG
  86. pdpa->magic = DPA_MAGIC;
  87. #endif
  88. }
  89. return pdpa;
  90. }
  91. // Should nuke the standard DPA above...
  92. HDPA DPA_CreateEx(int cpGrow, HANDLE hheap)
  93. {
  94. HDPA pdpa;
  95. if (hheap == NULL)
  96. {
  97. pdpa = Alloc(sizeof(DPA));
  98. hheap = g_hSharedHeap;
  99. }
  100. else
  101. pdpa = ControlAlloc(hheap, sizeof(DPA));
  102. if (pdpa)
  103. {
  104. pdpa->cp = 0;
  105. pdpa->cpAlloc = 0;
  106. pdpa->cpGrow = (cpGrow < 8 ? 8 : cpGrow);
  107. pdpa->pp = NULL;
  108. pdpa->hheap = hheap;
  109. #ifdef DEBUG
  110. pdpa->magic = DPA_MAGIC;
  111. #endif
  112. }
  113. return pdpa;
  114. }
  115. BOOL DPA_Destroy(HDPA pdpa)
  116. {
  117. //assert(IsDPA(pdpa));
  118. if (pdpa == NULL) // allow NULL for low memory cases, still assert
  119. return TRUE;
  120. assert (pdpa->hheap);
  121. #ifdef DEBUG
  122. pdpa->cp = 0;
  123. pdpa->cpAlloc = 0;
  124. pdpa->magic = 0;
  125. #endif
  126. if (pdpa->pp && !ControlFree(pdpa->hheap, pdpa->pp))
  127. return FALSE;
  128. return ControlFree(pdpa->hheap, pdpa);
  129. }
  130. HDPA DPA_Clone(HDPA pdpa, HDPA pdpaNew)
  131. {
  132. BOOL fAlloc = FALSE;
  133. if (!pdpaNew)
  134. {
  135. pdpaNew = DPA_CreateEx(pdpa->cpGrow, pdpa->hheap);
  136. if (!pdpaNew)
  137. return NULL;
  138. fAlloc = TRUE;
  139. }
  140. if (!DPA_Grow(pdpaNew, pdpa->cpAlloc)) {
  141. if (!fAlloc)
  142. DPA_Destroy(pdpaNew);
  143. return NULL;
  144. }
  145. pdpaNew->cp = pdpa->cp;
  146. hmemcpy(pdpaNew->pp, pdpa->pp, pdpa->cp * sizeof(void *));
  147. return pdpaNew;
  148. }
  149. void * DPA_GetPtr(HDPA pdpa, int index)
  150. {
  151. // assert(IsDPA(pdpa));
  152. if (index < 0 || index >= pdpa->cp)
  153. return NULL;
  154. return pdpa->pp[index];
  155. }
  156. int DPA_GetPtrIndex(HDPA pdpa, void * p)
  157. {
  158. void **pp;
  159. void **ppMax;
  160. if (pdpa->pp)
  161. {
  162. pp = pdpa->pp;
  163. ppMax = pp + pdpa->cp;
  164. for ( ; pp < ppMax; pp++)
  165. {
  166. if (*pp == p)
  167. return (pp - pdpa->pp);
  168. }
  169. }
  170. return -1;
  171. }
  172. BOOL DPA_Grow(HDPA pdpa, int cpAlloc)
  173. {
  174. if (cpAlloc > pdpa->cpAlloc)
  175. {
  176. void **ppNew;
  177. cpAlloc = ((cpAlloc + pdpa->cpGrow - 1) / pdpa->cpGrow) * pdpa->cpGrow;
  178. if (pdpa->pp)
  179. ppNew = (void * *)ControlReAlloc(pdpa->hheap, pdpa->pp, cpAlloc * sizeof(void *));
  180. else
  181. ppNew = (void * *)ControlAlloc(pdpa->hheap, cpAlloc * sizeof(void *));
  182. if (!ppNew)
  183. return FALSE;
  184. pdpa->pp = ppNew;
  185. pdpa->cpAlloc = cpAlloc;
  186. }
  187. return TRUE;
  188. }
  189. BOOL DPA_SetPtr(HDPA pdpa, int index, void * p)
  190. {
  191. if (index < 0)
  192. {
  193. // DebugMsg(DM_ERROR, "DPA: Invalid index: %d", index);
  194. return FALSE;
  195. }
  196. if (index >= pdpa->cp)
  197. {
  198. if (!DPA_Grow(pdpa, index + 1))
  199. return FALSE;
  200. pdpa->cp = index + 1;
  201. }
  202. pdpa->pp[index] = p;
  203. return TRUE;
  204. }
  205. int DPA_InsertPtr(HDPA pdpa, int index, void * p)
  206. {
  207. if (index < 0)
  208. {
  209. return -1;
  210. }
  211. if (index > pdpa->cp)
  212. index = pdpa->cp;
  213. // Make sure we have room for one more item
  214. //
  215. if (pdpa->cp + 1 > pdpa->cpAlloc)
  216. {
  217. if (!DPA_Grow(pdpa, pdpa->cp + 1))
  218. return -1;
  219. }
  220. // If we are inserting, we need to slide everybody up
  221. //
  222. if (index < pdpa->cp)
  223. {
  224. hmemcpy(&pdpa->pp[index + 1], &pdpa->pp[index],
  225. (pdpa->cp - index) * sizeof(void *));
  226. }
  227. pdpa->pp[index] = p;
  228. pdpa->cp++;
  229. return index;
  230. }
  231. void * DPA_DeletePtr(HDPA pdpa, int index)
  232. {
  233. void * p;
  234. // assert(IsDPA(pdpa));
  235. if (index < 0 || index >= pdpa->cp)
  236. {
  237. // DebugMsg(DM_ERROR, "DPA: Invalid index: %d", index);
  238. return NULL;
  239. }
  240. p = pdpa->pp[index];
  241. if (index < pdpa->cp - 1)
  242. {
  243. hmemcpy(&pdpa->pp[index], &pdpa->pp[index + 1],
  244. (pdpa->cp - (index + 1)) * sizeof(void *));
  245. }
  246. pdpa->cp--;
  247. if (pdpa->cpAlloc - pdpa->cp > pdpa->cpGrow)
  248. {
  249. void **ppNew;
  250. ppNew = ControlReAlloc(pdpa->hheap, pdpa->pp, (pdpa->cpAlloc - pdpa->cpGrow) * sizeof(void *));
  251. assert(ppNew);
  252. pdpa->pp = ppNew;
  253. pdpa->cpAlloc -= pdpa->cpGrow;
  254. }
  255. return p;
  256. }
  257. BOOL DPA_DeleteAllPtrs(HDPA pdpa)
  258. {
  259. if (pdpa->pp && !ControlFree(pdpa->hheap, pdpa->pp))
  260. return FALSE;
  261. pdpa->pp = NULL;
  262. pdpa->cp = pdpa->cpAlloc = 0;
  263. return TRUE;
  264. }
  265. BOOL DPA_Sort(HDPA pdpa, PFNDPACOMPARE pfnCmp, LPARAM lParam)
  266. {
  267. SORTPARAMS sp;
  268. sp.cp = pdpa->cp;
  269. sp.pp = pdpa->pp;
  270. sp.pfnCmp = pfnCmp;
  271. sp.lParam = lParam;
  272. return DPA_MergeSort(&sp);
  273. }
  274. #define SortCompare(psp, pp1, i1, pp2, i2) \
  275. (psp->pfnCmp(pp1[i1], pp2[i2], psp->lParam))
  276. //
  277. // This function merges two sorted lists and makes one sorted list.
  278. // psp->pp[iFirst, iFirst+cItes/2-1], psp->pp[iFirst+cItems/2, iFirst+cItems-1]
  279. //
  280. void DPA_MergeThem(SORTPARAMS * psp, int iFirst, int cItems)
  281. {
  282. //
  283. // Notes:
  284. // This function is separated from DPA_MergeSort2() to avoid comsuming
  285. // stack variables. Never inline this.
  286. //
  287. int cHalf = cItems/2;
  288. int iIn1, iIn2, iOut;
  289. LPVOID * ppvSrc = &psp->pp[iFirst];
  290. // Copy the first part to temp storage so we can write directly into
  291. // the final buffer. Note that this takes at most psp->cp/2 DWORD's
  292. hmemcpy(psp->ppT, ppvSrc, cHalf*sizeof(LPVOID));
  293. for (iIn1=0, iIn2=cHalf, iOut=0;;)
  294. {
  295. if (SortCompare(psp, psp->ppT, iIn1, ppvSrc, iIn2) <= 0) {
  296. ppvSrc[iOut++] = psp->ppT[iIn1++];
  297. if (iIn1==cHalf) {
  298. // We used up the first half; the rest of the second half
  299. // should already be in place
  300. break;
  301. }
  302. } else {
  303. ppvSrc[iOut++] = ppvSrc[iIn2++];
  304. if (iIn2==cItems) {
  305. // We used up the second half; copy the rest of the first half
  306. // into place
  307. hmemcpy(&ppvSrc[iOut], &psp->ppT[iIn1], (cItems-iOut)*sizeof(LPVOID));
  308. break;
  309. }
  310. }
  311. }
  312. }
  313. //
  314. // This function sorts a give list (psp->pp[iFirst,iFirst-cItems-1]).
  315. //
  316. void DPA_MergeSort2(SORTPARAMS * psp, int iFirst, int cItems)
  317. {
  318. //
  319. // Notes:
  320. // This function is recursively called. Therefore, we should minimize
  321. // the number of local variables and parameters. At this point, we
  322. // use one local variable and three parameters.
  323. //
  324. int cHalf;
  325. switch(cItems)
  326. {
  327. case 1:
  328. return;
  329. case 2:
  330. // Swap them, if they are out of order.
  331. if (SortCompare(psp, psp->pp, iFirst, psp->pp, iFirst+1) > 0)
  332. {
  333. psp->ppT[0] = psp->pp[iFirst];
  334. psp->pp[iFirst] = psp->pp[iFirst+1];
  335. psp->pp[iFirst+1] = psp->ppT[0];
  336. }
  337. break;
  338. default:
  339. cHalf = cItems/2;
  340. // Sort each half
  341. DPA_MergeSort2(psp, iFirst, cHalf);
  342. DPA_MergeSort2(psp, iFirst+cHalf, cItems-cHalf);
  343. // Then, merge them.
  344. DPA_MergeThem(psp, iFirst, cItems);
  345. break;
  346. }
  347. }
  348. BOOL DPA_MergeSort(SORTPARAMS * psp)
  349. {
  350. if (psp->cp==0)
  351. return TRUE;
  352. // Note that we divide by 2 below; we want to round down
  353. psp->ppT = LocalAlloc(LPTR, psp->cp/2 * sizeof(LPVOID));
  354. if (!psp->ppT)
  355. return FALSE;
  356. DPA_MergeSort2(psp, 0, psp->cp);
  357. LocalFree(psp->ppT);
  358. return TRUE;
  359. }
  360. // Search function
  361. //
  362. int DPA_Search(HDPA pdpa, void * pFind, int iStart,
  363. PFNDPACOMPARE pfnCompare, LPARAM lParam, UINT options)
  364. {
  365. int cp = DPA_GetPtrCount(pdpa);
  366. assert(pfnCompare);
  367. assert(0 <= iStart);
  368. // Only allow these wierd flags if the list is sorted
  369. assert((options & DPAS_SORTED) || !(options & (DPAS_INSERTBEFORE | DPAS_INSERTAFTER)));
  370. if (!(options & DPAS_SORTED))
  371. {
  372. // Not sorted: do lisearch.
  373. int i;
  374. for (i = iStart; i < cp; i++)
  375. {
  376. if (0 == pfnCompare(pFind, DPA_FastGetPtr(pdpa, i), lParam))
  377. return i;
  378. }
  379. return -1;
  380. }
  381. else
  382. {
  383. // Search the array using binary search. If several adjacent
  384. // elements match the target element, the index of the first
  385. // matching element is returned.
  386. int iRet = -1; // assume no match
  387. BOOL bFound = FALSE;
  388. int nCmp = 0;
  389. int iLow = 0; // Don't bother using iStart for binary search
  390. int iMid = 0;
  391. int iHigh = cp - 1;
  392. // (OK for cp == 0)
  393. while (iLow <= iHigh)
  394. {
  395. iMid = (iLow + iHigh) / 2;
  396. nCmp = pfnCompare(pFind, DPA_FastGetPtr(pdpa, iMid), lParam);
  397. if (0 > nCmp)
  398. iHigh = iMid - 1; // First is smaller
  399. else if (0 < nCmp)
  400. iLow = iMid + 1; // First is larger
  401. else
  402. {
  403. // Match; search back for first match
  404. bFound = TRUE;
  405. while (0 < iMid)
  406. {
  407. if (0 != pfnCompare(pFind, DPA_FastGetPtr(pdpa, iMid-1), lParam))
  408. break;
  409. else
  410. iMid--;
  411. }
  412. break;
  413. }
  414. }
  415. if (bFound)
  416. {
  417. assert(0 <= iMid);
  418. iRet = iMid;
  419. }
  420. // Did the search fail AND
  421. // is one of the strange search flags set?
  422. if (!bFound && (options & (DPAS_INSERTAFTER | DPAS_INSERTBEFORE)))
  423. {
  424. // Yes; return the index where the target should be inserted
  425. // if not found
  426. if (0 < nCmp) // First is larger
  427. iRet = iLow;
  428. else
  429. iRet = iMid;
  430. // (We don't distinguish between the two flags anymore)
  431. }
  432. else if ( !(options & (DPAS_INSERTAFTER | DPAS_INSERTBEFORE)) )
  433. {
  434. // Sanity check with lisearch
  435. assert(DPA_Search(pdpa, pFind, iStart, pfnCompare, lParam, options & ~DPAS_SORTED) == iRet);
  436. }
  437. return iRet;
  438. }
  439. }
  440. //===========================================================================
  441. //
  442. // String ptr management routines
  443. //
  444. // Copy as much of *psz to *pszBuf as will fit
  445. //
  446. int Str_GetPtr(LPCSTR psz, LPSTR pszBuf, int cchBuf)
  447. {
  448. int cch = 0;
  449. // if pszBuf is NULL, just return length of string.
  450. //
  451. if (!pszBuf && psz)
  452. return lstrlen(psz);
  453. if (cchBuf)
  454. {
  455. if (psz)
  456. {
  457. cch = lstrlen(psz);
  458. if (cch > cchBuf - 1)
  459. cch = cchBuf - 1;
  460. hmemcpy(pszBuf, psz, cch);
  461. }
  462. pszBuf[cch] = 0;
  463. }
  464. return cch;
  465. }
  466. BOOL Str_Set(LPSTR *ppsz, LPCSTR psz)
  467. {
  468. if (!psz)
  469. {
  470. if (*ppsz)
  471. {
  472. LocalFree(*ppsz);
  473. *ppsz = NULL;
  474. }
  475. }
  476. else
  477. {
  478. LPSTR pszNew;
  479. UINT cbSize = lstrlen(psz) + 1;
  480. if (*ppsz)
  481. pszNew = LocalReAlloc(*ppsz, cbSize, LMEM_MOVEABLE | LMEM_ZEROINIT);
  482. else
  483. pszNew = LocalAlloc(LPTR, cbSize);
  484. if (!pszNew)
  485. return FALSE;
  486. lstrcpy(pszNew, psz);
  487. *ppsz = pszNew;
  488. }
  489. return TRUE;
  490. }
  491. // Set *ppsz to a copy of psz, reallocing as needed
  492. //
  493. BOOL Str_SetPtr(LPSTR * ppsz, LPCSTR psz)
  494. {
  495. if (!psz)
  496. {
  497. if (*ppsz)
  498. {
  499. Free(*ppsz);
  500. *ppsz = NULL;
  501. }
  502. }
  503. else
  504. {
  505. LPSTR pszNew = (LPSTR)ReAlloc(*ppsz, lstrlen(psz) + 1);
  506. if (!pszNew)
  507. return FALSE;
  508. lstrcpy(pszNew, psz);
  509. *ppsz = pszNew;
  510. }
  511. return TRUE;
  512. }