home *** CD-ROM | disk | FTP | other *** search
- /* index - index handler for large pseudo-arrays
- * Written by Jim McBeath (jimmc) at SCI
- *
- * Revision history:
- * 24-Jan-85 Jim McBeath Add enumIndex function
- * 8-Mar-85 Jim McBeath remove unused var numentries from enumIndex
- * 17-Apr-86 Jim McBeath Add field nzcount
- * 19.Jan.87 J. McBeath Add freeIndex
- * 13.Feb.87 J. McBeath Set nzcount to 0 on init
- * 8.Jan.99 jimmc Lint cleanup
- */
-
- /* This module implements a very large pseudo-array. There are four
- entry points: to initialize a pseudo-array, to insert an item,
- to read an item, and to enumerate the entries in an array. The
- array contains integers (which could of course be used for another
- purpose, such as pointers to something else).
-
- Structure of a table:
- A table is a recursive structure which contains 2 words of size
- information and n words of pointers. The first word of size
- information tells how many entries are represented by this and
- all lower tables; the second word of size information tells how
- many entries are actually in this table. If the two numbers are
- the same, then the table is an end node which actually has the
- data entries in it.
- */
-
- /*..........*/
-
- #include "index.h"
-
- extern char *malloc(), *calloc();
-
- int indexDebug=0; /* a debugging flag */
-
- /*..........*/
-
- struct toplevel * /* pointer to the structure for future calls */
- initIndex() /* init a new index table */
- {
- struct toplevel *tt;
- struct tblblock *dd;
-
- tt = (struct toplevel *)calloc((unsigned)sizeof(struct toplevel),1);
- /* get space for top level block */
- if (!tt) return 0;
- dd = (struct tblblock *)calloc((unsigned)sizeof(struct tblblock),1);
- /* get space for top level table */
- if (!dd) {
- free((char *)tt);
- return 0;
- }
- tt->data = dd; /* save pointer in our block */
- tt->numlevs = 1; /* we always start with one level */
- tt->nzcount = 0;
- dd->repnum = TBLSIZ;
- dd->count = TBLSIZ;
- return tt; /* return pointer to top level block */
- }
-
- /*..........*/
-
- freeIndex(tt)
- struct toplevel *tt;
- {
- freeBlock(tt->data);
- free((char *)tt);
- }
-
- static freeBlock(dd)
- struct tblblock *dd;
- {
- int i;
- if (dd->repnum > dd->count) { /* not at lowest level */
- for (i=0; i<dd->count; i++)
- if (dd->tdata[i].p)
- freeBlock(dd->tdata[i].p);
- /* free lower level tables */
- }
- free((char *)dd);
- }
-
- /*..........*/
-
- setIndex(tt,ix,num) /* put index value into table */
- struct toplevel *tt; /* table to use */
- int ix; /* the index where it goes */
- long num; /* the value to put there */
- {
- struct tblblock *dd, *dd0;
-
- if (indexDebug) {
- printf("setIndex: index=%d, value=%d\n", ix, num);
- if (!tt) printf("setIndex: no table index\n");
- else if (!(tt->numlevs)) printf("setIndex: no numlevs\n");
- else if (!(tt->data)) printf("setIndex: no data array\n");
- }
- if (!tt) return -1; /* check for errors */
- if (!(tt->numlevs)) return -1;
- if (!(tt->data)) return -1;
- dd = tt->data; /* get data pointer */
- while (ix >= dd->repnum) { /* create a higher level */
- if (indexDebug)
- printf("setIndex: %d(ix) > %d(repnum)\n",
- ix, dd->repnum);
- dd0 = (struct tblblock *)calloc(
- (unsigned)sizeof(struct tblblock),1);
- /* get space for a higher level */
- if (!dd0) return -1; /* error */
- dd0->repnum = dd->repnum*TBLSIZ;
- dd0->count = TBLSIZ;
- dd0->tdata[0].p = dd;
- /* put in pointer to next level down */
- tt->data = dd0; /* put in new top-level pointer */
- tt->numlevs++;
- if (indexDebug)
- printf("setIndex: numlevs=%d\n", tt->numlevs);
- dd = dd0;
- }
- while (dd->repnum > dd->count) {
- /* scan down to the last level */
- if (indexDebug) printf("setIndex: %d(repnum) > %d(count)\n",
- dd->repnum, dd->count);
- dd0 = dd->tdata[ix/dd->count].p;
- /* get pointer to next table lower */
- if (!dd0) {
- /* if no table there, have to make one */
- dd0 = (struct tblblock *)calloc(
- (unsigned)sizeof(struct tblblock),1);
- if (!dd0) return -1; /* error */
- dd0->repnum = dd->repnum/dd->count;
- dd0->count = TBLSIZ;
- dd->tdata[ix/dd->count].p = dd0;
- /* save pointer to it */
- }
- ix %= dd->count; /* lower the index */
- dd = dd0;
- }
- if (dd->tdata[ix].n) tt->nzcount--;
- dd->tdata[ix].n = num; /* put it in */
- if (num) tt->nzcount++;
- if (indexDebug)
- printf("setIndex: table %X, index %d, value %d\n", dd,ix,num);
- return ix;
- }
-
- /*..........*/
-
- long /* return value out of table */
- /* returns 0 if no entry */
- getIndex(tt,ix)
- struct toplevel *tt;
- int ix; /* the index to look for */
- {
- struct tblblock *dd, *dd0;
-
- if (indexDebug) {
- printf("getIndex: index=%d\n", ix);
- if (!tt) printf("getIndex: no table\n");
- else if (!tt->data) printf("getIndex: no data array\n");
- else if (!tt->numlevs) printf("genIndex: no numlevs\n");
- }
- if (!tt) return 0; /* check for errors */
- if (!tt->data) return 0;
- if (!tt->numlevs) return 0;
- dd = tt->data;
- if (ix >= dd->repnum) {
- if (indexDebug)
- printf("getIndex: index %d > repnum %d\n",
- ix,dd->repnum);
- return 0; /* we don't have them that high */
- }
- while (dd->repnum > dd->count) { /* scan down to bottom level */
- if (indexDebug) printf("getIndex: %d(repnum) > %d(count)\n",
- dd->repnum, dd->count);
- dd0 = dd->tdata[ix/dd->count].p;
- /* get pointer to next level */
- if (!dd0) {
- if (indexDebug) printf("getIndex: no table\n");
- return 0; /* nothing there */
- }
- ix %= dd->count;
- dd = dd0;
- }
- if (indexDebug)
- printf("getIndex: table %X, index %d, value %d\n",
- dd, ix, dd->tdata[ix].n);
- return dd->tdata[ix].n; /* this is the data entry */
- }
-
- /*..........*/
-
- /* the enumerate function scans throught the table and calls (*f)(x,d) for
- * each non-zero entry n in the table. If f returns <>0, the enum routine
- * stops scanning and returns an error. (x is the index number, d is its
- * value.)
- */
- int /* returns number of entries or <0 on error */
- enumIndex(tt,f) /* enumerate the table */
- struct toplevel *tt; /* the table to enumerate */
- int (*f)(); /* the function to call for each item */
- {
-
- if (indexDebug) {
- if (!tt) printf("enumIndex: no table index\n");
- else if (!(tt->numlevs)) printf("enumIndex: no numlevs\n");
- else if (!(tt->data)) printf("enumIndex: no data array\n");
- }
- if (!tt) return -1; /* check for errors */
- if (!(tt->numlevs)) return -1;
- if (!(tt->data)) return -1;
- return enum1(tt->data,tt->numlevs,0,f);
- /* do the enumeration recursively */
- }
-
- static int
- enum1(dd,levs,b,f)
- struct tblblock *dd; /* the datablock to enumerate */
- int levs; /* the number of levels left to descend */
- int b; /* the base number for this segment */
- int (*f)(); /* the function to call */
- {
- int count=0;
- int i, n;
- int binc;
-
- if (levs<=1) {
- for (i=0; i<TBLSIZ; i++) { /* scan through the table */
- if (dd->tdata[i].n) {
- n = (*f)(b+i,dd->tdata[i].n);
- if (n!=0) return -1; /* error */
- count++;
- }
- }
- return count;
- /* return the number of entries processed */
- }
- else { /* not yet at the bottom, keep descending */
- binc = dd->repnum/TBLSIZ;
- for (i=0; i<TBLSIZ; i++, b+=binc) {
- if (dd->tdata[i].p) {
- n = enum1(dd->tdata[i].p,levs-1,b,f);
- if (n<0) return n;
- count += n;
- }
- }
- }
- return count;
- }
-
- /* end */
-