qPriHeapLib.c
上传用户:nvosite88
上传日期:2007-01-17
资源大小:4983k
文件大小:18k
源码类别:

VxWorks

开发平台:

C/C++

  1. /* qPriHeapLib.c - heap priority queue management library */
  2. /* Copyright 1984-1998 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 01p,11nov01,dee  Add COLDFIRE support
  8. 01o,04sep98,cdp  make ARM CPUs with ARM_THUMB==TRUE use portable routines.
  9. 01n,22apr97,jpd  Added ARM to non-portable list.
  10. 01m,19mar95,dvs  removed tron references.
  11. 01l,19jul92,pme  made qPriHeapRemove return STATUS.
  12. 01k,18jul92,smb  Changed errno.h to errnoLib.h.
  13. 01j,26may92,rrr  the tree shuffle
  14. 01i,19nov91,rrr  shut up some ansi warnings.
  15. 01h,04oct91,rrr  passed through the ansification filter
  16.                   -changed functions to ansi style
  17.   -changed includes to have absolute path from h/
  18.   -changed VOID to void
  19.   -changed copyright notice
  20. 01g,23jul91,hdn  added conditional macro for optimized TRON codes.
  21. 01f,24may91,wmd  added predeclarations to avoid compiler errors.
  22. 01e,28sep90,jcf  documentation.
  23. 01d,05jul90,jcf  added qPriHeapCalibrate().
  24. 01c,26jun90,jcf  add qPriHeapResort().
  25. 01b,10may90,jcf  fixed PORTABLE definition.
  26. 01a,14jun89,jcf  written.
  27. */
  28. /*
  29. DESCRIPTION
  30. This library contains routines to manage a priority queue.  The queue is
  31. maintained in priority order in a binary tree.  This queue performs a
  32. qPriHeapPut() operation preportional in time with log base 2 of the number of
  33. nodes in the queue.  This queue is used for timer queues.  The only restriction
  34. is that the heap can only handle a static number of nodes as specified at
  35. creation time.
  36. This queue complies with the multi-way queue data structures and thus may be
  37. utilized by any multi-way queue.  The priority heap multi-way queue
  38. class is accessed by the global id qPriHeapClassId.
  39. SEE ALSO: qLib()
  40. */
  41. #include "vxWorks.h"
  42. #include "qClass.h"
  43. #include "qPriHeapLib.h"
  44. #include "stdlib.h"
  45. #include "string.h"
  46. #include "errnoLib.h"
  47. #include "stdio.h"
  48. /* XXX should break out for each architecture */
  49. /* optimized version available for 680X0 and ARM */
  50. #if (defined(PORTABLE) || 
  51.      ((CPU_FAMILY != MC680X0) && (CPU_FAMILY != ARM) && (CPU_FAMILY != COLDFIRE)) || 
  52.      ((CPU_FAMILY == ARM) && ARM_THUMB))
  53. #define qPriHeapLib_PORTABLE
  54. #endif /* (defined(PORTABLE) || (CPU_FAMILY != MC680X0)) */
  55. /* imports */
  56. IMPORT ULONG vxTicks; /* current time in ticks */
  57. /* globals */
  58. LOCAL Q_CLASS qPriHeapClass =
  59.     {
  60.     (FUNCPTR)qPriHeapCreate,
  61.     (FUNCPTR)qPriHeapInit,
  62.     (FUNCPTR)qPriHeapDelete,
  63.     (FUNCPTR)qPriHeapTerminate,
  64.     (FUNCPTR)qPriHeapPut,
  65.     (FUNCPTR)qPriHeapGet,
  66.     (FUNCPTR)qPriHeapRemove,
  67.     (FUNCPTR)qPriHeapResort,
  68.     (FUNCPTR)qPriHeapAdvance,
  69.     (FUNCPTR)qPriHeapGetExpired,
  70.     (FUNCPTR)qPriHeapKey,
  71.     (FUNCPTR)qPriHeapCalibrate,
  72.     (FUNCPTR)qPriHeapInfo,
  73.     (FUNCPTR)qPriHeapEach,
  74.     &qPriHeapClass
  75.     };
  76. Q_CLASS_ID qPriHeapClassId = &qPriHeapClass;
  77. /* forward static functions */
  78. #ifdef qPriHeapLib_PORTABLE
  79. static void qPriHeapUp (Q_PRI_HEAP_HEAD *pQPriHeapHead, int index);
  80. static void qPriHeapDown (Q_PRI_HEAP_HEAD *pQPriHeapHead, int index);
  81. #else
  82. extern void qPriHeapUp (Q_PRI_HEAP_HEAD *pQPriHeapHead, int index);
  83. extern void qPriHeapDown (Q_PRI_HEAP_HEAD *pQPriHeapHead, int index);
  84. #endif
  85. /******************************************************************************
  86. *
  87. * qPriHeapArrayCreate - create and initialized a heap priority queue
  88. *
  89. * Create a heap priority queue.  Initialize the specified queue header.
  90. *
  91. * RETURNS: OK or ERROR if not enough memory to create queue.
  92. *
  93. * SEE ALSO: qPriHeapInit (2)
  94. */
  95. HEAP_ARRAY *qPriHeapArrayCreate
  96.     (
  97.     int heapSize
  98.     )
  99.     {
  100.     return ((HEAP_ARRAY *) malloc ((unsigned) 4 * heapSize));
  101.     }
  102. /******************************************************************************
  103. *
  104. * qPriHeapArrayDelete - deallocate a heap array
  105. *
  106. * This routine returns an allocated HEAP_ARRAY structure to the free memory
  107. * pool.
  108. *
  109. * RETURNS:
  110. *  OK, or
  111. *  ERROR if could not deallocate heap array.
  112. */
  113. STATUS qPriHeapArrayDelete
  114.     (
  115.     HEAP_ARRAY *pHeapArray
  116.     )
  117.     {
  118.     free ((char *) pHeapArray);
  119.     return OK;
  120.     }
  121. /******************************************************************************
  122. *
  123. * qPriHeapCreate - create and initialized a heap priority queue
  124. *
  125. * Create a heap priority queue.  Initialize the specified queue header.
  126. *
  127. * RETURNS: OK or ERROR if not enough memory to create queue.
  128. *
  129. * SEE ALSO: qPriHeapInit (2)
  130. */
  131. Q_PRI_HEAP_HEAD *qPriHeapCreate
  132.     (
  133.     HEAP_ARRAY *pHeapArray
  134.     )
  135.     {
  136.     Q_PRI_HEAP_HEAD *pQPriHeapHead = (Q_PRI_HEAP_HEAD *)
  137.      malloc (sizeof (Q_PRI_HEAP_HEAD));
  138.     if (pQPriHeapHead == NULL)
  139. return (NULL);
  140.     if (qPriHeapInit (pQPriHeapHead, pHeapArray) != OK)
  141. {
  142. free ((char *)pQPriHeapHead);
  143. return (NULL);
  144. }
  145.     return (pQPriHeapHead);
  146.     }
  147. /******************************************************************************
  148. *
  149. * qPriHeapInit - initialize a heap priority queue
  150. *
  151. * Initialize the heap priority queue pointed to by the specified queue
  152. * header.
  153. *
  154. * RETURNS:  OK, or ERROR if heap priority queue could not be initialized.
  155. *
  156. * ERRNO: S_qPriHeapLib_NULL_HEAP_ARRAY
  157. *
  158. */
  159. STATUS qPriHeapInit
  160.     (
  161.     Q_PRI_HEAP_HEAD *pQPriHeapHead,
  162.     HEAP_ARRAY      *pHeapArray
  163.     )
  164.     {
  165.     if (pHeapArray == NULL)
  166. {
  167. errnoSet (S_qPriHeapLib_NULL_HEAP_ARRAY);
  168. return (ERROR);
  169. }
  170.     pQPriHeapHead->pHeapArray = pHeapArray; /* store bmap list pointer */
  171.     pQPriHeapHead->pHighNode = NULL; /* zero the highest node */
  172.     pQPriHeapHead->heapIndex = 0; /* initialize the heap index */
  173.     return (OK);
  174.     }
  175. /******************************************************************************
  176. *
  177. * qPriHeapDelete - delete a priority heap queue
  178. *
  179. * This routine deallocates memory associated with the queue.  All queued
  180. * nodes are lost.
  181. *
  182. * RETURNS:
  183. *  OK, or
  184. *  ERROR if memory cannot be deallocated.
  185. */
  186. STATUS qPriHeapDelete
  187.     (
  188.     Q_PRI_HEAP_HEAD *pQPriHeapHead
  189.     )
  190.     {
  191.     free ((char *) pQPriHeapHead);
  192.     return OK;
  193.     }
  194. /******************************************************************************
  195. *
  196. * qPriHeapTerminate - terminate a heap priority queue
  197. *
  198. * This routine terminates a heap priority queue.  All queued nodes will be lost.
  199. *
  200. * ARGSUSED
  201. */
  202. STATUS qPriHeapTerminate
  203.     (
  204.     Q_PRI_HEAP_HEAD *pQPriHeapHead
  205.     )
  206.     {
  207.     return (OK);
  208.     }
  209. /*******************************************************************************
  210. *
  211. * qPriHeapPut - insert a node into a heap priority queue
  212. *
  213. * This routine inserts a node into a heap priority queue.  The insertion is
  214. * based on the priority key.  The lower the key the higher the priority.
  215. */
  216. void qPriHeapPut
  217.     (
  218.     Q_PRI_HEAP_HEAD     *pQPriHeapHead,
  219.     Q_PRI_HEAP_NODE     *pQPriHeapNode,
  220.     ULONG                key
  221.     )
  222.     {
  223.     int index = pQPriHeapHead->heapIndex++;
  224.     pQPriHeapNode->key = key;
  225.     (*pQPriHeapHead->pHeapArray)[index] = pQPriHeapNode;
  226.     qPriHeapUp (pQPriHeapHead, index);
  227.     }
  228. /*******************************************************************************
  229. *
  230. * qPriHeapGet - remove and return first node in heap priority queue
  231. *
  232. * This routine removes and returns the first node in a heap priority queue.  If
  233. * the queue is empty, NULL is returned.
  234. *
  235. * RETURNS
  236. *  Pointer to first queue node in queue head, or
  237. *  NULL if queue is empty.
  238. */
  239. Q_PRI_HEAP_NODE *qPriHeapGet
  240.     (
  241.     Q_PRI_HEAP_HEAD *pQPriHeapHead
  242.     )
  243.     {
  244.     FAST Q_PRI_HEAP_NODE **heapArray = *pQPriHeapHead->pHeapArray;
  245.     Q_PRI_HEAP_NODE *pQPriHeapNode = pQPriHeapHead->pHighNode;
  246.     if (pQPriHeapHead->heapIndex == 0)
  247. return (NULL);
  248.     else if (pQPriHeapHead->heapIndex-- == 1)
  249. pQPriHeapHead->pHighNode = NULL;
  250.     else
  251. {
  252. heapArray [0] = heapArray [pQPriHeapHead->heapIndex];
  253. qPriHeapDown (pQPriHeapHead, 0);
  254. }
  255.     return (pQPriHeapNode);
  256.     }
  257. /*******************************************************************************
  258. *
  259. * qPriHeapRemove - remove a node from a heap priority queue
  260. *
  261. * This routine removes a node from the specified heap priority queue.
  262. */
  263. STATUS qPriHeapRemove
  264.     (
  265.     Q_PRI_HEAP_HEAD *pQPriHeapHead,
  266.     Q_PRI_HEAP_NODE *pQPriHeapNode
  267.     )
  268.     {
  269.     FAST int index = pQPriHeapNode->index;
  270.     FAST Q_PRI_HEAP_NODE **heapArray = *pQPriHeapHead->pHeapArray;
  271.     int heapIndex = pQPriHeapHead->heapIndex;
  272.     if (--pQPriHeapHead->heapIndex == 0)
  273. pQPriHeapHead->pHighNode = NULL;
  274.     else
  275. {
  276. heapArray [index] = heapArray [heapIndex - 1];
  277. if ((index > 0) &&
  278.     (heapArray [(index - 1) / 2]->key > heapArray [index]->key))
  279.     qPriHeapUp (pQPriHeapHead, index);
  280. else
  281.     qPriHeapDown (pQPriHeapHead, index);
  282. }
  283.     return (OK);
  284.     }
  285. /*******************************************************************************
  286. *
  287. * qPriHeapResort - resort a node to a new position based on a new key
  288. *
  289. * This routine resorts a node to a new position based on a new key.
  290. */
  291. void qPriHeapResort
  292.     (
  293.     Q_PRI_HEAP_HEAD *pQPriHeapHead,
  294.     Q_PRI_HEAP_NODE *pQPriHeapNode,
  295.     ULONG            newKey
  296.     )
  297.     {
  298.     FAST int index = pQPriHeapNode->index;
  299.     FAST Q_PRI_HEAP_NODE **heapArray = *pQPriHeapHead->pHeapArray;
  300.     pQPriHeapNode->key = newKey;
  301.     if ((index > 0) &&
  302. (heapArray [(index - 1) / 2]->key > heapArray [index]->key))
  303. qPriHeapUp (pQPriHeapHead, index);
  304.     else
  305. qPriHeapDown (pQPriHeapHead, index);
  306.     }
  307. /*******************************************************************************
  308. *
  309. * qPriHeapAdvance - advance a queues concept of time
  310. *
  311. * Heap queues need not keep track of time because nodes contain time of
  312. * expiration.  So this routine is a NOP.
  313. *
  314. * NOMANUAL
  315. * ARGSUSED
  316. */
  317. void qPriHeapAdvance
  318.     (
  319.     Q_PRI_HEAP_HEAD *pQPriHeapHead
  320.     )
  321.     {
  322.     /* Absolute queue so advancing key of lead node unnecessary */
  323.     }
  324. /*******************************************************************************
  325. *
  326. * qPriHeapGetExpired - return a time-to-fire expired node
  327. *
  328. * This routine returns a time-to-fire expired node in a heap priority timer
  329. * queue.  Expired nodes result from a comparison with the global variable
  330. * vxTicks.  As many nodes may expire on a single advance of vxTicks, this
  331. * routine should be called inside a while loop until NULL is returned.  NULL
  332. * is returned when there are no expired nodes.
  333. *
  334. * RETURNS
  335. *  Pointer to first queue node in queue head, or
  336. *  NULL if queue is empty.
  337. */
  338. Q_PRI_HEAP_NODE *qPriHeapGetExpired
  339.     (
  340.     Q_PRI_HEAP_HEAD *pQPriHeapHead
  341.     )
  342.     {
  343.     Q_PRI_HEAP_NODE *pQPriHeapNode = pQPriHeapHead->pHighNode;
  344.     if ((pQPriHeapNode != NULL) && (pQPriHeapNode->key <= vxTicks))
  345. return (qPriHeapGet (pQPriHeapHead));
  346.     else
  347. return ((Q_PRI_HEAP_NODE *) NULL);
  348.     }
  349. /*******************************************************************************
  350. *
  351. * qPriHeapKey - return the key of a node
  352. *
  353. * This routine returns the key of a node currently in a heap priority queue.
  354. * The keyType determines key style.  A normal key style returns the nodes
  355. * internal key.  A timer queue key type style returns the key as the
  356. * time-to-fire.
  357. *
  358. * RETURNS
  359. *  Node's key, or
  360. *  node's time-to-fire.
  361. */
  362. ULONG qPriHeapKey
  363.     (
  364.     Q_PRI_HEAP_NODE *pQPriHeapNode,
  365.     int              keyType            /* 0 = normal; 1 = time queue */
  366.     )
  367.     {
  368.     if (keyType == 0)
  369. return (pQPriHeapNode->key);
  370.     else
  371. return (pQPriHeapNode->key - vxTicks);
  372.     }
  373. /*******************************************************************************
  374. *
  375. * qPriHeapCalibrate - offset every node in a queue by some delta
  376. *
  377. * This routine offsets every node in a heap priority queue by some delta.  The
  378. * offset may either by positive or negative.
  379. */
  380. void qPriHeapCalibrate
  381.     (
  382.     Q_PRI_HEAP_HEAD *pQPriHeapHead,     /* queue to calibrate nodes for */
  383.     ULONG            keyDelta           /* offset to add to each node's key */
  384.     )
  385.     {
  386.     FAST int ix;
  387.     FAST Q_PRI_HEAP_NODE **heapArray = *pQPriHeapHead->pHeapArray;
  388.     for (ix = 0; ix < pQPriHeapHead->heapIndex; ix ++)
  389.  heapArray[ix]->key += keyDelta;
  390.     }
  391. /*******************************************************************************
  392. *
  393. * qPriHeapInfo - gather information on a priority heap queue
  394. *
  395. * This routine fills up to maxNodes elements of a nodeArray with nodes
  396. * currently in a priority heap queue.  The actual number of nodes copied to the
  397. * array is returned.  If the nodeArray is NULL, then the number of nodes in
  398. * the priority heap queue is returned.
  399. *
  400. * RETURNS
  401. *  Number of node pointers copied into the nodeArray, or
  402. *  Number of nodes in multi-way queue if nodeArray is NULL
  403. */
  404. int qPriHeapInfo
  405.     (
  406.     Q_PRI_HEAP_HEAD *pQPriHeapHead,     /* heap queue to gather list for */
  407.     FAST int nodeArray[],               /* array of node pointers for filling */
  408.     FAST int maxNodes                   /* max node pointers for nodeArray */
  409.     )
  410.     {
  411.     int numNodes = min (maxNodes, pQPriHeapHead->heapIndex);
  412.     if (nodeArray == NULL) /* NULL node array means return count */
  413. return (pQPriHeapHead->heapIndex);
  414.     bcopy ((char *)*pQPriHeapHead->pHeapArray, (char *)nodeArray, numNodes * 4);
  415.     return (numNodes);
  416.     }
  417. /*******************************************************************************
  418. *
  419. * qPriHeapEach - call a routine for each node in a queue
  420. *
  421. * This routine calls a user-supplied routine once for each node in the
  422. * queue.  The routine should be declared as follows:
  423. * .CS
  424. *  BOOL routine (pQNode, arg)
  425. *      Q_PRI_HEAP_NODE *pQNode; /@ pointer to a queue node          @/
  426. *      int arg; /@ arbitrary user-supplied argument @/
  427. * .CE
  428. * The user-supplied routine should return TRUE if qPriHeapEach (2) is to
  429. * continue calling it for each entry, or FALSE if it is done and
  430. * qPriHeapEach can exit.
  431. *
  432. * RETURNS: NULL if traversed whole queue, or pointer to Q_PRI_HEAP_NODE that
  433. *          qPriHeapEach stopped on.
  434. */
  435. Q_PRI_HEAP_NODE *qPriHeapEach
  436.     (
  437.     Q_PRI_HEAP_HEAD *pQHead,    /* queue head of queue to call routine for */
  438.     FUNCPTR          routine,   /* the routine to call for each table entry */
  439.     int              routineArg /* arbitrary user-supplied argument */
  440.     )
  441.     {
  442.     FAST int ix;
  443.     for (ix = 0;
  444.  (ix < pQHead->heapIndex) &&
  445.  ((* routine) ((*pQHead->pHeapArray)[ix], routineArg));
  446.  ix ++)
  447. ;
  448.     if (ix < pQHead->heapIndex)
  449. return ((*pQHead->pHeapArray)[ix]); /* return node we ended with */
  450.     else
  451. return ((Q_PRI_HEAP_NODE *) NULL); /* did all nodes */
  452.     }
  453. #ifdef qPriHeapLib_PORTABLE
  454. /*******************************************************************************
  455. *
  456. * qPriHeapUp - elevate a node to its proper place in the heap tree
  457. *
  458. * This routine elevates a node to its proper place in the heap tree.
  459. */
  460. LOCAL void qPriHeapUp
  461.     (
  462.     Q_PRI_HEAP_HEAD *pQPriHeapHead,
  463.     int index
  464.     )
  465.     {
  466.     int workIx   = index;
  467.     int parentIx = (workIx - 1) / 2;
  468.     Q_PRI_HEAP_NODE **heapArray = *pQPriHeapHead->pHeapArray;
  469.     Q_PRI_HEAP_NODE *workNode = heapArray [workIx];
  470.     while ((workIx > 0) && (heapArray [parentIx]->key > workNode->key))
  471. {
  472. heapArray [workIx] = heapArray [parentIx];
  473. workIx = parentIx;
  474. parentIx = (workIx - 1) / 2;
  475. }
  476.     heapArray [workIx] = workNode;
  477.     pQPriHeapHead->pHighNode = heapArray [0];
  478.     }
  479. /*******************************************************************************
  480. *
  481. * qPriHeapDown - move a node down to its proper place in the heap tree
  482. *
  483. * This routine moves a node down to its proper place in the heap tree.
  484. */
  485. LOCAL void qPriHeapDown
  486.     (
  487.     Q_PRI_HEAP_HEAD *pQPriHeapHead,
  488.     int index
  489.     )
  490.     {
  491.     int workIx   = index;
  492.     int lesserChildIx;
  493.     int leftChildIx = 2 * workIx + 1;
  494.     int rightChildIx = leftChildIx + 1;
  495.     Q_PRI_HEAP_NODE **heapArray = *pQPriHeapHead->pHeapArray;
  496.     Q_PRI_HEAP_NODE *workNode = heapArray [workIx];
  497.     while (leftChildIx < pQPriHeapHead->heapIndex)
  498. {
  499. if ((rightChildIx >= pQPriHeapHead->heapIndex) ||
  500.     (heapArray [leftChildIx]->key < heapArray [rightChildIx]->key))
  501.     lesserChildIx = leftChildIx;
  502. else
  503.     lesserChildIx = rightChildIx;
  504. if (heapArray [lesserChildIx]->key < workNode->key)
  505.     {
  506.     heapArray [workIx] = heapArray [lesserChildIx];
  507.     workIx = lesserChildIx;
  508.     }
  509. else
  510.     break;
  511. leftChildIx  = 2 * workIx + 1;
  512. rightChildIx = 2 * workIx + 2;
  513. }
  514.     heapArray [workIx] = workNode;
  515.     pQPriHeapHead->pHighNode = heapArray [0];
  516.     }
  517. #endif /* qPriHeapLib_PORTABLE */
  518. /*******************************************************************************
  519. *
  520. * qPriHeapShow - dump the heap in human readable form by key or node
  521. *
  522. * This routine prints a humun readable representation of the heap to standard
  523. * out.  The two output formats are selected as: 0 node format, 1 key format.
  524. *
  525. * CAVEATS
  526. * The output is only printed for the first 16 nodes, because beyond this the
  527. * output is unintelligible.
  528. */
  529. void qPriHeapShow
  530.     (
  531.     Q_PRI_HEAP_HEAD *pHeap,     /* pointer to heap head to dump */
  532.     int format                  /* 0 - node format; 1 - key format */
  533.     )
  534.     {
  535.     int ix;
  536.     char gap[100];
  537.     char halfgap[100];
  538.     char *space = "                                               ";
  539.     int nodesPerLine = 1;
  540.     int endOfLine = 0;
  541.     int fmtlen = 3;
  542.     int limit = 15;
  543.     if (pHeap->heapIndex > 0)
  544. printf ("First: %xn", pHeap->pHighNode);
  545.     else
  546. printf ("First: NULLn");
  547.     if (format > 0)
  548. {
  549. limit = 7;
  550. fmtlen = 8;
  551. printf ("%24s"," ");
  552. }
  553.     else
  554. printf ("%29s"," ");
  555.     for (ix = 0; ix < min (pHeap->heapIndex, limit); ix ++)
  556. {
  557. if (ix == endOfLine)
  558.     {
  559.     strncpy (gap, space, 32 / nodesPerLine);
  560.     gap [(32 / nodesPerLine) - fmtlen] = EOS;
  561.     strncpy (halfgap, space, 16 / nodesPerLine);
  562.     halfgap [(16 / nodesPerLine) - fmtlen] = EOS;
  563.     nodesPerLine = nodesPerLine << 1;
  564.     endOfLine += nodesPerLine;
  565.     if (format > 0)
  566. printf ("%8xn%s", (*pHeap->pHeapArray)[ix], halfgap);
  567.     else
  568. printf ("%3dn%s", (*pHeap->pHeapArray)[ix]->key, halfgap);
  569.     }
  570. else
  571.     if (format > 0)
  572. printf ("%8x%s", (*pHeap->pHeapArray)[ix], gap);
  573.     else
  574. printf ("%3d%s", (*pHeap->pHeapArray)[ix]->key, gap);
  575. }
  576.     if (ix == limit)
  577. printf ("nTerminated at %d nodes because output gets ugly.n", limit);
  578.     else
  579. printf ("n");
  580.     }