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: }