Annotation of embedaddon/quagga/lib/pqueue.c, revision 1.1

1.1     ! misho       1: /* Priority queue functions.
        !             2:    Copyright (C) 2003 Yasuhiro Ohara
        !             3: 
        !             4: This file is part of GNU Zebra.
        !             5: 
        !             6: GNU Zebra is free software; you can redistribute it and/or modify
        !             7: it under the terms of the GNU General Public License as published
        !             8: by the Free Software Foundation; either version 2, or (at your
        !             9: option) any later version.
        !            10: 
        !            11: GNU Zebra is distributed in the hope that it will be useful, but
        !            12: WITHOUT ANY WARRANTY; without even the implied warranty of
        !            13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
        !            14: General Public License for more details.
        !            15: 
        !            16: You should have received a copy of the GNU General Public License
        !            17: along with GNU Zebra; see the file COPYING.  If not, write to the
        !            18: Free Software Foundation, Inc., 59 Temple Place - Suite 330,
        !            19: Boston, MA 02111-1307, USA.  */
        !            20: 
        !            21: #include <zebra.h>
        !            22: 
        !            23: #include "memory.h"
        !            24: #include "pqueue.h"
        !            25: 
        !            26: /* priority queue using heap sort */
        !            27: 
        !            28: /* pqueue->cmp() controls the order of sorting (i.e, ascending or
        !            29:    descending). If you want the left node to move upper of the heap
        !            30:    binary tree, make cmp() to return less than 0.  for example, if cmp
        !            31:    (10, 20) returns -1, the sorting is ascending order. if cmp (10,
        !            32:    20) returns 1, the sorting is descending order. if cmp (10, 20)
        !            33:    returns 0, this library does not do sorting (which will not be what
        !            34:    you want).  To be brief, if the contents of cmp_func (left, right)
        !            35:    is left - right, dequeue () returns the smallest node.  Otherwise
        !            36:    (if the contents is right - left), dequeue () returns the largest
        !            37:    node.  */
        !            38: 
        !            39: #define DATA_SIZE (sizeof (void *))
        !            40: #define PARENT_OF(x) ((x - 1) / 2)
        !            41: #define LEFT_OF(x)  (2 * x + 1)
        !            42: #define RIGHT_OF(x) (2 * x + 2)
        !            43: #define HAVE_CHILD(x,q) (x < (q)->size / 2)
        !            44: 
        !            45: void
        !            46: trickle_up (int index, struct pqueue *queue)
        !            47: {
        !            48:   void *tmp;
        !            49: 
        !            50:   /* Save current node as tmp node.  */
        !            51:   tmp = queue->array[index];
        !            52: 
        !            53:   /* Continue until the node reaches top or the place where the parent
        !            54:      node should be upper than the tmp node.  */
        !            55:   while (index > 0 &&
        !            56:          (*queue->cmp) (tmp, queue->array[PARENT_OF (index)]) < 0)
        !            57:     {
        !            58:       /* actually trickle up */
        !            59:       queue->array[index] = queue->array[PARENT_OF (index)];
        !            60:       if (queue->update != NULL)
        !            61:        (*queue->update) (queue->array[index], index);
        !            62:       index = PARENT_OF (index);
        !            63:     }
        !            64: 
        !            65:   /* Restore the tmp node to appropriate place.  */
        !            66:   queue->array[index] = tmp;
        !            67:   if (queue->update != NULL)
        !            68:     (*queue->update) (tmp, index);
        !            69: }
        !            70: 
        !            71: void
        !            72: trickle_down (int index, struct pqueue *queue)
        !            73: {
        !            74:   void *tmp;
        !            75:   int which;
        !            76: 
        !            77:   /* Save current node as tmp node.  */
        !            78:   tmp = queue->array[index];
        !            79: 
        !            80:   /* Continue until the node have at least one (left) child.  */
        !            81:   while (HAVE_CHILD (index, queue))
        !            82:     {
        !            83:       /* If right child exists, and if the right child is more proper
        !            84:          to be moved upper.  */
        !            85:       if (RIGHT_OF (index) < queue->size &&
        !            86:           (*queue->cmp) (queue->array[LEFT_OF (index)],
        !            87:                          queue->array[RIGHT_OF (index)]) > 0)
        !            88:         which = RIGHT_OF (index);
        !            89:       else
        !            90:         which = LEFT_OF (index);
        !            91: 
        !            92:       /* If the tmp node should be upper than the child, break.  */
        !            93:       if ((*queue->cmp) (queue->array[which], tmp) > 0)
        !            94:         break;
        !            95: 
        !            96:       /* Actually trickle down the tmp node.  */
        !            97:       queue->array[index] = queue->array[which];
        !            98:        if (queue->update != NULL)
        !            99:         (*queue->update) (queue->array[index], index);
        !           100:       index = which;
        !           101:     }
        !           102: 
        !           103:   /* Restore the tmp node to appropriate place.  */
        !           104:   queue->array[index] = tmp;
        !           105:   if (queue->update != NULL)
        !           106:     (*queue->update) (tmp, index);
        !           107: }
        !           108: 
        !           109: struct pqueue *
        !           110: pqueue_create (void)
        !           111: {
        !           112:   struct pqueue *queue;
        !           113: 
        !           114:   queue = XCALLOC (MTYPE_PQUEUE, sizeof (struct pqueue));
        !           115: 
        !           116:   queue->array = XCALLOC (MTYPE_PQUEUE_DATA, 
        !           117:                           DATA_SIZE * PQUEUE_INIT_ARRAYSIZE);
        !           118:   queue->array_size = PQUEUE_INIT_ARRAYSIZE;
        !           119: 
        !           120:   /* By default we want nothing to happen when a node changes. */
        !           121:   queue->update = NULL;
        !           122:   return queue;
        !           123: }
        !           124: 
        !           125: void
        !           126: pqueue_delete (struct pqueue *queue)
        !           127: {
        !           128:   XFREE (MTYPE_PQUEUE_DATA, queue->array);
        !           129:   XFREE (MTYPE_PQUEUE, queue);
        !           130: }
        !           131: 
        !           132: static int
        !           133: pqueue_expand (struct pqueue *queue)
        !           134: {
        !           135:   void **newarray;
        !           136: 
        !           137:   newarray = XCALLOC (MTYPE_PQUEUE_DATA, queue->array_size * DATA_SIZE * 2);
        !           138:   if (newarray == NULL)
        !           139:     return 0;
        !           140: 
        !           141:   memcpy (newarray, queue->array, queue->array_size * DATA_SIZE);
        !           142: 
        !           143:   XFREE (MTYPE_PQUEUE_DATA, queue->array);
        !           144:   queue->array = newarray;
        !           145:   queue->array_size *= 2;
        !           146: 
        !           147:   return 1;
        !           148: }
        !           149: 
        !           150: void
        !           151: pqueue_enqueue (void *data, struct pqueue *queue)
        !           152: {
        !           153:   if (queue->size + 2 >= queue->array_size && ! pqueue_expand (queue))
        !           154:     return;
        !           155: 
        !           156:   queue->array[queue->size] = data;
        !           157:   if (queue->update != NULL)
        !           158:     (*queue->update) (data, queue->size);
        !           159:   trickle_up (queue->size, queue);
        !           160:   queue->size ++;
        !           161: }
        !           162: 
        !           163: void *
        !           164: pqueue_dequeue (struct pqueue *queue)
        !           165: {
        !           166:   void *data = queue->array[0];
        !           167:   queue->array[0] =  queue->array[--queue->size];
        !           168:   trickle_down (0, queue);
        !           169:   return data;
        !           170: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>