2 This file is part of the software library CADLIB written by Conrad Ziesler
3 Copyright 2003, Conrad Ziesler, all rights reserved.
5 *************************
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 /* names.c, efficient string table support
30 #define __NAMES_PRIVATE__
33 static namehash_t
*names_newhash(names_t
*nt
, int refp
, const char *str
)
37 b
=malloc(sizeof(namehash_t
)+q
);
42 nt
->bytesalloc
+=sizeof(namehash_t
)+q
;
50 static unsigned int names_ptrhash(names_t
*nt
, int refp
)
52 unsigned q
=nt
->qtybins
;
58 r= ((v%(7*q+(q/3)+5))^v) % q;
60 r
= v
^ (v
>>3) ^ ((v
/3)>>15) ^ ((~v
)>>11);
64 static unsigned int names_strhash(names_t
*nt
, const char *str
)
66 unsigned q
=nt
->qtybins
;
80 char *names_lookup(names_t
*nt
, int refp
)
86 id
=names_ptrhash(nt
,refp
);
88 for(nh
=nt
->cref
[id
];nh
!=NULL
;nh
=nh
->cref
,i
++)
90 assert(nh
->magic
==NAME_MAGIC
);
91 if(refp
==nh
->refp
){ return nh
->str
; }
97 int names_check(names_t
*nt
, const char *name
)
103 id
=names_strhash(nt
,name
);
105 for(nh
=nt
->cstr
[id
];nh
!=NULL
;nh
=nh
->cstr
,i
++)
107 assert(nh
->magic
==NAME_MAGIC
);
108 if(strcmp(name
,nh
->str
)==0){ return nh
->refp
; }
115 void names_add(names_t
*nt
, int refp
, const char *name
)
117 unsigned int idn
,idr
,id
;
118 namehash_t
*nh
,*nhref
=NULL
,*nhstr
=NULL
;
121 if(nt
->qtynames
>((5*nt
->qtybins
)/4)) /* double table size each time we outgrow old table */
122 names_rehash(nt
, (2*nt
->qtynames
) );
124 idn
=names_strhash(nt
,name
);
125 idr
=names_ptrhash(nt
,refp
);
127 for(nh
=nt
->cref
[idr
];nh
!=NULL
;nh
=nh
->cref
,i
++)
129 assert(nh
->magic
==NAME_MAGIC
);
130 if(refp
==nh
->refp
){ nt
->avg_refl
=(nt
->avg_refl
+i
)/2; nhref
=nh
; break; }
133 for(nh
=nt
->cstr
[idn
];nh
!=NULL
;nh
=nh
->cstr
,i
++)
135 assert(nh
->magic
==NAME_MAGIC
);
136 if(strcmp(name
,nh
->str
)==0){ nt
->avg_strl
=(nt
->avg_strl
+i
)/2; nhstr
=nh
; break; }
139 if(nhstr
==NULL
) /* adding new name entry */
141 if(nhref
!=NULL
) /* but refp was the same */
143 fprintf(stderr
,"**** DUPLICATE KEY NAME ****\n");
144 if(1)assert(0&&"duplicate key in names");
147 nh
=names_newhash(nt
, refp
, name
);
148 nh
->cstr
=nt
->cstr
[idn
];
150 nh
->cref
=nt
->cref
[idr
];
153 else /* replacing old name entry */
155 namehash_t
*prev
=NULL
;
156 assert(0 && "Replacing strings in names has a bug. do not use");
157 /* lookup refp of old name and unlink */
158 id
=names_ptrhash(nt
,nhstr
->refp
);
159 for(nh
=nt
->cref
[id
];nh
!=NULL
;prev
=nh
,nh
=nh
->cref
,i
++)
160 if(nhstr
->refp
==nh
->refp
)
162 if(prev
==NULL
)nt
->cref
[id
]=nh
->cref
;
163 else prev
->cref
=nh
->cref
;
166 /* relink new name, refp */
168 nhstr
->cref
=nt
->cref
[idr
];
173 char * names_stats(names_t
*nt
)
175 static char buf
[1024];
176 int i
,qs
=0,qp
=0,ms
=0,mp
=0,j
,ks
=0,kp
=0;
179 for(i
=0;i
<nt
->qtybins
;i
++)
182 for(j
=0,nh
=nt
->cstr
[i
];nh
!=NULL
;nh
=nh
->cstr
,j
++) assert(nh
->magic
==NAME_MAGIC
);
186 for(j
=0,nh
=nt
->cref
[i
];nh
!=NULL
;nh
=nh
->cref
,j
++) assert(nh
->magic
==NAME_MAGIC
);
195 sprintf(buf
,"names: %i bins (%i totaling %i) , alloc %i, avg: %i %i max: %i %i",nt
->qtybins
,nt
->qtynames
,nt
->namebytes
,nt
->bytesalloc
,qp
,qs
,mp
,ms
);
202 /* this should optimize our hash table for memory usage */
203 void names_rehash(names_t
*nt
, int newbins
)
212 nt
->bytesalloc
+= ( (newbins
-oldqty
)*sizeof(void *)*2 );
213 /* do cref first, using cstr */
216 nt
->cref
=malloc(sizeof(void *)*(nt
->qtybins
+1));
217 assert(nt
->cref
!=NULL
);
218 memset(nt
->cref
,0,sizeof(void*)*nt
->qtybins
);
220 /* iterate through list of string hashes, adding to ref hashes */
221 for(i
=0;i
<oldqty
;i
++)
222 for(hp
=nt
->cstr
[i
];hp
!=NULL
;hp
=hp
->cstr
)
225 id
=names_ptrhash(nt
,hp
->refp
);
226 hp
->cref
=nt
->cref
[id
];
230 /* next do cstr, using new cref */
233 nt
->cstr
=malloc(sizeof(void *)*(nt
->qtybins
+1));
234 assert(nt
->cstr
!=NULL
);
235 memset(nt
->cstr
,0,sizeof(void*)*nt
->qtybins
);
237 for(i
=0;i
<nt
->qtybins
;i
++)
238 for(hp
=nt
->cref
[i
];hp
!=NULL
;hp
=hp
->cref
)
241 id
=names_strhash(nt
,hp
->str
);
242 hp
->cstr
=nt
->cstr
[id
];
249 names_t
*names_new(void)
252 p
=malloc(sizeof(names_t
));
254 memset(p
,0,sizeof(names_t
));
255 p
->bytesalloc
=sizeof(names_t
);
264 names_rehash(p
,13); /* start small, grow bigger */
268 void names_free(names_t
*nt
)
271 namehash_t
*nh
,*next
;
274 for(i
=0;i
<nt
->qtybins
;i
++)
276 for(nh
=nt
->cstr
[i
];nh
!=NULL
;nh
=next
)
278 assert(nh
->magic
==NAME_MAGIC
);