Actual source code: ctable.c

  2: /* Contributed by - Mark Adams */

  4: #include <petscsys.h>
  5: #include <../src/sys/ctable.h> 
  6: #if defined (PETSC_HAVE_LIMITS_H)
  7: #include <limits.h>
  8: #endif
  9: #define HASH_FACT 79943
 10: #define HASHT(ta,x) ((unsigned long)((HASH_FACT*(unsigned long)x)%ta->tablesize))

 14: /* PetscTableCreate() ********************************************
 15:  * 
 16:  * hash table for non-zero data and keys 
 17:  *
 18:  */
 19: PetscErrorCode  PetscTableCreate(const PetscInt n,PetscTable *rta)
 20: {
 21:   PetscTable     ta;

 25:   if (n < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"n < 0");
 26:   PetscNew(struct _n_PetscTable,&ta);
 27:   ta->tablesize = (3*n)/2 + 17;
 28:   if (ta->tablesize < n) ta->tablesize = INT_MAX/4; /* overflow */
 29:   PetscMalloc(sizeof(PetscInt)*ta->tablesize,&ta->keytable);
 30:   PetscMemzero(ta->keytable,sizeof(PetscInt)*ta->tablesize);
 31:   PetscMalloc(sizeof(PetscInt)*ta->tablesize,&ta->table);
 32:   ta->head      = 0;
 33:   ta->count     = 0;
 34:   *rta          = ta;
 35:   return(0);
 36: }

 40: /* PetscTableCreate() ********************************************
 41:  * 
 42:  * hash table for non-zero data and keys 
 43:  *
 44:  */
 45: PetscErrorCode  PetscTableCreateCopy(const PetscTable intable,PetscTable *rta)
 46: {
 48:   PetscInt       i;
 49:   PetscTable     ta;

 52:   PetscNew(struct _n_PetscTable,&ta);
 53:   ta->tablesize = intable->tablesize;
 54:   PetscMalloc(sizeof(PetscInt)*ta->tablesize,&ta->keytable);
 55:   PetscMalloc(sizeof(PetscInt)*ta->tablesize,&ta->table);
 56:   for(i = 0; i < ta->tablesize ; i++){
 57:     ta->keytable[i] = intable->keytable[i];
 58:     ta->table[i]    = intable->table[i];
 59: #if defined(PETSC_USE_DEBUG)    
 60:     if (ta->keytable[i] < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_COR,"ta->keytable[i] < 0");
 61: #endif  
 62:  }
 63:   ta->head  = 0;
 64:   ta->count = intable->count;
 65:   *rta      = ta;
 66:   return(0);
 67: }

 71: /* PetscTableDestroy() ********************************************
 72:  * 
 73:  *
 74:  */
 75: PetscErrorCode  PetscTableDestroy(PetscTable *ta)
 76: {

 80:   if (!*ta) return(0);
 81:   PetscFree((*ta)->keytable);
 82:   PetscFree((*ta)->table);
 83:   PetscFree(*ta);
 84:   return(0);
 85: }
 88: /* PetscTableGetCount() ********************************************
 89:  */
 90: PetscErrorCode  PetscTableGetCount(const PetscTable ta,PetscInt *count)
 91: {
 93:   *count = ta->count;
 94:   return(0);
 95: }

 99: /* PetscTableIsEmpty() ********************************************
100:  */
101: PetscErrorCode  PetscTableIsEmpty(const PetscTable ta,PetscInt *flag)
102: {
104:   *flag = !(ta->count);
105:   return(0);
106: }

110: /* PetscTableAdd() ********************************************
111:  *
112:  */
113: PetscErrorCode  PetscTableAdd(PetscTable ta,const PetscInt key,const PetscInt data)
114: {
116:   PetscInt       ii = 0,hash = HASHT(ta,key);
117:   const PetscInt tsize = ta->tablesize,tcount = ta->count;
118: 
120:   if (key <= 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"key <= 0");
121:   if (!data) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Null data");
122: 
123:   if (ta->count < 5*(ta->tablesize/6) - 1) {
124:     while (ii++ < ta->tablesize){
125:       if (ta->keytable[hash] == key) {
126:         ta->table[hash] = data; /* over write */
127:         return(0);
128:       } else if (!ta->keytable[hash]) {
129:         ta->count++; /* add */
130:         ta->keytable[hash] = key; ta->table[hash] = data;
131:         return(0);
132:       }
133:       hash = (hash == (ta->tablesize-1)) ? 0 : hash+1;
134:     }
135:     SETERRQ(PETSC_COMM_SELF,PETSC_ERR_COR,"Full table");
136:   } else {
137:     PetscInt *oldtab = ta->table,*oldkt = ta->keytable,newk,ndata;

139:     /* alloc new (bigger) table */
140:     if (ta->tablesize == INT_MAX/4) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_COR,"ta->tablesize < 0");
141:     ta->tablesize = 2*tsize;
142:     if (ta->tablesize <= tsize) ta->tablesize = INT_MAX/4;

144:     PetscMalloc(ta->tablesize*sizeof(PetscInt),&ta->table);
145:     PetscMalloc(ta->tablesize*sizeof(PetscInt),&ta->keytable);
146:     PetscMemzero(ta->keytable,ta->tablesize*sizeof(PetscInt));

148:     ta->count     = 0;
149:     ta->head      = 0;
150: 
151:     PetscTableAdd(ta,key,data);
152:     /* rehash */
153:     for (ii = 0; ii < tsize; ii++) {
154:       newk = oldkt[ii];
155:       if (newk) {
156:         ndata = oldtab[ii];
157:         PetscTableAdd(ta,newk,ndata);
158:       }
159:     }
160:     if (ta->count != tcount + 1) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_COR,"corrupted ta->count");
161: 
162:     PetscFree(oldtab);
163:     PetscFree(oldkt);
164:   }
165:   return(0);
166: }

170: /* PetscTableRemoveAll() ********************************************
171:  *
172:  *
173:  */
174: PetscErrorCode  PetscTableRemoveAll(PetscTable ta)
175: {

179:   ta->head = 0;
180:   if (ta->count) {
181:     ta->count = 0;
182:     PetscMemzero(ta->keytable,ta->tablesize*sizeof(PetscInt));
183:   }
184:   return(0);
185: }

189: /* PetscTableFind() ********************************************
190:  *
191:  * returns data. If data==0, then no table entry exists.
192:  *
193:  */
194: PetscErrorCode  PetscTableFind(PetscTable ta,const PetscInt key,PetscInt *data)
195: {
196:   PetscInt hash,ii = 0;

199:   if (!key) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Null key");
200:   hash  = HASHT(ta,key);
201:   *data = 0;
202:   while (ii++ < ta->tablesize) {
203:     if (!ta->keytable[hash]) break;
204:     else if (ta->keytable[hash] == key) {
205:       *data = ta->table[hash];
206:       break;
207:     }
208:     hash = (hash == (ta->tablesize-1)) ? 0 : hash+1;
209:   }
210:   return(0);
211: }

215: /* PetscTableGetHeadPosition() ********************************************
216:  *
217:  */
218: PetscErrorCode  PetscTableGetHeadPosition(PetscTable ta,PetscTablePosition *ppos)
219: {
220:   PetscInt i = 0;

223:   *ppos = NULL;
224:   if (!ta->count) return(0);
225: 
226:   /* find first valid place */
227:   do {
228:     if (ta->keytable[i]) {
229:       *ppos = (PetscTablePosition)&ta->table[i];
230:       break;
231:     }
232:   } while (i++ < ta->tablesize);
233:   if (!*ppos) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_COR,"No head");
234:   return(0);
235: }

239: /* PetscTableGetNext() ********************************************
240:  *
241:  *  - iteration - PetscTablePosition is always valid (points to a data)
242:  *  
243:  */
244: PetscErrorCode  PetscTableGetNext(PetscTable ta,PetscTablePosition *rPosition,PetscInt *pkey,PetscInt *data)
245: {
246:   PetscInt           idex;
247:   PetscTablePosition pos;

250:   pos = *rPosition;
251:   if (!pos) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Null position");
252:   *data = *pos;
253:   if (!*data) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Null data");
254:   idex = pos - ta->table;
255:   *pkey = ta->keytable[idex];
256:   if (!*pkey) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Null key");

258:   /* get next */
259:   do {
260:     pos++;  idex++;
261:     if (idex >= ta->tablesize) {
262:       pos = 0; /* end of list */
263:       break;
264:     } else if (ta->keytable[idex]) {
265:       pos = ta->table + idex;
266:       break;
267:     }
268:   } while (idex < ta->tablesize);
269:   *rPosition = pos;
270:   return(0);
271: }


276: /* 
277:      PetscTableAddCount - adds another key to the hash table and gives it the data of the current size of the table,
278:           if the entry already exists then just return
279:  *
280:  */
281: PetscErrorCode  PetscTableAddCount(PetscTable ta,const PetscInt key)
282: {
284:   PetscInt       ii = 0,hash = HASHT(ta,key);
285:   const PetscInt tsize = ta->tablesize,tcount = ta->count;
286: 
288:   if (key <= 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"key <= 0");
289: 
290:   if (ta->count < 5*(ta->tablesize/6) - 1) {
291:     while (ii++ < ta->tablesize){
292:       if (ta->keytable[hash] == key) {
293:         return(0);
294:       } else if (!ta->keytable[hash]) {
295:         ta->count++; /* add */
296:         ta->keytable[hash] = key; ta->table[hash] = ta->count;
297:         return(0);
298:       }
299:       hash = (hash == (ta->tablesize-1)) ? 0 : hash+1;
300:     }
301:     SETERRQ(PETSC_COMM_SELF,PETSC_ERR_COR,"Full table");
302:   } else {
303:     PetscInt *oldtab = ta->table,*oldkt = ta->keytable,newk,ndata;

305:     /* before making the table larger check if key is already in table */
306:     while (ii++ < ta->tablesize){
307:       if (ta->keytable[hash] == key) return(0);
308:       hash = (hash == (ta->tablesize-1)) ? 0 : hash+1;
309:     }

311:     /* alloc new (bigger) table */
312:     if (ta->tablesize == INT_MAX/4) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_COR,"ta->tablesize < 0");
313:     ta->tablesize = 2*tsize;
314:     if (ta->tablesize <= tsize) ta->tablesize = INT_MAX/4;

316:     PetscMalloc(ta->tablesize*sizeof(PetscInt),&ta->table);
317:     PetscMalloc(ta->tablesize*sizeof(PetscInt),&ta->keytable);
318:     PetscMemzero(ta->keytable,ta->tablesize*sizeof(PetscInt));

320:     ta->count     = 0;
321:     ta->head      = 0;
322: 
323:     /* Build a new copy of the data */
324:     for (ii = 0; ii < tsize; ii++) {
325:       newk = oldkt[ii];
326:       if (newk) {
327:         ndata = oldtab[ii];
328:         PetscTableAdd(ta,newk,ndata);
329:       }
330:     }
331:     PetscTableAddCount(ta,key);
332:     if (ta->count != tcount + 1) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_COR,"corrupted ta->count");
333: 
334:     PetscFree(oldtab);
335:     PetscFree(oldkt);
336:   }
337:   return(0);
338: }