Reduce C&P code by factoring out the uniquifying string pool.
[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   int old_nstrings = pool->ss.nstrings;
31   Id id = stringpool_str2id (&pool->ss, str, create);
32   /* If we changed the ID->string relations we need to get rid of an
33      eventually existing provides lookup cache.  */
34   if (old_nstrings != pool->ss.nstrings)
35     pool_freewhatprovides(pool);
36   return id;
37 }
38
39 Id
40 rel2id(Pool *pool, Id name, Id evr, int flags, int create)
41 {
42   Hashval h;
43   unsigned int hh;
44   Hashmask hashmask;
45   int i;
46   Id id;
47   Hashtable hashtbl;
48   Reldep *ran;
49
50   hashmask = pool->relhashmask;
51   hashtbl = pool->relhashtbl;
52   ran = pool->rels;
53   
54   // extend hashtable if needed
55   if (pool->nrels * 2 > hashmask)
56     {
57       xfree(pool->relhashtbl);
58       pool->relhashmask = hashmask = mkmask(pool->ss.nstrings + REL_BLOCK);
59       pool->relhashtbl = hashtbl = xcalloc(hashmask + 1, sizeof(Id));
60       // rehash all rels into new hashtable
61       for (i = 1; i < pool->nrels; i++)
62         {
63           h = relhash(ran[i].name, ran[i].evr, ran[i].flags) & hashmask;
64           hh = HASHCHAIN_START;
65           while (hashtbl[h])
66             h = HASHCHAIN_NEXT(h, hh, hashmask);
67           hashtbl[h] = i;
68         }
69     }
70   
71   // compute hash and check for match
72
73   h = relhash(name, evr, flags) & hashmask;
74   hh = HASHCHAIN_START;
75   while ((id = hashtbl[h]) != 0)
76     {
77       if (ran[id].name == name && ran[id].evr == evr && ran[id].flags == flags)
78         break;
79       h = HASHCHAIN_NEXT(h, hh, hashmask);
80     }
81   if (id)
82     return MAKERELDEP(id);
83
84   if (!create)
85     return ID_NULL;
86
87   pool_freewhatprovides(pool);
88
89   id = pool->nrels++;
90   // extend rel space if needed
91   if ((id & REL_BLOCK) == 0)
92     pool->rels = xrealloc(pool->rels, ((pool->nrels + REL_BLOCK) & ~REL_BLOCK) * sizeof(Reldep));
93   hashtbl[h] = id;
94   ran = pool->rels + id;
95   ran->name = name;
96   ran->evr = evr;
97   ran->flags = flags;
98   return MAKERELDEP(id);
99 }
100
101
102 // Id -> String
103 // for rels (returns name only) and strings
104 // 
105 const char *
106 id2str(Pool *pool, Id id)
107 {
108   if (ISRELDEP(id))
109     {
110       Reldep *rd = GETRELDEP(pool, id);
111       if (ISRELDEP(rd->name))
112         return "REL";
113       return pool->ss.stringspace + pool->ss.strings[rd->name];
114     }
115   return pool->ss.stringspace + pool->ss.strings[id];
116 }
117
118 static const char *rels[] = {
119   " ! ",
120   " > ",
121   " = ",
122   " >= ",
123   " < ",
124   " <> ",
125   " <= ",
126   " <=> "
127 };
128
129
130 // get operator for RelId
131 const char *
132 id2rel(Pool *pool, Id id)
133 {
134   Reldep *rd;
135   if (!ISRELDEP(id))
136     return "";
137   rd = GETRELDEP(pool, id);
138   switch (rd->flags)
139     {
140     case 0: case 1: case 2: case 3:
141     case 4: case 5: case 6: case 7:
142       return rels[rd->flags & 7];
143     case REL_AND:
144       return " AND ";
145     case REL_OR:
146       return " OR ";
147     case REL_WITH:
148       return " WITH ";
149     case REL_NAMESPACE:
150       return " NAMESPACE ";
151     default:
152       break;
153     }
154   return " ??? ";
155 }
156
157
158 // get e:v.r for Id
159 // 
160 const char *
161 id2evr(Pool *pool, Id id)
162 {
163   Reldep *rd;
164   if (!ISRELDEP(id))
165     return "";
166   rd = GETRELDEP(pool, id);
167   if (ISRELDEP(rd->evr))
168     return "REL";
169   return pool->ss.stringspace + pool->ss.strings[rd->evr];
170 }
171
172 const char *
173 dep2str(Pool *pool, Id id)
174 {
175   Reldep *rd;
176   const char *sr;
177   char *s1, *s2;
178   int n, l, ls1, ls2, lsr;
179
180   if (!ISRELDEP(id))
181     return pool->ss.stringspace + pool->ss.strings[id];
182   rd = GETRELDEP(pool, id);
183   n = pool->dep2strn;
184
185   sr = id2rel(pool, id);
186   lsr = strlen(sr);
187
188   s2 = (char *)dep2str(pool, rd->evr);
189   pool->dep2strn = n;
190   ls2 = strlen(s2);
191
192   s1 = (char *)dep2str(pool, rd->name);
193   pool->dep2strn = n;
194   ls1 = strlen(s1);
195
196   if (rd->flags == REL_NAMESPACE)
197     {
198       sr = "(";
199       lsr = 1;
200       ls2++;
201     }
202
203   l = ls1 + ls2 + lsr;
204   if (l + 1 > pool->dep2strlen[n])
205     {
206       if (s1 != pool->dep2strbuf[n])
207         pool->dep2strbuf[n] = xrealloc(pool->dep2strbuf[n], l + 32);
208       else
209         {
210           pool->dep2strbuf[n] = xrealloc(pool->dep2strbuf[n], l + 32);
211           s1 = pool->dep2strbuf[n];
212         }
213       pool->dep2strlen[n] = l + 32;
214     }
215   if (s1 != pool->dep2strbuf[n])
216     {
217       strcpy(pool->dep2strbuf[n], s1);
218       s1 = pool->dep2strbuf[n];
219     }
220   strcpy(s1 + ls1, sr);
221   pool->dep2strbuf[n] = s1 + ls1 + lsr;
222   s2 = (char *)dep2str(pool, rd->evr);
223   if (s2 != pool->dep2strbuf[n])
224     strcpy(pool->dep2strbuf[n], s2);
225   pool->dep2strbuf[n] = s1;
226   if (rd->flags == REL_NAMESPACE)
227     {
228       s1[ls1 + ls2 + lsr - 1] = ')';
229       s1[ls1 + ls2 + lsr] = 0;
230     }
231   pool->dep2strn = (n + 1) % DEP2STRBUF;
232   return s1;
233 }
234
235
236 void
237 pool_shrink_strings(Pool *pool)
238 {
239   stringpool_shrink (&pool->ss);
240 }
241
242 void
243 pool_shrink_rels(Pool *pool)
244 {
245   pool->rels = (Reldep *)xrealloc(pool->rels, ((pool->nrels + REL_BLOCK) & ~REL_BLOCK) * sizeof(Reldep));
246 }
247
248 // reset all hash tables
249 // 
250 void
251 pool_freeidhashes(Pool *pool)
252 {
253   pool->ss.stringhashtbl = xfree(pool->ss.stringhashtbl);
254   pool->ss.stringhashmask = 0;
255   pool->relhashtbl = xfree(pool->relhashtbl);
256   pool->relhashmask = 0;
257 }
258
259 // EOF