ptbl.c

Go to the documentation of this file.
00001 /*                          P T B L . C
00002  * BRL-CAD
00003  *
00004  * Copyright (c) 2004-2006 United States Government as represented by
00005  * the U.S. Army Research Laboratory.
00006  *
00007  * This library is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public License
00009  * as published by the Free Software Foundation; either version 2 of
00010  * the License, or (at your option) any later version.
00011  *
00012  * This library is distributed in the hope that it will be useful, but
00013  * WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Library General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with this file; see the file named COPYING for more
00019  * information.
00020  */
00021 
00022 /** \addtogroup ptbl */
00023 /*@{*/
00024 
00025 /** @file ptbl.c
00026  *
00027  * @brief Support for generalized "pointer tables"
00028  *
00029  *  Support for generalized "pointer tables",
00030  *  kept compactly in a dynamic array.
00031  *
00032  *  The table is currently un-ordered, and is merely a array of pointers.
00033  *  The support routine nmg_tbl manipulates the array for you.
00034  *  Pointers to be operated on (inserted, deleted,
00035  *  searched for) are passed as a "pointer to long".
00036  *
00037  *
00038  *  @authors    Lee A. Butler
00039  *  @authors    Michael John Muuss
00040  *
00041  * @par  Source -
00042  *      The U. S. Army Research Laboratory
00043  *@n    Aberdeen Proving Ground, Maryland  21005-5068  USA
00044  *
00045  */
00046 
00047 
00048 #ifndef lint
00049 static const char libbu_ptbl_RCSid[] = "@(#)$Header: /cvsroot/brlcad/brlcad/src/libbu/ptbl.c,v 14.12 2006/09/03 15:14:07 lbutler Exp $ (ARL)";
00050 #endif
00051 
00052 #include "common.h"
00053 
00054 #include <stdio.h>
00055 #ifdef HAVE_STRING_H
00056 #  include <string.h>
00057 #else
00058 #  include <strings.h>
00059 #endif
00060 
00061 #include "machine.h"
00062 #include "bu.h"
00063 
00064 
00065 /**
00066  *                      B U _ P T B L _ I N I T
00067  *
00068  *  Initialize struct & get storage for table.
00069  *  Recommend 8 or 64 for initial len.
00070  */
00071 void
00072 bu_ptbl_init(struct bu_ptbl *b, int len, const char *str)
00073 {
00074         if (bu_debug & BU_DEBUG_PTBL)
00075                 bu_log("bu_ptbl_init(%8x, len=%d, %s)\n", b, len, str);
00076         BU_LIST_INIT(&b->l);
00077         b->l.magic = BU_PTBL_MAGIC;
00078         if( len <= 0 )  len = 64;
00079         b->blen = len;
00080         b->buffer = (long **)bu_calloc(b->blen, sizeof(long *), str);
00081         b->end = 0;
00082 }
00083 
00084 
00085 /**
00086  *                      B U _ P T B L _ R E S E T
00087  *
00088  *  Reset the table to have no elements, but retain any existing storage.
00089  */
00090 void
00091 bu_ptbl_reset(struct bu_ptbl *b)
00092 {
00093         BU_CK_PTBL(b);
00094         if (bu_debug & BU_DEBUG_PTBL)
00095                 bu_log("bu_ptbl_reset(%8x)\n", b);
00096         b->end = 0;
00097         memset( (char *)b->buffer, 0, b->blen*sizeof(long *) ); /* no peeking */
00098 }
00099 
00100 
00101 /**
00102  *                      B U _ P T B L _ I N S
00103  *
00104  *  Append/Insert a (long *) item to/into the table.
00105  */
00106 int
00107 bu_ptbl_ins(struct bu_ptbl *b, long int *p)
00108 {
00109         register int i;
00110 
00111         BU_CK_PTBL(b);
00112 
00113         if (bu_debug & BU_DEBUG_PTBL)
00114                 bu_log("bu_ptbl_ins(%8x, %8x)\n", b, p);
00115 
00116         if (b->blen == 0) bu_ptbl_init(b, 64, "bu_ptbl_ins() buffer");
00117         if (b->end >= b->blen)  {
00118                 b->buffer = (long **)bu_realloc( (char *)b->buffer,
00119                     sizeof(p)*(b->blen *= 4),
00120                     "bu_ptbl.buffer[] (ins)" );
00121         }
00122 
00123         i=b->end++;
00124         b->buffer[i] = p;
00125         return(i);
00126 }
00127 
00128 
00129 /**
00130  *                      B U _ P T B L _ L O C A T E
00131  *
00132  *  locate a (long *) in an existing table
00133  *
00134  *  
00135  * @return      index of first matching element in array, if found
00136  * @return      -1      if not found
00137  *
00138  * We do this a great deal, so make it go as fast as possible.
00139  * this is the biggest argument I can make for changing to an
00140  * ordered list.  Someday....
00141  */
00142 int
00143 bu_ptbl_locate(const struct bu_ptbl *b, const long int *p)
00144 {
00145         register int            k;
00146         register const long     **pp;
00147 
00148         BU_CK_PTBL(b);
00149         pp = (const long **)b->buffer;
00150 #       include "noalias.h"
00151         for( k = b->end-1; k >= 0; k-- )
00152                 if (pp[k] == p) return(k);
00153 
00154         return(-1);
00155 }
00156 
00157 
00158 /**
00159  *                      B U _ P T B L _ Z E R O
00160  *
00161  *  Set all occurrences of "p" in the table to zero.
00162  *  This is different than deleting them.
00163  */
00164 void
00165 bu_ptbl_zero(struct bu_ptbl *b, const long int *p)
00166 {
00167         register int            k;
00168         register const long     **pp;
00169 
00170         BU_CK_PTBL(b);
00171         pp = (const long **)b->buffer;
00172 #       include "noalias.h"
00173         for( k = b->end-1; k >= 0; k-- )
00174                 if (pp[k] == p) pp[k] = (long *)0;
00175 }
00176 
00177 
00178 /**
00179  *                      B U _ P T B L _ I N S _ U N I Q U E
00180  *
00181  *  Append item to table, if not already present.  Unique insert.
00182  *
00183  *
00184  *  @return     index of first matchine element in array, if found.  (table unchanged)
00185  *  @return     -1      if table extended to hold new element
00186  *
00187  * We do this a great deal, so make it go as fast as possible.
00188  * this is the biggest argument I can make for changing to an
00189  * ordered list.  Someday....
00190  */
00191 int
00192 bu_ptbl_ins_unique(struct bu_ptbl *b, long int *p)
00193 {
00194         register int    k;
00195         register long   **pp = b->buffer;
00196 
00197         BU_CK_PTBL(b);
00198 
00199 #       include "noalias.h"
00200 
00201         /* search for existing */
00202         for( k = b->end-1; k >= 0; k-- )
00203                 if (pp[k] == p) return(k);
00204 
00205         if (bu_debug & BU_DEBUG_PTBL)
00206                 bu_log("bu_ptbl_ins_unique(%8x, %8x)\n", b, p);
00207 
00208         if (b->blen <= 0 || b->end >= b->blen)  {
00209                 /* Table needs to grow */
00210                 bu_ptbl_ins( b, p );
00211                 return -1;      /* To signal that it was added */
00212         }
00213 
00214         b->buffer[k=b->end++] = p;
00215         return(-1);             /* To signal that it was added */
00216 }
00217 
00218 
00219 /**
00220  *                      B U _ P T B L _ R M
00221  *
00222  *  Remove all occurrences of an item from a table
00223  *
00224  *
00225  *  @return     Number of copies of 'p' that were removed from the table.
00226  *  @return     0 if none found.
00227  *
00228  * we go backwards down the table looking for occurrences
00229  * of p to delete.  We do it backwards to reduce the amount
00230  * of data moved when there is more than one occurrence of p
00231  * in the table.  A pittance savings, unless you're doing a
00232  * lot of it.
00233  */
00234 int
00235 bu_ptbl_rm(struct bu_ptbl *b, const long int *p)
00236 {
00237         register int end = b->end, j, k, l;
00238         register long **pp = b->buffer;
00239         int     ndel = 0;
00240 
00241         BU_CK_PTBL(b);
00242         for (l = b->end-1 ; l >= 0 ; --l)  {
00243                 if (pp[l] == p){
00244                         /* delete consecutive occurrence(s) of p */
00245                         ndel++;
00246 
00247                         j=l+1;
00248                         while (l >= 1 && pp[l-1] == p) --l, ndel++;
00249                         /* pp[l] through pp[j-1] match p */
00250 
00251                         end -= j - l;
00252 #                       include "noalias.h"
00253                         for(k=l ; j < b->end ;)
00254                                 b->buffer[k++] = b->buffer[j++];
00255                         b->end = end;
00256                 }
00257         }
00258         if (bu_debug & BU_DEBUG_PTBL)
00259                 bu_log("bu_ptbl_rm(%8x, %8x) ndel=%d\n", b, p, ndel);
00260         return ndel;
00261 }
00262 
00263 
00264 /**
00265  *                      B U _ P T B L _ C A T
00266  *
00267  *  Catenate one table onto end of another.
00268  *  There is no checking for duplication.
00269  */
00270 void
00271 bu_ptbl_cat(struct bu_ptbl *dest, const struct bu_ptbl *src)
00272 {
00273         BU_CK_PTBL(dest);
00274         BU_CK_PTBL(src);
00275         if (bu_debug & BU_DEBUG_PTBL)
00276                 bu_log("bu_ptbl_cat(%8x, %8x)\n", dest, src);
00277 
00278         if ((dest->blen - dest->end) < src->end) {
00279                 dest->blen = (dest->blen + src->end) * 2 + 8;
00280                 dest->buffer = (long **)bu_realloc( (char *)dest->buffer,
00281                         dest->blen * sizeof(long *),
00282                         "bu_ptbl.buffer[] (cat)");
00283         }
00284         bcopy( (char *)src->buffer, (char *)&dest->buffer[dest->end],
00285                 src->end*sizeof(long *));
00286         dest->end += src->end;
00287 }
00288 
00289 
00290 /**
00291  *                      B U _ P T B L _ C A T _ U N I Q
00292  *
00293  *  Catenate one table onto end of another,
00294  *  ensuring that no entry is duplicated.
00295  *  Duplications between multiple items in 'src' are not caught.
00296  *  The search is a nasty n**2 one.  The tables are expected to be short.
00297  */
00298 void
00299 bu_ptbl_cat_uniq(struct bu_ptbl *dest, const struct bu_ptbl *src)
00300 {
00301         register long   **p;
00302 
00303         BU_CK_PTBL(dest);
00304         BU_CK_PTBL(src);
00305         if (bu_debug & BU_DEBUG_PTBL)
00306                 bu_log("bu_ptbl_cat_uniq(%8x, %8x)\n", dest, src);
00307 
00308         /* Assume the worst, ensure sufficient space to add all 'src' items */
00309         if ((dest->blen - dest->end) < src->end) {
00310                 dest->buffer = (long **)bu_realloc( (char *)dest->buffer,
00311                         sizeof(long *)*(dest->blen += src->blen + 8),
00312                         "bu_ptbl.buffer[] (cat_uniq)");
00313         }
00314         for( BU_PTBL_FOR( p, (long **), src ) )  {
00315                 bu_ptbl_ins_unique( dest, *p );
00316         }
00317 }
00318 
00319 
00320 /**
00321  *                      B U _ P T B L _ F R E E
00322  *
00323  *  Deallocate dynamic buffer associated with a table,
00324  *  and render this table unusable without a subsequent bu_ptbl_init().
00325  */
00326 void
00327 bu_ptbl_free(struct bu_ptbl *b)
00328 {
00329         BU_CK_PTBL(b);
00330 
00331         bu_free((genptr_t)b->buffer, "bu_ptbl.buffer[]");
00332         memset((char *)b, 0, sizeof(struct bu_ptbl));   /* sanity */
00333 
00334         if (bu_debug & BU_DEBUG_PTBL)
00335                 bu_log("bu_ptbl_free(%8x)\n", b);
00336 }
00337 
00338 
00339 /**
00340  *                      B U _ P T B L
00341  *
00342  *  This version maintained for source compatibility with existing NMG code.
00343  */
00344 int
00345 bu_ptbl(struct bu_ptbl *b, int func, long int *p)
00346 {
00347         if (func == BU_PTBL_INIT) {
00348                 bu_ptbl_init(b, 64, "bu_ptbl() buffer[]");
00349                 return 0;
00350         } else if (func == BU_PTBL_RST) {
00351                 bu_ptbl_reset(b);
00352                 return 0;
00353         } else if (func == BU_PTBL_INS) {
00354                 return bu_ptbl_ins(b, p);
00355         } else if (func == BU_PTBL_LOC) {
00356                 return bu_ptbl_locate(b, p);
00357         } else if( func == BU_PTBL_ZERO ) {
00358                 bu_ptbl_zero(b, p);
00359                 return( 0 );
00360         } else if (func == BU_PTBL_INS_UNIQUE) {
00361                 return bu_ptbl_ins_unique(b, p);
00362         } else if (func == BU_PTBL_RM) {
00363                 return bu_ptbl_rm(b, p);
00364         } else if (func == BU_PTBL_CAT) {
00365                 bu_ptbl_cat( b, (const struct bu_ptbl *)p );
00366                 return(0);
00367         } else if (func == BU_PTBL_FREE) {
00368                 bu_ptbl_free(b);
00369                 return (0);
00370         } else {
00371                 BU_CK_PTBL(b);
00372                 bu_log("bu_ptbl(%8x) Unknown table function %d\n", b, func);
00373                 bu_bomb("bu_ptbl");
00374         }
00375         return(-1);/* this is here to keep lint happy */
00376 }
00377 
00378 
00379 /**
00380  *                      B U _ P R _ P T B L
00381  *
00382  *  Print a bu_ptbl array for inspection.
00383  */
00384 void
00385 bu_pr_ptbl(const char *title, const struct bu_ptbl *tbl, int verbose)
00386 {
00387         register long   **lp;
00388 
00389         BU_CK_PTBL(tbl);
00390         bu_log("%s: bu_ptbl array with %d entries\n",
00391                 title, tbl->end );
00392 
00393         if( !verbose )  return;
00394 
00395         /* Go in ascending order */
00396         for( lp = (long **)BU_PTBL_BASEADDR(tbl);
00397              lp <= (long **)BU_PTBL_LASTADDR(tbl); lp++
00398         )  {
00399                 if( *lp == 0 )  {
00400                         bu_log("  %.8x NULL entry\n", *lp);
00401                         continue;
00402                 }
00403                 bu_log("  %.8x %s\n", *lp, bu_identify_magic(**lp) );
00404         }
00405 }
00406 
00407 
00408 /**
00409  *                      B U _ P T B L _ T R U N C
00410  *
00411  *      truncate a bu_ptbl
00412  */
00413 void
00414 bu_ptbl_trunc(struct bu_ptbl *tbl, int end)
00415 {
00416         BU_CK_PTBL(tbl);
00417 
00418         if( tbl->end <= end )
00419                 return;
00420 
00421         tbl->end = end;
00422         return;
00423 }
00424 /*@}*/
00425 /*
00426  * Local Variables:
00427  * mode: C
00428  * tab-width: 8
00429  * c-basic-offset: 4
00430  * indent-tabs-mode: t
00431  * End:
00432  * ex: shiftwidth=4 tabstop=8
00433  */

Generated on Mon Sep 18 01:24:48 2006 for BRL-CAD by  doxygen 1.4.6