Reduce C&P code by factoring out the uniquifying string pool.
[platform/upstream/libsolv.git] / src / strpool.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 #include <string.h>
9 #include "util.h"
10 #include "strpool.h"
11
12 #define STRING_BLOCK      2047
13 #define STRINGSPACE_BLOCK 65535
14
15 void
16 stringpool_init (Stringpool *ss, const char *strs[])
17 {
18   unsigned totalsize = 0;
19   unsigned count;
20   // count number and total size of predefined strings
21   for (count = 0; strs[count]; count++)
22     totalsize += strlen(strs[count]) + 1;
23
24   // alloc appropriate space
25   ss->stringspace = (char *)xmalloc((totalsize + STRINGSPACE_BLOCK) & ~STRINGSPACE_BLOCK);
26   ss->strings = (Offset *)xmalloc(((count + STRING_BLOCK) & ~STRING_BLOCK) * sizeof(Offset));
27
28   // now copy predefined strings into allocated space
29   ss->sstrings = 0;
30   for (count = 0; strs[count]; count++)
31     {
32       strcpy(ss->stringspace + ss->sstrings, strs[count]);
33       ss->strings[count] = ss->sstrings;
34       ss->sstrings += strlen(strs[count]) + 1;
35     }
36   ss->nstrings = count;
37 }
38
39 Id
40 stringpool_str2id (Stringpool *ss, const char *str, int create)
41 {
42   Hashval h;
43   unsigned int hh;
44   Hashmask hashmask;
45   int i, space_needed;
46   Id id;
47   Hashtable hashtbl;
48
49   // check string
50   if (!str)
51     return STRID_NULL;
52   if (!*str)
53     return STRID_EMPTY;
54
55   hashmask = ss->stringhashmask;
56   hashtbl = ss->stringhashtbl;
57
58   // expand hashtable if needed
59   // 
60   // 
61   if (ss->nstrings * 2 > hashmask)
62     {
63       xfree(hashtbl);
64
65       // realloc hash table
66       ss->stringhashmask = hashmask = mkmask(ss->nstrings + STRING_BLOCK);
67       ss->stringhashtbl = hashtbl = (Hashtable)xcalloc(hashmask + 1, sizeof(Id));
68
69       // rehash all strings into new hashtable
70       for (i = 1; i < ss->nstrings; i++)
71         {
72           h = strhash(ss->stringspace + ss->strings[i]) & hashmask;
73           hh = HASHCHAIN_START;
74           while (hashtbl[h] != 0)  // follow overflow chain
75             h = HASHCHAIN_NEXT(h, hh, hashmask);
76           hashtbl[h] = i;
77         }
78     }
79
80   // compute hash and check for match
81
82   h = strhash(str) & hashmask;
83   hh = HASHCHAIN_START;
84   while ((id = hashtbl[h]) != 0)  // follow hash overflow chain
85     {
86       // break if string already hashed
87       if(!strcmp(ss->stringspace + ss->strings[id], str))
88         break;
89       h = HASHCHAIN_NEXT(h, hh, hashmask);
90     }
91   if (id || !create)    // exit here if string found
92     return id;
93
94   // generate next id and save in table
95   id = ss->nstrings++;
96   hashtbl[h] = id;
97
98   // 
99   if ((id & STRING_BLOCK) == 0)
100     ss->strings = xrealloc(ss->strings, ((ss->nstrings + STRING_BLOCK) & ~STRING_BLOCK) * sizeof(Hashval));
101   // 'pointer' into stringspace is Offset of next free pos: sstrings
102   ss->strings[id] = ss->sstrings;
103
104   space_needed = strlen(str) + 1;
105
106   // resize string buffer if needed
107   if (((ss->sstrings + space_needed - 1) | STRINGSPACE_BLOCK) != ((ss->sstrings - 1) | STRINGSPACE_BLOCK))
108     ss->stringspace = xrealloc(ss->stringspace, (ss->sstrings + space_needed + STRINGSPACE_BLOCK) & ~STRINGSPACE_BLOCK);
109   // copy new string into buffer
110   memcpy(ss->stringspace + ss->sstrings, str, space_needed);
111   // next free pos is behind new string
112   ss->sstrings += space_needed;
113
114   return id;
115 }
116
117 void
118 stringpool_shrink (Stringpool *ss)
119 {
120   ss->stringspace = (char *)xrealloc(ss->stringspace, (ss->sstrings + STRINGSPACE_BLOCK) & ~STRINGSPACE_BLOCK);
121   ss->strings = (Offset *)xrealloc(ss->strings, ((ss->nstrings + STRING_BLOCK) & ~STRING_BLOCK) * sizeof(Offset));
122 }