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