- move dep2str buffer into pool so that the memory gets released
[platform/upstream/libsolv.git] / src / poolid.c
1 /*
2  * poolid.c
3  *
4  * Id management
5  */
6
7 #include <stdlib.h>
8 #include <string.h>
9 #include <stdio.h>
10
11 #include "pool.h"
12 #include "poolid.h"
13 #include "poolid_private.h"
14 #include "util.h"
15
16
17 // intern string into pool
18 // return Id
19
20 Id
21 str2id(Pool *pool, const char *str, int create)
22 {
23   Hashval h;
24   unsigned int hh;
25   Hashmask hashmask;
26   int i, space_needed;
27   Id id;
28   Hashtable hashtbl;
29
30   // check string
31   if (!str)
32     return ID_NULL;
33   if (!*str)
34     return ID_EMPTY;
35
36   hashmask = pool->stringhashmask;
37   hashtbl = pool->stringhashtbl;
38
39   // expand hashtable if needed
40   // 
41   // 
42   if (pool->nstrings * 2 > hashmask)
43     {
44       xfree(hashtbl);
45
46       // realloc hash table
47       pool->stringhashmask = hashmask = mkmask(pool->nstrings + STRING_BLOCK);
48       pool->stringhashtbl = hashtbl = (Hashtable)xcalloc(hashmask + 1, sizeof(Id));
49
50       // rehash all strings into new hashtable
51       for (i = 1; i < pool->nstrings; i++)
52         {
53           h = strhash(pool->stringspace + pool->strings[i]) & hashmask;
54           hh = HASHCHAIN_START;
55           while (hashtbl[h] != ID_NULL)  // follow overflow chain
56             h = HASHCHAIN_NEXT(h, hh, hashmask);
57           hashtbl[h] = i;
58         }
59     }
60
61   // compute hash and check for match
62
63   h = strhash(str) & hashmask;
64   hh = HASHCHAIN_START;
65   while ((id = hashtbl[h]) != ID_NULL)  // follow hash overflow chain
66     {
67       // break if string already hashed
68       if(!strcmp(pool->stringspace + pool->strings[id], str))
69         break;
70       h = HASHCHAIN_NEXT(h, hh, hashmask);
71     }
72   if (id || !create)    // exit here if string found
73     return id;
74
75   pool_freewhatprovides(pool);
76
77   // generate next id and save in table
78   id = pool->nstrings++;
79   hashtbl[h] = id;
80
81   // 
82   if ((id & STRING_BLOCK) == 0)
83     pool->strings = xrealloc(pool->strings, ((pool->nstrings + STRING_BLOCK) & ~STRING_BLOCK) * sizeof(Hashval));
84   // 'pointer' into stringspace is Offset of next free pos: sstrings
85   pool->strings[id] = pool->sstrings;
86
87   space_needed = strlen(str) + 1;
88
89   // resize string buffer if needed
90   if (((pool->sstrings + space_needed - 1) | STRINGSPACE_BLOCK) != ((pool->sstrings - 1) | STRINGSPACE_BLOCK))
91     pool->stringspace = xrealloc(pool->stringspace, (pool->sstrings + space_needed + STRINGSPACE_BLOCK) & ~STRINGSPACE_BLOCK);
92   // copy new string into buffer
93   memcpy(pool->stringspace + pool->sstrings, str, space_needed);
94   // next free pos is behind new string
95   pool->sstrings += space_needed;
96
97   return id;
98 }
99
100
101 Id
102 rel2id(Pool *pool, Id name, Id evr, int flags, int create)
103 {
104   Hashval h;
105   unsigned int hh;
106   Hashmask hashmask;
107   int i;
108   Id id;
109   Hashtable hashtbl;
110   Reldep *ran;
111
112   hashmask = pool->relhashmask;
113   hashtbl = pool->relhashtbl;
114   ran = pool->rels;
115   
116   // extend hashtable if needed
117   if (pool->nrels * 2 > hashmask)
118     {
119       xfree(pool->relhashtbl);
120       pool->relhashmask = hashmask = mkmask(pool->nstrings + REL_BLOCK);
121       pool->relhashtbl = hashtbl = xcalloc(hashmask + 1, sizeof(Id));
122       // rehash all rels into new hashtable
123       for (i = 1; i < pool->nrels; i++)
124         {
125           h = relhash(ran[i].name, ran[i].evr, ran[i].flags) & hashmask;
126           hh = HASHCHAIN_START;
127           while (hashtbl[h])
128             h = HASHCHAIN_NEXT(h, hh, hashmask);
129           hashtbl[h] = i;
130         }
131     }
132   
133   // compute hash and check for match
134
135   h = relhash(name, evr, flags) & hashmask;
136   hh = HASHCHAIN_START;
137   while ((id = hashtbl[h]) != 0)
138     {
139       if (ran[id].name == name && ran[id].evr == evr && ran[id].flags == flags)
140         break;
141       h = HASHCHAIN_NEXT(h, hh, hashmask);
142     }
143   if (id)
144     return MAKERELDEP(id);
145
146   if (!create)
147     return ID_NULL;
148
149   pool_freewhatprovides(pool);
150
151   id = pool->nrels++;
152   // extend rel space if needed
153   if ((id & REL_BLOCK) == 0)
154     pool->rels = xrealloc(pool->rels, ((pool->nrels + REL_BLOCK) & ~REL_BLOCK) * sizeof(Reldep));
155   hashtbl[h] = id;
156   ran = pool->rels + id;
157   ran->name = name;
158   ran->evr = evr;
159   ran->flags = flags;
160   return MAKERELDEP(id);
161 }
162
163
164 // Id -> String
165 // for rels (returns name only) and strings
166 // 
167 const char *
168 id2str(Pool *pool, Id id)
169 {
170   if (ISRELDEP(id))
171     {
172       Reldep *rd = GETRELDEP(pool, id);
173       if (ISRELDEP(rd->name))
174         return "REL";
175       return pool->stringspace + pool->strings[rd->name];
176     }
177   return pool->stringspace + pool->strings[id];
178 }
179
180 static const char *rels[] = {
181   " ! ",
182   " > ",
183   " = ",
184   " >= ",
185   " < ",
186   " <> ",
187   " <= ",
188   " <=> "
189 };
190
191
192 // get operator for RelId
193 const char *
194 id2rel(Pool *pool, Id id)
195 {
196   Reldep *rd;
197   if (!ISRELDEP(id))
198     return "";
199   rd = GETRELDEP(pool, id);
200   switch (rd->flags)
201     {
202     case 0: case 1: case 2: case 3:
203     case 4: case 5: case 6: case 7:
204       return rels[rd->flags & 7];
205     case REL_AND:
206       return " AND ";
207     case REL_OR:
208       return " OR ";
209     case REL_WITH:
210       return " WITH ";
211     case REL_NAMESPACE:
212       return " NAMESPACE ";
213     default:
214       break;
215     }
216   return " ??? ";
217 }
218
219
220 // get e:v.r for Id
221 // 
222 const char *
223 id2evr(Pool *pool, Id id)
224 {
225   Reldep *rd;
226   if (!ISRELDEP(id))
227     return "";
228   rd = GETRELDEP(pool, id);
229   if (ISRELDEP(rd->evr))
230     return "REL";
231   return pool->stringspace + pool->strings[rd->evr];
232 }
233
234 #define DEP2STRBUF 16
235
236 const char *
237 dep2str(Pool *pool, Id id)
238 {
239   Reldep *rd;
240   const char *sr;
241   char *s1, *s2;
242   int n, l, ls1, ls2, lsr;
243
244   if (!ISRELDEP(id))
245     return pool->stringspace + pool->strings[id];
246   rd = GETRELDEP(pool, id);
247   n = pool->dep2strn;
248
249   sr = id2rel(pool, id);
250   lsr = strlen(sr);
251
252   s2 = (char *)dep2str(pool, rd->evr);
253   pool->dep2strn = n;
254   ls2 = strlen(s2);
255
256   s1 = (char *)dep2str(pool, rd->name);
257   pool->dep2strn = n;
258   ls1 = strlen(s1);
259
260   if (rd->flags == REL_NAMESPACE)
261     {
262       sr = "(";
263       lsr = 1;
264       ls2++;
265     }
266
267   l = ls1 + ls2 + lsr;
268   if (l + 1 > pool->dep2strlen[n])
269     {
270       if (s1 != pool->dep2strbuf[n])
271         pool->dep2strbuf[n] = xrealloc(pool->dep2strbuf[n], l + 32);
272       else
273         {
274           pool->dep2strbuf[n] = xrealloc(pool->dep2strbuf[n], l + 32);
275           s1 = pool->dep2strbuf[n];
276         }
277       pool->dep2strlen[n] = l + 32;
278     }
279   if (s1 != pool->dep2strbuf[n])
280     {
281       strcpy(pool->dep2strbuf[n], s1);
282       s1 = pool->dep2strbuf[n];
283     }
284   strcpy(s1 + ls1, sr);
285   pool->dep2strbuf[n] = s1 + ls1 + lsr;
286   s2 = (char *)dep2str(pool, rd->evr);
287   if (s2 != pool->dep2strbuf[n])
288     strcpy(pool->dep2strbuf[n], s2);
289   pool->dep2strbuf[n] = s1;
290   if (rd->flags == REL_NAMESPACE)
291     {
292       s1[ls1 + ls2 + lsr - 1] = ')';
293       s1[ls1 + ls2 + lsr] = 0;
294     }
295   pool->dep2strn = (n + 1) % DEP2STRBUF;
296   return s1;
297 }
298
299
300 void
301 pool_shrink_strings(Pool *pool)
302 {
303   pool->stringspace = (char *)xrealloc(pool->stringspace, (pool->sstrings + STRINGSPACE_BLOCK) & ~STRINGSPACE_BLOCK);
304   pool->strings = (Offset *)xrealloc(pool->strings, ((pool->nstrings + STRING_BLOCK) & ~STRING_BLOCK) * sizeof(Offset));
305 }
306
307 void
308 pool_shrink_rels(Pool *pool)
309 {
310   pool->rels = (Reldep *)xrealloc(pool->rels, ((pool->nrels + REL_BLOCK) & ~REL_BLOCK) * sizeof(Reldep));
311 }
312
313 // reset all hash tables
314 // 
315 void
316 pool_freeidhashes(Pool *pool)
317 {
318   pool->stringhashtbl = xfree(pool->stringhashtbl);
319   pool->relhashtbl = xfree(pool->relhashtbl);
320   pool->stringhashmask = 0;
321   pool->relhashmask = 0;
322 }
323
324 // EOF