diff options
author | Michael Matz <matz@suse.de> | 2007-11-16 13:48:23 +0000 |
---|---|---|
committer | Michael Matz <matz@suse.de> | 2007-11-16 13:48:23 +0000 |
commit | 9e09e79d5ea318d3e4ec8f9dc7b2d53c9c2a07c6 (patch) | |
tree | 096d85b660e63cc5c670a353add5b41c98536f80 /src/strpool.c | |
parent | 06ad039561bc89fb3937a0503870333d32ee087e (diff) | |
download | libsolv-9e09e79d5ea318d3e4ec8f9dc7b2d53c9c2a07c6.tar.gz libsolv-9e09e79d5ea318d3e4ec8f9dc7b2d53c9c2a07c6.tar.bz2 libsolv-9e09e79d5ea318d3e4ec8f9dc7b2d53c9c2a07c6.zip |
Reduce C&P code by factoring out the uniquifying string pool.
Diffstat (limited to 'src/strpool.c')
-rw-r--r-- | src/strpool.c | 122 |
1 files changed, 122 insertions, 0 deletions
diff --git a/src/strpool.c b/src/strpool.c new file mode 100644 index 0000000..622664f --- /dev/null +++ b/src/strpool.c @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2007, Novell Inc. + * + * This program is licensed under the BSD license, read LICENSE.BSD + * for further information + */ + +#include <string.h> +#include "util.h" +#include "strpool.h" + +#define STRING_BLOCK 2047 +#define STRINGSPACE_BLOCK 65535 + +void +stringpool_init (Stringpool *ss, const char *strs[]) +{ + unsigned totalsize = 0; + unsigned count; + // count number and total size of predefined strings + for (count = 0; strs[count]; count++) + totalsize += strlen(strs[count]) + 1; + + // alloc appropriate space + ss->stringspace = (char *)xmalloc((totalsize + STRINGSPACE_BLOCK) & ~STRINGSPACE_BLOCK); + ss->strings = (Offset *)xmalloc(((count + STRING_BLOCK) & ~STRING_BLOCK) * sizeof(Offset)); + + // now copy predefined strings into allocated space + ss->sstrings = 0; + for (count = 0; strs[count]; count++) + { + strcpy(ss->stringspace + ss->sstrings, strs[count]); + ss->strings[count] = ss->sstrings; + ss->sstrings += strlen(strs[count]) + 1; + } + ss->nstrings = count; +} + +Id +stringpool_str2id (Stringpool *ss, const char *str, int create) +{ + Hashval h; + unsigned int hh; + Hashmask hashmask; + int i, space_needed; + Id id; + Hashtable hashtbl; + + // check string + if (!str) + return STRID_NULL; + if (!*str) + return STRID_EMPTY; + + hashmask = ss->stringhashmask; + hashtbl = ss->stringhashtbl; + + // expand hashtable if needed + // + // + if (ss->nstrings * 2 > hashmask) + { + xfree(hashtbl); + + // realloc hash table + ss->stringhashmask = hashmask = mkmask(ss->nstrings + STRING_BLOCK); + ss->stringhashtbl = hashtbl = (Hashtable)xcalloc(hashmask + 1, sizeof(Id)); + + // rehash all strings into new hashtable + for (i = 1; i < ss->nstrings; i++) + { + h = strhash(ss->stringspace + ss->strings[i]) & hashmask; + hh = HASHCHAIN_START; + while (hashtbl[h] != 0) // follow overflow chain + h = HASHCHAIN_NEXT(h, hh, hashmask); + hashtbl[h] = i; + } + } + + // compute hash and check for match + + h = strhash(str) & hashmask; + hh = HASHCHAIN_START; + while ((id = hashtbl[h]) != 0) // follow hash overflow chain + { + // break if string already hashed + if(!strcmp(ss->stringspace + ss->strings[id], str)) + break; + h = HASHCHAIN_NEXT(h, hh, hashmask); + } + if (id || !create) // exit here if string found + return id; + + // generate next id and save in table + id = ss->nstrings++; + hashtbl[h] = id; + + // + if ((id & STRING_BLOCK) == 0) + ss->strings = xrealloc(ss->strings, ((ss->nstrings + STRING_BLOCK) & ~STRING_BLOCK) * sizeof(Hashval)); + // 'pointer' into stringspace is Offset of next free pos: sstrings + ss->strings[id] = ss->sstrings; + + space_needed = strlen(str) + 1; + + // resize string buffer if needed + if (((ss->sstrings + space_needed - 1) | STRINGSPACE_BLOCK) != ((ss->sstrings - 1) | STRINGSPACE_BLOCK)) + ss->stringspace = xrealloc(ss->stringspace, (ss->sstrings + space_needed + STRINGSPACE_BLOCK) & ~STRINGSPACE_BLOCK); + // copy new string into buffer + memcpy(ss->stringspace + ss->sstrings, str, space_needed); + // next free pos is behind new string + ss->sstrings += space_needed; + + return id; +} + +void +stringpool_shrink (Stringpool *ss) +{ + ss->stringspace = (char *)xrealloc(ss->stringspace, (ss->sstrings + STRINGSPACE_BLOCK) & ~STRINGSPACE_BLOCK); + ss->strings = (Offset *)xrealloc(ss->strings, ((ss->nstrings + STRING_BLOCK) & ~STRING_BLOCK) * sizeof(Offset)); +} |