Annotation of embedaddon/bird/filter/tree.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  *     Filters: utility functions
        !             3:  *
        !             4:  *     Copyright 1998 Pavel Machek <pavel@ucw.cz>
        !             5:  *
        !             6:  *     Can be freely distributed and used under the terms of the GNU GPL.
        !             7:  */
        !             8: 
        !             9: #include "lib/alloca.h"
        !            10: #include "nest/bird.h"
        !            11: #include "conf/conf.h"
        !            12: #include "filter/filter.h"
        !            13: 
        !            14: /**
        !            15:  * find_tree
        !            16:  * @t: tree to search in
        !            17:  * @val: value to find
        !            18:  *
        !            19:  * Search for given value in the tree. I relies on fact that sorted tree is populated
        !            20:  * by &f_val structures (that can be compared by val_compare()). In each node of tree, 
        !            21:  * either single value (then t->from==t->to) or range is present.
        !            22:  *
        !            23:  * Both set matching and |switch() { }| construction is implemented using this function,
        !            24:  * thus both are as fast as they can be.
        !            25:  */
        !            26: struct f_tree *
        !            27: find_tree(struct f_tree *t, struct f_val val)
        !            28: {
        !            29:   if (!t)
        !            30:     return NULL;
        !            31:   if ((val_compare(t->from, val) != 1) &&
        !            32:       (val_compare(t->to, val) != -1))
        !            33:     return t;
        !            34:   if (val_compare(t->from, val) == -1)
        !            35:     return find_tree(t->right, val);
        !            36:   else
        !            37:     return find_tree(t->left, val);
        !            38: }
        !            39: 
        !            40: static struct f_tree *
        !            41: build_tree_rec(struct f_tree **buf, int l, int h)
        !            42: {
        !            43:   struct f_tree *n;
        !            44:   int pos;
        !            45: 
        !            46:   if (l >= h)
        !            47:     return NULL;
        !            48: 
        !            49:   pos = (l+h)/2;
        !            50:   n = buf[pos];
        !            51:   n->left = build_tree_rec(buf, l, pos);
        !            52:   n->right = build_tree_rec(buf, pos+1, h);
        !            53:   return n;
        !            54: }
        !            55: 
        !            56: static int 
        !            57: tree_compare(const void *p1, const void *p2)
        !            58: {
        !            59:   return val_compare((* (struct f_tree **) p1)->from, (* (struct f_tree **) p2)->from);
        !            60: }
        !            61: 
        !            62: /**
        !            63:  * build_tree
        !            64:  * @from: degenerated tree (linked by @tree->left) to be transformed into form suitable for find_tree()
        !            65:  *
        !            66:  * Transforms degenerated tree into balanced tree.
        !            67:  */
        !            68: struct f_tree *
        !            69: build_tree(struct f_tree *from)
        !            70: {
        !            71:   struct f_tree *tmp, *root;
        !            72:   struct f_tree **buf;
        !            73:   int len, i;
        !            74: 
        !            75:   if (from == NULL)
        !            76:     return NULL;
        !            77: 
        !            78:   len = 0;
        !            79:   for (tmp = from; tmp != NULL; tmp = tmp->left)
        !            80:     len++;
        !            81: 
        !            82:   if (len <= 1024)
        !            83:     buf = alloca(len * sizeof(struct f_tree *));
        !            84:   else
        !            85:     buf = xmalloc(len * sizeof(struct f_tree *));
        !            86: 
        !            87:   /* Convert a degenerated tree into an sorted array */
        !            88:   i = 0;
        !            89:   for (tmp = from; tmp != NULL; tmp = tmp->left)
        !            90:     buf[i++] = tmp;
        !            91: 
        !            92:   qsort(buf, len, sizeof(struct f_tree *), tree_compare);
        !            93: 
        !            94:   root = build_tree_rec(buf, 0, len);
        !            95: 
        !            96:   if (len > 1024)
        !            97:     xfree(buf);
        !            98: 
        !            99:   return root;
        !           100: }
        !           101: 
        !           102: struct f_tree *
        !           103: f_new_tree(void)
        !           104: {
        !           105:   struct f_tree * ret;
        !           106:   ret = cfg_alloc(sizeof(struct f_tree));
        !           107:   ret->left = ret->right = NULL;
        !           108:   ret->from.type = ret->to.type = T_VOID;
        !           109:   ret->from.val.i = ret->to.val.i = 0;
        !           110:   ret->data = NULL;
        !           111:   return ret;
        !           112: }
        !           113: 
        !           114: /**
        !           115:  * same_tree
        !           116:  * @t1: first tree to be compared
        !           117:  * @t2: second one
        !           118:  *
        !           119:  * Compares two trees and returns 1 if they are same
        !           120:  */
        !           121: int
        !           122: same_tree(struct f_tree *t1, struct f_tree *t2)
        !           123: {
        !           124:   if ((!!t1) != (!!t2))
        !           125:     return 0;
        !           126:   if (!t1)
        !           127:     return 1;
        !           128:   if (val_compare(t1->from, t2->from))
        !           129:     return 0;
        !           130:   if (val_compare(t1->to, t2->to))
        !           131:     return 0;
        !           132:   if (!same_tree(t1->left, t2->left))
        !           133:     return 0;
        !           134:   if (!same_tree(t1->right, t2->right))
        !           135:     return 0;
        !           136:   if (!i_same(t1->data, t2->data))
        !           137:     return 0;
        !           138:   return 1;
        !           139: }
        !           140: 
        !           141: 
        !           142: static void
        !           143: tree_node_format(struct f_tree *t, buffer *buf)
        !           144: {
        !           145:   if (t == NULL)
        !           146:     return;
        !           147: 
        !           148:   tree_node_format(t->left, buf);
        !           149: 
        !           150:   val_format(t->from, buf);
        !           151:   if (val_compare(t->from, t->to) != 0)
        !           152:   {
        !           153:     buffer_puts(buf, "..");
        !           154:     val_format(t->to, buf);
        !           155:   }
        !           156:   buffer_puts(buf, ", ");
        !           157: 
        !           158:   tree_node_format(t->right, buf);
        !           159: }
        !           160: 
        !           161: void
        !           162: tree_format(struct f_tree *t, buffer *buf)
        !           163: {
        !           164:   buffer_puts(buf, "[");
        !           165: 
        !           166:   tree_node_format(t, buf);
        !           167: 
        !           168:   if (buf->pos == buf->end)
        !           169:     return;
        !           170: 
        !           171:   /* Undo last separator */
        !           172:   if (buf->pos[-1] != '[')
        !           173:     buf->pos -= 2;
        !           174: 
        !           175:   buffer_puts(buf, "]");
        !           176: }

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