1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
|
#include "system.h"
#include <rpm/rpmstring.h>
#include <rpm/rpmstrpool.h>
#include "debug.h"
#define HASHTYPE strHash
#define HTKEYTYPE const char *
#define HTDATATYPE rpmsid
#include "lib/rpmhash.H"
#include "lib/rpmhash.C"
#undef HASHTYPE
#undef HTKEYTYPE
#undef HTDATATYPE
#define STRDATA_CHUNK 65536
#define STROFFS_CHUNK 2048
/* XXX this is ridiculously small... */
#define STRHASH_INITSIZE 5
struct rpmstrPool_s {
size_t * offs; /* offsets into data area */
rpmsid offs_size; /* largest offset index */;
rpmsid offs_alloced; /* offsets allocation size */
char * data; /* string data area */
size_t data_size; /* string data area size */
size_t data_alloced; /* string data area allocation size */
strHash hash; /* string -> sid hash table */
int nrefs; /* refcount */
};
rpmstrPool rpmstrPoolCreate(void)
{
rpmstrPool pool = xcalloc(1, sizeof(*pool));
pool->hash = strHashCreate(STRHASH_INITSIZE, rstrhash, strcmp, NULL, NULL);
pool->nrefs = 1;
return pool;
}
rpmstrPool rpmstrPoolFree(rpmstrPool pool)
{
if (pool) {
if (pool->nrefs > 1) {
pool->nrefs--;
} else {
strHashFree(pool->hash);
free(pool->offs);
free(pool->data);
free(pool);
}
}
return NULL;
}
rpmstrPool rpmstrPoolLink(rpmstrPool pool)
{
if (pool)
pool->nrefs++;
return pool;
}
void rpmstrPoolFreeze(rpmstrPool pool)
{
if (pool) {
pool->hash = strHashFree(pool->hash);
pool->data_alloced = pool->data_size;
pool->data = xrealloc(pool->data, pool->data_alloced);
pool->offs_alloced = pool->offs_size + 1;
pool->offs = xrealloc(pool->offs,
pool->offs_alloced * sizeof(*pool->offs));
}
}
void rpmstrPoolUnfreeze(rpmstrPool pool)
{
if (pool && pool->hash == NULL) {
int sizehint = (pool->offs_size / 2) - 1;
if (sizehint < STRHASH_INITSIZE)
sizehint = STRHASH_INITSIZE;
pool->hash = strHashCreate(sizehint, rstrhash, strcmp, NULL, NULL);
for (int i = 1; i < pool->offs_size; i++) {
strHashAddEntry(pool->hash, rpmstrPoolStr(pool, i), i);
}
}
}
static rpmsid rpmstrPoolPut(rpmstrPool pool, const char *s, size_t slen, unsigned int hash)
{
const char *t = NULL;
size_t ssize = slen + 1;
if (ssize > pool->data_alloced - pool->data_size) {
size_t need = pool->data_size + ssize;
size_t alloced = pool->data_alloced;
while (alloced < need)
alloced += STRDATA_CHUNK;
pool->data = xrealloc(pool->data, alloced);
pool->data_alloced = alloced;
/* ouch, need to rehash the whole lot as key addresses change */
if (pool->offs_size > 0) {
pool->hash = strHashFree(pool->hash);
rpmstrPoolUnfreeze(pool);
}
}
pool->offs_size += 1;
if (pool->offs_alloced <= pool->offs_size) {
pool->offs_alloced += STROFFS_CHUNK;
pool->offs = xrealloc(pool->offs,
pool->offs_alloced * sizeof(*pool->offs));
}
t = memcpy(pool->data + pool->data_size, s, ssize);
pool->offs[pool->offs_size] = pool->data_size;
pool->data_size += ssize;
strHashAddHEntry(pool->hash, t, hash, pool->offs_size);
return pool->offs_size;
}
rpmsid rpmstrPoolIdn(rpmstrPool pool, const char *s, size_t slen, int create)
{
rpmsid sid = 0;
if (pool && s) {
unsigned int hash = strHashKeyHash(pool->hash, s);
rpmsid *sids;
if (strHashGetHEntry(pool->hash, s, hash, &sids, NULL, NULL)) {
sid = sids[0];
} else if (create && pool->hash) {
sid = rpmstrPoolPut(pool, s, slen, hash);
}
}
return sid;
}
rpmsid rpmstrPoolId(rpmstrPool pool, const char *s, int create)
{
return rpmstrPoolIdn(pool, s, strlen(s), create);
}
const char * rpmstrPoolStr(rpmstrPool pool, rpmsid sid)
{
const char *s = NULL;
if (pool && sid <= pool->offs_size)
s = pool->data + pool->offs[sid];
return s;
}
size_t rpmstrPoolStrlen(rpmstrPool pool, rpmsid sid)
{
size_t slen = 0;
if (pool && sid <= pool->offs_size) {
size_t end = (sid < pool->offs_size) ? pool->offs[sid + 1] :
pool->offs_size;
slen = end - pool->offs[sid] - 1;
}
return slen;
}
|