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.

973 lines
24 KiB

  1. /*
  2. * ptrarray.c - Pointer array ADT module.
  3. */
  4. /*
  5. Pointer array structures are allocated by AllocateMemory(). Handles to
  6. pointer arrays are pointers to ARRAYs. Each ARRAY contains a pointer to an
  7. rray of pointers in the pointer array. Each array of pointers is allocated by
  8. GlobalAlloc() to allow it to grow to greater than 64 Kb in size. Pointer
  9. arrays are 0-based. Array elements are accessed using pointers. If this
  10. proves to be too slow, we'll go to pointers with a 64 Kb limit on total array
  11. size.
  12. Pointer arrays are created with pointer comparison functions for sorting and
  13. searching. The sorting comparison function is used to insert new pointers into
  14. the pointer array in sorted order. The searching comparison function is used
  15. to search the sorted pointer array for a pointer. The sorting comparison
  16. function is passed the pointer to be added to the pointer array and a pointer
  17. from the pointer array for comparison. The searching comparison function is
  18. passed a pointer to the information being searched for and a pointer from the
  19. pointer array for comparison.
  20. */
  21. /* Headers
  22. **********/
  23. #include "project.h"
  24. #pragma hdrstop
  25. /* Macros
  26. *********/
  27. /* extract array element */
  28. #define ARRAY_ELEMENT(ppa, ai) (((ppa)->ppcvArray)[(ai)])
  29. /* Add pointers to array in sorted order? */
  30. #define ADD_PTRS_IN_SORTED_ORDER(ppa) IS_FLAG_SET((ppa)->dwFlags, PA_FL_SORTED_ADD)
  31. /* Types
  32. ********/
  33. /* pointer array flags */
  34. typedef enum _ptrarrayflags
  35. {
  36. /* Insert elements in sorted order. */
  37. PA_FL_SORTED_ADD = 0x0001,
  38. /* flag combinations */
  39. ALL_PA_FLAGS = PA_FL_SORTED_ADD
  40. }
  41. PTRARRAYFLAGS;
  42. /* pointer array structure */
  43. /*
  44. * Free elements in the ppcvArray[] array lie between indexes (aicPtrsUsed)
  45. * and (aiLast), inclusive.
  46. */
  47. typedef struct _ptrarray
  48. {
  49. /* elements to grow array by after it fills up */
  50. ARRAYINDEX aicPtrsToGrowBy;
  51. /* array flags */
  52. DWORD dwFlags;
  53. /* pointer to base of array */
  54. PCVOID *ppcvArray;
  55. /* index of last element allocated in array */
  56. ARRAYINDEX aicPtrsAllocated;
  57. /*
  58. * (We keep a count of the number of elements used instead of the index of
  59. * the last element used so that this value is 0 for an empty array, and not
  60. * some non-zero sentinel value.)
  61. */
  62. /* number of elements used in array */
  63. ARRAYINDEX aicPtrsUsed;
  64. }
  65. PTRARRAY;
  66. DECLARE_STANDARD_TYPES(PTRARRAY);
  67. /***************************** Private Functions *****************************/
  68. /* Module Prototypes
  69. ********************/
  70. PRIVATE_CODE BOOL AddAFreePtrToEnd(PPTRARRAY);
  71. PRIVATE_CODE void PtrHeapSwap(PPTRARRAY, ARRAYINDEX, ARRAYINDEX);
  72. PRIVATE_CODE void PtrHeapSift(PPTRARRAY, ARRAYINDEX, ARRAYINDEX, COMPARESORTEDPTRSPROC);
  73. #ifdef VSTF
  74. PRIVATE_CODE BOOL IsValidPCNEWPTRARRAY(PCNEWPTRARRAY);
  75. PRIVATE_CODE BOOL IsValidPCPTRARRAY(PCPTRARRAY);
  76. #endif
  77. #if defined(DEBUG) || defined(VSTF)
  78. PRIVATE_CODE BOOL IsPtrArrayInSortedOrder(PCPTRARRAY, COMPARESORTEDPTRSPROC);
  79. #endif
  80. /*
  81. ** AddAFreePtrToEnd()
  82. **
  83. ** Adds a free element to the end of an array.
  84. **
  85. ** Arguments: pa - pointer to array
  86. **
  87. ** Returns: TRUE if successful, or FALSE if not.
  88. **
  89. ** Side Effects: May grow the array.
  90. */
  91. PRIVATE_CODE BOOL AddAFreePtrToEnd(PPTRARRAY pa)
  92. {
  93. BOOL bResult;
  94. ASSERT(IS_VALID_STRUCT_PTR(pa, CPTRARRAY));
  95. /* Are there any free elements in the array? */
  96. if (pa->aicPtrsUsed < pa->aicPtrsAllocated)
  97. /* Yes. Return the next free pointer. */
  98. bResult = TRUE;
  99. else
  100. {
  101. ARRAYINDEX aicNewPtrs = pa->aicPtrsAllocated + pa->aicPtrsToGrowBy;
  102. PCVOID *ppcvArray;
  103. bResult = FALSE;
  104. /* Try to grow the array. */
  105. /* Blow off unlikely overflow conditions as ASSERT()s. */
  106. ASSERT(pa->aicPtrsAllocated <= ARRAYINDEX_MAX + 1);
  107. ASSERT(ARRAYINDEX_MAX + 1 - pa->aicPtrsToGrowBy >= pa->aicPtrsAllocated);
  108. #ifdef DBLCHECK
  109. ASSERT((double)aicNewPtrs * (double)(sizeof(PVOID)) <= (double)DWORD_MAX);
  110. #endif
  111. /* Try to grow the array. */
  112. if (ReallocateMemory((PVOID)(pa->ppcvArray), aicNewPtrs * sizeof(*ppcvArray), (PVOID *)(&ppcvArray)))
  113. {
  114. /*
  115. * Array reallocated successfully. Set up PTRARRAY fields, and return
  116. * the first free index.
  117. */
  118. pa->ppcvArray = ppcvArray;
  119. pa->aicPtrsAllocated = aicNewPtrs;
  120. bResult = TRUE;
  121. }
  122. }
  123. return(bResult);
  124. }
  125. /*
  126. ** PtrHeapSwap()
  127. **
  128. ** Swaps two elements in an array.
  129. **
  130. ** Arguments: pa - pointer to array
  131. ** aiFirst - index of first element
  132. ** aiSecond - index of second element
  133. **
  134. ** Returns: void
  135. **
  136. ** Side Effects: none
  137. */
  138. PRIVATE_CODE void PtrHeapSwap(PPTRARRAY pa, ARRAYINDEX ai1, ARRAYINDEX ai2)
  139. {
  140. PCVOID pcvTemp;
  141. ASSERT(IS_VALID_STRUCT_PTR(pa, CPTRARRAY));
  142. ASSERT(ai1 >= 0);
  143. ASSERT(ai1 < pa->aicPtrsUsed);
  144. ASSERT(ai2 >= 0);
  145. ASSERT(ai2 < pa->aicPtrsUsed);
  146. pcvTemp = ARRAY_ELEMENT(pa, ai1);
  147. ARRAY_ELEMENT(pa, ai1) = ARRAY_ELEMENT(pa, ai2);
  148. ARRAY_ELEMENT(pa, ai2) = pcvTemp;
  149. return;
  150. }
  151. /*
  152. ** PtrHeapSift()
  153. **
  154. ** Sifts an element down in an array until the partially ordered tree property
  155. ** is retored.
  156. **
  157. ** Arguments: pa - pointer to array
  158. ** aiFirst - index of element to sift down
  159. ** aiLast - index of last element in subtree
  160. ** cspp - element comparison callback function to be called to
  161. ** compare elements
  162. **
  163. ** Returns: void
  164. **
  165. ** Side Effects: none
  166. */
  167. PRIVATE_CODE void PtrHeapSift(PPTRARRAY pa, ARRAYINDEX aiFirst, ARRAYINDEX aiLast,
  168. COMPARESORTEDPTRSPROC cspp)
  169. {
  170. ARRAYINDEX ai;
  171. PCVOID pcvTemp;
  172. ASSERT(IS_VALID_STRUCT_PTR(pa, CPTRARRAY));
  173. ASSERT(IS_VALID_CODE_PTR(cspp, COMPARESORTEDPTRSPROC));
  174. ASSERT(aiFirst >= 0);
  175. ASSERT(aiFirst < pa->aicPtrsUsed);
  176. ASSERT(aiLast >= 0);
  177. ASSERT(aiLast < pa->aicPtrsUsed);
  178. ai = aiFirst * 2;
  179. pcvTemp = ARRAY_ELEMENT(pa, aiFirst);
  180. while (ai <= aiLast)
  181. {
  182. if (ai < aiLast &&
  183. (*cspp)(ARRAY_ELEMENT(pa, ai), ARRAY_ELEMENT(pa, ai + 1)) == CR_FIRST_SMALLER)
  184. ai++;
  185. if ((*cspp)(pcvTemp, ARRAY_ELEMENT(pa, ai)) != CR_FIRST_SMALLER)
  186. break;
  187. ARRAY_ELEMENT(pa, aiFirst) = ARRAY_ELEMENT(pa, ai);
  188. aiFirst = ai;
  189. ai *= 2;
  190. }
  191. ARRAY_ELEMENT(pa, aiFirst) = pcvTemp;
  192. return;
  193. }
  194. #ifdef VSTF
  195. /*
  196. ** IsValidPCNEWPTRARRAY()
  197. **
  198. **
  199. **
  200. ** Arguments:
  201. **
  202. ** Returns:
  203. **
  204. ** Side Effects: none
  205. */
  206. PRIVATE_CODE BOOL IsValidPCNEWPTRARRAY(PCNEWPTRARRAY pcnpa)
  207. {
  208. BOOL bResult;
  209. /*
  210. * Given the current value of ARRAYINDEX_MAX (ULONG_MAX - 1), we don't
  211. * really need a check like:
  212. *
  213. * (pcna->aicInitialPtrs - 1 <= ARRAYINDEX_MAX)
  214. *
  215. * since the maximum value of the aicInitialPtrs field (ULONG_MAX) still
  216. * yields a valid top index:
  217. *
  218. * (ULONG_MAX) - 1 == (ULONG_MAX - 1)
  219. *
  220. * ARRAYINDEX_MAX == (ULONG_MAX - 1)
  221. *
  222. * But we'll leave the clause here anyway in case things change.
  223. */
  224. if (IS_VALID_READ_PTR(pcnpa, CNEWPTRARRAY) &&
  225. EVAL(pcnpa->aicInitialPtrs >= 0) &&
  226. EVAL(pcnpa->aicInitialPtrs < ARRAYINDEX_MAX) &&
  227. EVAL(pcnpa->aicAllocGranularity > 0) &&
  228. FLAGS_ARE_VALID(pcnpa->dwFlags, ALL_NPA_FLAGS))
  229. bResult = TRUE;
  230. else
  231. bResult = FALSE;
  232. return(bResult);
  233. }
  234. /*
  235. ** IsValidPCPTRARRAY()
  236. **
  237. **
  238. **
  239. ** Arguments:
  240. **
  241. ** Returns:
  242. **
  243. ** Side Effects: none
  244. */
  245. PRIVATE_CODE BOOL IsValidPCPTRARRAY(PCPTRARRAY pcpa)
  246. {
  247. BOOL bResult;
  248. if (IS_VALID_READ_PTR(pcpa, CPTRARRAY) &&
  249. EVAL(pcpa->aicPtrsToGrowBy > 0) &&
  250. FLAGS_ARE_VALID(pcpa->dwFlags, ALL_PA_FLAGS) &&
  251. EVAL(pcpa->aicPtrsAllocated >= 0) &&
  252. IS_VALID_READ_BUFFER_PTR(pcpa->ppcvArray, PCVOID, (pcpa->aicPtrsAllocated) * sizeof(*(pcpa->ppcvArray))) &&
  253. (EVAL(pcpa->aicPtrsUsed >= 0) &&
  254. EVAL(pcpa->aicPtrsUsed <= pcpa->aicPtrsAllocated)))
  255. bResult = TRUE;
  256. else
  257. bResult = FALSE;
  258. return(bResult);
  259. }
  260. #endif
  261. #if defined(DEBUG) || defined(VSTF)
  262. /*
  263. ** IsPtrArrayInSortedOrder()
  264. **
  265. **
  266. **
  267. ** Arguments:
  268. **
  269. ** Returns:
  270. **
  271. ** Side Effects: none
  272. */
  273. PRIVATE_CODE BOOL IsPtrArrayInSortedOrder(PCPTRARRAY pcpa,
  274. COMPARESORTEDPTRSPROC cspp)
  275. {
  276. BOOL bResult = TRUE;
  277. /* Don't validate pcpa here. */
  278. ASSERT(IS_VALID_CODE_PTR(cspp, COMPARESORTEDPTRSPROC));
  279. if (pcpa->aicPtrsUsed > 1)
  280. {
  281. ARRAYINDEX ai;
  282. for (ai = 0; ai < pcpa->aicPtrsUsed - 1; ai++)
  283. {
  284. if ((*cspp)(ARRAY_ELEMENT(pcpa, ai), ARRAY_ELEMENT(pcpa, ai + 1))
  285. == CR_FIRST_LARGER)
  286. {
  287. bResult = FALSE;
  288. ERROR_OUT((TEXT("IsPtrArrayInSortedOrder(): Element [%ld] %#lx > following element [%ld] %#lx."),
  289. ai,
  290. ARRAY_ELEMENT(pcpa, ai),
  291. ai + 1,
  292. ARRAY_ELEMENT(pcpa, ai + 1)));
  293. break;
  294. }
  295. }
  296. }
  297. return(bResult);
  298. }
  299. #endif
  300. /****************************** Public Functions *****************************/
  301. /*
  302. ** CreatePtrArray()
  303. **
  304. ** Creates a pointer array.
  305. **
  306. ** Arguments: pcna - pointer to NEWPTRARRAY describing the array to be
  307. ** created
  308. **
  309. ** Returns: Handle to the new array if successful, or NULL if
  310. ** unsuccessful.
  311. **
  312. ** Side Effects: none
  313. */
  314. PUBLIC_CODE BOOL CreatePtrArray(PCNEWPTRARRAY pcna, PHPTRARRAY phpa)
  315. {
  316. PCVOID *ppcvArray;
  317. ASSERT(IS_VALID_STRUCT_PTR(pcna, CNEWPTRARRAY));
  318. ASSERT(IS_VALID_WRITE_PTR(phpa, HPTRARRAY));
  319. /* Try to allocate the initial array. */
  320. *phpa = NULL;
  321. if (AllocateMemory(pcna->aicInitialPtrs * sizeof(*ppcvArray), (PVOID *)(&ppcvArray)))
  322. {
  323. PPTRARRAY pa;
  324. /* Try to allocate PTRARRAY structure. */
  325. if (AllocateMemory(sizeof(*pa), &pa))
  326. {
  327. /* Initialize PTRARRAY fields. */
  328. pa->aicPtrsToGrowBy = pcna->aicAllocGranularity;
  329. pa->ppcvArray = ppcvArray;
  330. pa->aicPtrsAllocated = pcna->aicInitialPtrs;
  331. pa->aicPtrsUsed = 0;
  332. /* Set flags. */
  333. if (IS_FLAG_SET(pcna->dwFlags, NPA_FL_SORTED_ADD))
  334. pa->dwFlags = PA_FL_SORTED_ADD;
  335. else
  336. pa->dwFlags = 0;
  337. *phpa = (HPTRARRAY)pa;
  338. ASSERT(IS_VALID_HANDLE(*phpa, PTRARRAY));
  339. }
  340. else
  341. /* Unlock and free array (ignoring return values). */
  342. FreeMemory((PVOID)(ppcvArray));
  343. }
  344. return(*phpa != NULL);
  345. }
  346. /*
  347. ** DestroyPtrArray()
  348. **
  349. ** Destroys an array.
  350. **
  351. ** Arguments: hpa - handle to array to be destroyed
  352. **
  353. ** Returns: void
  354. **
  355. ** Side Effects: none
  356. */
  357. PUBLIC_CODE void DestroyPtrArray(HPTRARRAY hpa)
  358. {
  359. ASSERT(IS_VALID_HANDLE(hpa, PTRARRAY));
  360. /* Free the array. */
  361. ASSERT(((PCPTRARRAY)hpa)->ppcvArray);
  362. FreeMemory((PVOID)(((PCPTRARRAY)hpa)->ppcvArray));
  363. /* Free PTRARRAY structure. */
  364. FreeMemory((PPTRARRAY)hpa);
  365. return;
  366. }
  367. #pragma warning(disable:4100) /* "unreferenced formal parameter" warning */
  368. /*
  369. ** InsertPtr()
  370. **
  371. ** Adds an element to an array at a given index.
  372. **
  373. ** Arguments: hpa - handle to array that element is to be added to
  374. ** aiInsert - index where new element is to be inserted
  375. ** pcvNew - pointer to element to add to array
  376. **
  377. ** Returns: TRUE if the element was inserted successfully, or FALSE if
  378. ** not.
  379. **
  380. ** Side Effects: The array may be grown.
  381. **
  382. ** N.b., for an array marked PA_FL_SORTED_ADD, this index should only be
  383. ** retrieved using SearchSortedArray(), or the sorted order will be destroyed.
  384. */
  385. PUBLIC_CODE BOOL InsertPtr(HPTRARRAY hpa, COMPARESORTEDPTRSPROC cspp, ARRAYINDEX aiInsert, PCVOID pcvNew)
  386. {
  387. BOOL bResult;
  388. ASSERT(IS_VALID_HANDLE(hpa, PTRARRAY));
  389. ASSERT(aiInsert >= 0);
  390. ASSERT(aiInsert <= ((PCPTRARRAY)hpa)->aicPtrsUsed);
  391. #ifdef DEBUG
  392. /* Make sure the correct index was given for insertion. */
  393. if (ADD_PTRS_IN_SORTED_ORDER((PCPTRARRAY)hpa))
  394. {
  395. ARRAYINDEX aiNew;
  396. EVAL(! SearchSortedArray(hpa, cspp, pcvNew, &aiNew));
  397. ASSERT(aiInsert == aiNew);
  398. }
  399. #endif
  400. /* Get a free element in the array. */
  401. bResult = AddAFreePtrToEnd((PPTRARRAY)hpa);
  402. if (bResult)
  403. {
  404. ASSERT(((PCPTRARRAY)hpa)->aicPtrsUsed < ARRAYINDEX_MAX);
  405. /* Open a slot for the new element. */
  406. MoveMemory((PVOID)& ARRAY_ELEMENT((PPTRARRAY)hpa, aiInsert + 1),
  407. & ARRAY_ELEMENT((PPTRARRAY)hpa, aiInsert),
  408. (((PCPTRARRAY)hpa)->aicPtrsUsed - aiInsert) * sizeof(ARRAY_ELEMENT((PCPTRARRAY)hpa, 0)));
  409. /* Put the new element in the open slot. */
  410. ARRAY_ELEMENT((PPTRARRAY)hpa, aiInsert) = pcvNew;
  411. ((PPTRARRAY)hpa)->aicPtrsUsed++;
  412. }
  413. return(bResult);
  414. }
  415. #pragma warning(default:4100) /* "unreferenced formal parameter" warning */
  416. /*
  417. ** AddPtr()
  418. **
  419. ** Adds an element to an array, in sorted order if so specified at
  420. ** CreatePtrArray() time.
  421. **
  422. ** Arguments: hpa - handle to array that element is to be added to
  423. ** pcvNew - pointer to element to be added to array
  424. ** pai - pointer to ARRAYINDEX to be filled in with index of
  425. ** new element, may be NULL
  426. **
  427. ** Returns: TWINRESULT
  428. **
  429. ** Side Effects: The array may be grown.
  430. */
  431. PUBLIC_CODE BOOL AddPtr(HPTRARRAY hpa, COMPARESORTEDPTRSPROC cspp, PCVOID pcvNew, PARRAYINDEX pai)
  432. {
  433. BOOL bResult;
  434. ARRAYINDEX aiNew;
  435. ASSERT(IS_VALID_HANDLE(hpa, PTRARRAY));
  436. ASSERT(! pai || IS_VALID_WRITE_PTR(pai, ARRAYINDEX));
  437. /* Find out where the new element should go. */
  438. if (ADD_PTRS_IN_SORTED_ORDER((PCPTRARRAY)hpa))
  439. EVAL(! SearchSortedArray(hpa, cspp, pcvNew, &aiNew));
  440. else
  441. aiNew = ((PCPTRARRAY)hpa)->aicPtrsUsed;
  442. bResult = InsertPtr(hpa, cspp, aiNew, pcvNew);
  443. if (bResult && pai)
  444. *pai = aiNew;
  445. return(bResult);
  446. }
  447. /*
  448. ** DeletePtr()
  449. **
  450. ** Removes an element from an element array.
  451. **
  452. ** Arguments: ha - handle to array
  453. ** aiDelete - index of element to be deleted
  454. **
  455. ** Returns: TWINRESULT
  456. **
  457. ** Side Effects: none
  458. */
  459. PUBLIC_CODE void DeletePtr(HPTRARRAY hpa, ARRAYINDEX aiDelete)
  460. {
  461. ASSERT(IS_VALID_HANDLE(hpa, PTRARRAY));
  462. ASSERT(aiDelete >= 0);
  463. ASSERT(aiDelete < ((PCPTRARRAY)hpa)->aicPtrsUsed);
  464. /*
  465. * Compact the element array by moving down all elements past the one being
  466. * deleted.
  467. */
  468. MoveMemory((PVOID)& ARRAY_ELEMENT((PPTRARRAY)hpa, aiDelete),
  469. & ARRAY_ELEMENT((PPTRARRAY)hpa, aiDelete + 1),
  470. (((PCPTRARRAY)hpa)->aicPtrsUsed - aiDelete - 1) * sizeof(ARRAY_ELEMENT((PCPTRARRAY)hpa, 0)));
  471. /* One less element used. */
  472. ((PPTRARRAY)hpa)->aicPtrsUsed--;
  473. return;
  474. }
  475. /*
  476. ** DeleteAllPtrs()
  477. **
  478. **
  479. **
  480. ** Arguments:
  481. **
  482. ** Returns:
  483. **
  484. ** Side Effects: none
  485. */
  486. PUBLIC_CODE void DeleteAllPtrs(HPTRARRAY hpa)
  487. {
  488. ASSERT(IS_VALID_HANDLE(hpa, PTRARRAY));
  489. ((PPTRARRAY)hpa)->aicPtrsUsed = 0;
  490. return;
  491. }
  492. /*
  493. ** GetPtrCount()
  494. **
  495. ** Retrieves the number of elements in an element array.
  496. **
  497. ** Arguments: hpa - handle to array
  498. **
  499. ** Returns: TWINRESULT
  500. **
  501. ** Side Effects: none
  502. */
  503. PUBLIC_CODE ARRAYINDEX GetPtrCount(HPTRARRAY hpa)
  504. {
  505. ASSERT(IS_VALID_HANDLE(hpa, PTRARRAY));
  506. return(((PCPTRARRAY)hpa)->aicPtrsUsed);
  507. }
  508. /*
  509. ** GetPtr()
  510. **
  511. ** Retrieves an element from an array.
  512. **
  513. ** Arguments: hpa - handle to array
  514. ** ai - index of element to be retrieved
  515. **
  516. ** Returns: TWINRESULT
  517. **
  518. ** Side Effects: none
  519. */
  520. PUBLIC_CODE PVOID GetPtr(HPTRARRAY hpa, ARRAYINDEX ai)
  521. {
  522. ASSERT(IS_VALID_HANDLE(hpa, PTRARRAY));
  523. ASSERT(ai >= 0);
  524. ASSERT(ai < ((PCPTRARRAY)hpa)->aicPtrsUsed);
  525. return((PVOID)ARRAY_ELEMENT((PCPTRARRAY)hpa, ai));
  526. }
  527. /*
  528. ** SortPtrArray()
  529. **
  530. ** Sorts an array.
  531. **
  532. ** Arguments: hpa - handle to element list to be sorted
  533. ** cspp - pointer comparison callback function
  534. **
  535. ** Returns: void
  536. **
  537. ** Side Effects: none
  538. **
  539. ** Uses heap sort.
  540. */
  541. PUBLIC_CODE void SortPtrArray(HPTRARRAY hpa, COMPARESORTEDPTRSPROC cspp)
  542. {
  543. ASSERT(IS_VALID_HANDLE(hpa, PTRARRAY));
  544. /* Are there any elements to sort (2 or more)? */
  545. if (((PCPTRARRAY)hpa)->aicPtrsUsed > 1)
  546. {
  547. ARRAYINDEX ai;
  548. ARRAYINDEX aiLastUsed = ((PCPTRARRAY)hpa)->aicPtrsUsed - 1;
  549. /* Yes. Create partially ordered tree. */
  550. for (ai = aiLastUsed / 2; ai >= 0; ai--)
  551. PtrHeapSift((PPTRARRAY)hpa, ai, aiLastUsed, cspp);
  552. for (ai = aiLastUsed; ai >= 1; ai--)
  553. {
  554. /* Remove minimum from front of heap. */
  555. PtrHeapSwap((PPTRARRAY)hpa, 0, ai);
  556. /* Reestablish partially ordered tree. */
  557. PtrHeapSift((PPTRARRAY)hpa, 0, ai - 1, cspp);
  558. }
  559. }
  560. ASSERT(IsPtrArrayInSortedOrder((PCPTRARRAY)hpa, cspp));
  561. return;
  562. }
  563. /*
  564. ** SearchSortedArray()
  565. **
  566. ** Searches an array for a target element using binary search. If several
  567. ** adjacent elements match the target element, the index of the first matching
  568. ** element is returned.
  569. **
  570. ** Arguments: hpa - handle to array to be searched
  571. ** cspp - element comparison callback function to be called to
  572. ** compare the target element with an element from the
  573. ** array, the callback function is called as:
  574. **
  575. ** (*cspp)(pcvTarget, pcvPtrFromList)
  576. **
  577. ** pcvTarget - pointer to target element to search for
  578. ** pbFound - pointer to BOOL to be filled in with TRUE if the
  579. ** target element is found, or FALSE if not
  580. ** paiTarget - pointer to ARRAYINDEX to be filled in with the
  581. ** index of the first element matching the target
  582. ** element if found, otherwise filled in with the
  583. ** index where the target element should be
  584. ** inserted
  585. **
  586. ** Returns: TRUE if target element is found. FALSE if not.
  587. **
  588. ** Side Effects: none
  589. **
  590. ** We use a private version of SearchSortedArray() instead of the CRT bsearch()
  591. ** function since we want it to return the insertion index of the target
  592. ** element if the target element is not found.
  593. */
  594. PUBLIC_CODE BOOL SearchSortedArray(HPTRARRAY hpa, COMPARESORTEDPTRSPROC cspp,
  595. PCVOID pcvTarget, PARRAYINDEX paiTarget)
  596. {
  597. BOOL bFound;
  598. ASSERT(IS_VALID_HANDLE(hpa, PTRARRAY));
  599. ASSERT(IS_VALID_CODE_PTR(cspp, COMPARESORTEDPTRSPROC));
  600. ASSERT(IS_VALID_WRITE_PTR(paiTarget, ARRAYINDEX));
  601. ASSERT(ADD_PTRS_IN_SORTED_ORDER((PCPTRARRAY)hpa));
  602. #if 0
  603. ASSERT(IsPtrArrayInSortedOrder((PCPTRARRAY)hpa, ((PCPTRARRAY)hpa)->cspp));
  604. #endif
  605. bFound = FALSE;
  606. /* Are there any elements to search through? */
  607. if (((PCPTRARRAY)hpa)->aicPtrsUsed > 0)
  608. {
  609. ARRAYINDEX aiLow = 0;
  610. ARRAYINDEX aiMiddle = 0;
  611. ARRAYINDEX aiHigh = ((PCPTRARRAY)hpa)->aicPtrsUsed - 1;
  612. COMPARISONRESULT cr = CR_EQUAL;
  613. /* Yes. Search for the target element. */
  614. /*
  615. * At the end of the penultimate iteration of this loop:
  616. *
  617. * aiLow == aiMiddle == aiHigh.
  618. */
  619. ASSERT(aiHigh <= ARRAYINDEX_MAX);
  620. while (aiLow <= aiHigh)
  621. {
  622. aiMiddle = (aiLow + aiHigh) / 2;
  623. cr = (*cspp)(pcvTarget, ARRAY_ELEMENT((PCPTRARRAY)hpa, aiMiddle));
  624. if (cr == CR_FIRST_SMALLER)
  625. aiHigh = aiMiddle - 1;
  626. else if (cr == CR_FIRST_LARGER)
  627. aiLow = aiMiddle + 1;
  628. else
  629. {
  630. /*
  631. * Found a match at index aiMiddle. Search back for first match.
  632. */
  633. bFound = TRUE;
  634. while (aiMiddle > 0)
  635. {
  636. if ((*cspp)(pcvTarget, ARRAY_ELEMENT((PCPTRARRAY)hpa, aiMiddle - 1)) != CR_EQUAL)
  637. break;
  638. else
  639. aiMiddle--;
  640. }
  641. break;
  642. }
  643. }
  644. /*
  645. * Return the index of the target if found, or the index where the target
  646. * should be inserted if not found.
  647. */
  648. /*
  649. * If (cr == CR_FIRST_LARGER), the insertion index is aiLow.
  650. *
  651. * If (cr == CR_FIRST_SMALLER), the insertion index is aiMiddle.
  652. *
  653. * If (cr == CR_EQUAL), the insertion index is aiMiddle.
  654. */
  655. if (cr == CR_FIRST_LARGER)
  656. *paiTarget = aiLow;
  657. else
  658. *paiTarget = aiMiddle;
  659. }
  660. else
  661. /*
  662. * No. The target element cannot be found in an empty array. It should
  663. * be inserted as the first element.
  664. */
  665. *paiTarget = 0;
  666. ASSERT(*paiTarget <= ((PCPTRARRAY)hpa)->aicPtrsUsed);
  667. return(bFound);
  668. }
  669. /*
  670. ** LinearSearchArray()
  671. **
  672. ** Searches an array for a target element using binary search. If several
  673. ** adjacent elements match the target element, the index of the first matching
  674. ** element is returned.
  675. **
  676. ** Arguments: hpa - handle to array to be searched
  677. ** cupp - element comparison callback function to be called to
  678. ** compare the target element with an element from the
  679. ** array, the callback function is called as:
  680. **
  681. ** (*cupp)(pvTarget, pvPtrFromList)
  682. **
  683. ** the callback function should return a value based upon
  684. ** the result of the element comparison as follows:
  685. **
  686. ** FALSE, pvTarget == pvPtrFromList
  687. ** TRUE, pvTarget != pvPtrFromList
  688. **
  689. ** pvTarget - far element to target element to search for
  690. ** paiTarget - far element to ARRAYINDEX to be filled in with
  691. ** the index of the first matching element if
  692. ** found, otherwise filled in with index where
  693. ** element should be inserted
  694. **
  695. ** Returns: TRUE if target element is found. FALSE if not.
  696. **
  697. ** Side Effects: none
  698. **
  699. ** We use a private version of LinearSearchForPtr() instead of the CRT _lfind()
  700. ** function since we want it to return the insertion index of the target
  701. ** element if the target element is not found.
  702. **
  703. ** If the target element is not found the insertion index returned is the first
  704. ** element after the last used element in the array.
  705. */
  706. PUBLIC_CODE BOOL LinearSearchArray(HPTRARRAY hpa, COMPAREUNSORTEDPTRSPROC cupp,
  707. PCVOID pcvTarget, PARRAYINDEX paiTarget)
  708. {
  709. BOOL bFound;
  710. ARRAYINDEX ai;
  711. ASSERT(IS_VALID_HANDLE(hpa, PTRARRAY) &&
  712. (! cupp || IS_VALID_CODE_PTR(cupp, COMPPTRSPROC)) &&
  713. IS_VALID_WRITE_PTR(paiTarget, ARRAYINDEX));
  714. bFound = FALSE;
  715. for (ai = 0; ai < ((PCPTRARRAY)hpa)->aicPtrsUsed; ai++)
  716. {
  717. if (! (*cupp)(pcvTarget, ARRAY_ELEMENT((PCPTRARRAY)hpa, ai)))
  718. {
  719. bFound = TRUE;
  720. break;
  721. }
  722. }
  723. if (bFound)
  724. *paiTarget = ai;
  725. return(bFound);
  726. }
  727. #if defined(DEBUG) || defined(VSTF)
  728. /*
  729. ** IsValidHPTRARRAY()
  730. **
  731. **
  732. **
  733. ** Arguments:
  734. **
  735. ** Returns:
  736. **
  737. ** Side Effects: none
  738. */
  739. PUBLIC_CODE BOOL IsValidHPTRARRAY(HPTRARRAY hpa)
  740. {
  741. return(IS_VALID_STRUCT_PTR((PCPTRARRAY)hpa, CPTRARRAY));
  742. }
  743. #endif
  744. #ifdef VSTF
  745. /*
  746. ** IsValidHGLOBAL()
  747. **
  748. **
  749. **
  750. ** Arguments:
  751. **
  752. ** Returns:
  753. **
  754. ** Side Effects: none
  755. */
  756. PUBLIC_CODE BOOL IsValidHGLOBAL(HGLOBAL hg)
  757. {
  758. return(EVAL(hg != NULL));
  759. }
  760. #endif