|
Packit Service |
ff689b |
/*
|
|
Packit Service |
ff689b |
* Copyright (c) 2007, Novell Inc.
|
|
Packit Service |
ff689b |
*
|
|
Packit Service |
ff689b |
* This program is licensed under the BSD license, read LICENSE.BSD
|
|
Packit Service |
ff689b |
* for further information
|
|
Packit Service |
ff689b |
*/
|
|
Packit Service |
ff689b |
|
|
Packit Service |
ff689b |
#include <string.h>
|
|
Packit Service |
ff689b |
#include "util.h"
|
|
Packit Service |
ff689b |
#include "strpool.h"
|
|
Packit Service |
ff689b |
|
|
Packit Service |
ff689b |
#define STRING_BLOCK 2047
|
|
Packit Service |
ff689b |
#define STRINGSPACE_BLOCK 65535
|
|
Packit Service |
ff689b |
|
|
Packit Service |
ff689b |
void
|
|
Packit Service |
ff689b |
stringpool_init(Stringpool *ss, const char *strs[])
|
|
Packit Service |
ff689b |
{
|
|
Packit Service |
ff689b |
unsigned totalsize = 0;
|
|
Packit Service |
ff689b |
unsigned count;
|
|
Packit Service |
ff689b |
|
|
Packit Service |
ff689b |
memset(ss, 0, sizeof(*ss));
|
|
Packit Service |
ff689b |
/* count number and total size of predefined strings */
|
|
Packit Service |
ff689b |
for (count = 0; strs[count]; count++)
|
|
Packit Service |
ff689b |
totalsize += strlen(strs[count]) + 1;
|
|
Packit Service |
ff689b |
|
|
Packit Service |
ff689b |
/* alloc appropriate space */
|
|
Packit Service |
ff689b |
ss->stringspace = solv_extend_resize(0, totalsize, 1, STRINGSPACE_BLOCK);
|
|
Packit Service |
ff689b |
ss->strings = solv_extend_resize(0, count, sizeof(Offset), STRING_BLOCK);
|
|
Packit Service |
ff689b |
|
|
Packit Service |
ff689b |
/* now copy predefined strings into allocated space */
|
|
Packit Service |
ff689b |
ss->sstrings = 0;
|
|
Packit Service |
ff689b |
for (count = 0; strs[count]; count++)
|
|
Packit Service |
ff689b |
{
|
|
Packit Service |
ff689b |
strcpy(ss->stringspace + ss->sstrings, strs[count]);
|
|
Packit Service |
ff689b |
ss->strings[count] = ss->sstrings;
|
|
Packit Service |
ff689b |
ss->sstrings += strlen(strs[count]) + 1;
|
|
Packit Service |
ff689b |
}
|
|
Packit Service |
ff689b |
ss->nstrings = count;
|
|
Packit Service |
ff689b |
}
|
|
Packit Service |
ff689b |
|
|
Packit Service |
ff689b |
void
|
|
Packit Service |
ff689b |
stringpool_free(Stringpool *ss)
|
|
Packit Service |
ff689b |
{
|
|
Packit Service |
ff689b |
solv_free(ss->strings);
|
|
Packit Service |
ff689b |
solv_free(ss->stringspace);
|
|
Packit Service |
ff689b |
solv_free(ss->stringhashtbl);
|
|
Packit Service |
ff689b |
}
|
|
Packit Service |
ff689b |
|
|
Packit Service |
ff689b |
void
|
|
Packit Service |
ff689b |
stringpool_freehash(Stringpool *ss)
|
|
Packit Service |
ff689b |
{
|
|
Packit Service |
ff689b |
ss->stringhashtbl = solv_free(ss->stringhashtbl);
|
|
Packit Service |
ff689b |
ss->stringhashmask = 0;
|
|
Packit Service |
ff689b |
}
|
|
Packit Service |
ff689b |
|
|
Packit Service |
ff689b |
void
|
|
Packit Service |
ff689b |
stringpool_init_empty(Stringpool *ss)
|
|
Packit Service |
ff689b |
{
|
|
Packit Service |
ff689b |
static const char *emptystrs[] = { "<NULL>", "", 0 };
|
|
Packit Service |
ff689b |
stringpool_init(ss, emptystrs);
|
|
Packit Service |
ff689b |
}
|
|
Packit Service |
ff689b |
|
|
Packit Service |
ff689b |
void
|
|
Packit Service |
ff689b |
stringpool_clone(Stringpool *ss, Stringpool *from)
|
|
Packit Service |
ff689b |
{
|
|
Packit Service |
ff689b |
memset(ss, 0, sizeof(*ss));
|
|
Packit Service |
ff689b |
ss->strings = solv_extend_resize(0, from->nstrings, sizeof(Offset), STRING_BLOCK);
|
|
Packit Service |
ff689b |
memcpy(ss->strings, from->strings, from->nstrings * sizeof(Offset));
|
|
Packit Service |
ff689b |
ss->stringspace = solv_extend_resize(0, from->sstrings, 1, STRINGSPACE_BLOCK);
|
|
Packit Service |
ff689b |
memcpy(ss->stringspace, from->stringspace, from->sstrings);
|
|
Packit Service |
ff689b |
ss->nstrings = from->nstrings;
|
|
Packit Service |
ff689b |
ss->sstrings = from->sstrings;
|
|
Packit Service |
ff689b |
}
|
|
Packit Service |
ff689b |
|
|
Packit Service |
ff689b |
void
|
|
Packit Service |
ff689b |
stringpool_resize_hash(Stringpool *ss, int numnew)
|
|
Packit Service |
ff689b |
{
|
|
Packit Service |
ff689b |
Hashval h, hh, hashmask;
|
|
Packit Service |
ff689b |
Hashtable hashtbl;
|
|
Packit Service |
ff689b |
int i;
|
|
Packit Service |
ff689b |
|
|
Packit Service |
ff689b |
if (numnew <= 0)
|
|
Packit Service |
ff689b |
return;
|
|
Packit Service |
ff689b |
hashmask = mkmask(ss->nstrings + numnew);
|
|
Packit Service |
ff689b |
if (hashmask <= ss->stringhashmask)
|
|
Packit Service |
ff689b |
return; /* same as before */
|
|
Packit Service |
ff689b |
|
|
Packit Service |
ff689b |
/* realloc hash table */
|
|
Packit Service |
ff689b |
ss->stringhashmask = hashmask;
|
|
Packit Service |
ff689b |
solv_free(ss->stringhashtbl);
|
|
Packit Service |
ff689b |
ss->stringhashtbl = hashtbl = (Hashtable)solv_calloc(hashmask + 1, sizeof(Id));
|
|
Packit Service |
ff689b |
|
|
Packit Service |
ff689b |
/* rehash all strings into new hashtable */
|
|
Packit Service |
ff689b |
for (i = 1; i < ss->nstrings; i++)
|
|
Packit Service |
ff689b |
{
|
|
Packit Service |
ff689b |
h = strhash(ss->stringspace + ss->strings[i]) & hashmask;
|
|
Packit Service |
ff689b |
hh = HASHCHAIN_START;
|
|
Packit Service |
ff689b |
while (hashtbl[h] != 0)
|
|
Packit Service |
ff689b |
h = HASHCHAIN_NEXT(h, hh, hashmask);
|
|
Packit Service |
ff689b |
hashtbl[h] = i;
|
|
Packit Service |
ff689b |
}
|
|
Packit Service |
ff689b |
}
|
|
Packit Service |
ff689b |
|
|
Packit Service |
ff689b |
Id
|
|
Packit Service |
ff689b |
stringpool_strn2id(Stringpool *ss, const char *str, unsigned int len, int create)
|
|
Packit Service |
ff689b |
{
|
|
Packit Service |
ff689b |
Hashval h, hh, hashmask, oldhashmask;
|
|
Packit Service |
ff689b |
Id id;
|
|
Packit Service |
ff689b |
Hashtable hashtbl;
|
|
Packit Service |
ff689b |
|
|
Packit Service |
ff689b |
if (!str)
|
|
Packit Service |
ff689b |
return STRID_NULL;
|
|
Packit Service |
ff689b |
if (!len)
|
|
Packit Service |
ff689b |
return STRID_EMPTY;
|
|
Packit Service |
ff689b |
|
|
Packit Service |
ff689b |
hashmask = oldhashmask = ss->stringhashmask;
|
|
Packit Service |
ff689b |
/* expand hashtable if needed */
|
|
Packit Service |
ff689b |
if ((Hashval)ss->nstrings * 2 > hashmask)
|
|
Packit Service |
ff689b |
{
|
|
Packit Service |
ff689b |
stringpool_resize_hash(ss, STRING_BLOCK);
|
|
Packit Service |
ff689b |
hashmask = ss->stringhashmask;
|
|
Packit Service |
ff689b |
}
|
|
Packit Service |
ff689b |
hashtbl = ss->stringhashtbl;
|
|
Packit Service |
ff689b |
|
|
Packit Service |
ff689b |
/* compute hash and check for match */
|
|
Packit Service |
ff689b |
h = strnhash(str, len) & hashmask;
|
|
Packit Service |
ff689b |
hh = HASHCHAIN_START;
|
|
Packit Service |
ff689b |
while ((id = hashtbl[h]) != 0)
|
|
Packit Service |
ff689b |
{
|
|
Packit Service |
ff689b |
if(!memcmp(ss->stringspace + ss->strings[id], str, len)
|
|
Packit Service |
ff689b |
&& ss->stringspace[ss->strings[id] + len] == 0)
|
|
Packit Service |
ff689b |
break;
|
|
Packit Service |
ff689b |
h = HASHCHAIN_NEXT(h, hh, hashmask);
|
|
Packit Service |
ff689b |
}
|
|
Packit Service |
ff689b |
if (id || !create) /* exit here if string found */
|
|
Packit Service |
ff689b |
return id;
|
|
Packit Service |
ff689b |
|
|
Packit Service |
ff689b |
/* this should be a test for a flag that tells us if the
|
|
Packit Service |
ff689b |
* correct blocking is used, but adding a flag would break
|
|
Packit Service |
ff689b |
* the ABI. So we use the existance of the hash area as
|
|
Packit Service |
ff689b |
* indication instead */
|
|
Packit Service |
ff689b |
if (!oldhashmask)
|
|
Packit Service |
ff689b |
{
|
|
Packit Service |
ff689b |
ss->stringspace = solv_extend_resize(ss->stringspace, ss->sstrings + len + 1, 1, STRINGSPACE_BLOCK);
|
|
Packit Service |
ff689b |
ss->strings = solv_extend_resize(ss->strings, ss->nstrings + 1, sizeof(Offset), STRING_BLOCK);
|
|
Packit Service |
ff689b |
}
|
|
Packit Service |
ff689b |
|
|
Packit Service |
ff689b |
/* generate next id and save in table */
|
|
Packit Service |
ff689b |
id = ss->nstrings++;
|
|
Packit Service |
ff689b |
hashtbl[h] = id;
|
|
Packit Service |
ff689b |
|
|
Packit Service |
ff689b |
ss->strings = solv_extend(ss->strings, id, 1, sizeof(Offset), STRING_BLOCK);
|
|
Packit Service |
ff689b |
ss->strings[id] = ss->sstrings; /* we will append to the end */
|
|
Packit Service |
ff689b |
|
|
Packit Service |
ff689b |
/* append string to stringspace */
|
|
Packit Service |
ff689b |
ss->stringspace = solv_extend(ss->stringspace, ss->sstrings, len + 1, 1, STRINGSPACE_BLOCK);
|
|
Packit Service |
ff689b |
memcpy(ss->stringspace + ss->sstrings, str, len);
|
|
Packit Service |
ff689b |
ss->stringspace[ss->sstrings + len] = 0;
|
|
Packit Service |
ff689b |
ss->sstrings += len + 1;
|
|
Packit Service |
ff689b |
return id;
|
|
Packit Service |
ff689b |
}
|
|
Packit Service |
ff689b |
|
|
Packit Service |
ff689b |
Id
|
|
Packit Service |
ff689b |
stringpool_str2id(Stringpool *ss, const char *str, int create)
|
|
Packit Service |
ff689b |
{
|
|
Packit Service |
ff689b |
if (!str)
|
|
Packit Service |
ff689b |
return STRID_NULL;
|
|
Packit Service |
ff689b |
if (!*str)
|
|
Packit Service |
ff689b |
return STRID_EMPTY;
|
|
Packit Service |
ff689b |
return stringpool_strn2id(ss, str, (unsigned int)strlen(str), create);
|
|
Packit Service |
ff689b |
}
|
|
Packit Service |
ff689b |
|
|
Packit Service |
ff689b |
void
|
|
Packit Service |
ff689b |
stringpool_shrink(Stringpool *ss)
|
|
Packit Service |
ff689b |
{
|
|
Packit Service |
ff689b |
ss->stringspace = solv_extend_resize(ss->stringspace, ss->sstrings, 1, STRINGSPACE_BLOCK);
|
|
Packit Service |
ff689b |
ss->strings = solv_extend_resize(ss->strings, ss->nstrings, sizeof(Offset), STRING_BLOCK);
|
|
Packit Service |
ff689b |
}
|