Blame src/strpool.c

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
}