Example #1
0
/**
 * Add a new name to the hashset and allocate it a unique id
 * @param hs the hashset in question
 * @param prop the property to add
 * @return 1 if successful, else 0
 */
int hashset_put( hashset *hs, char *prop )
{
    unsigned slot;
    struct hs_bucket *b;
    if ( (float)hs->num_keys/(float)hs->num_buckets > MAX_RATIO )
    {
        if ( !hashset_rehash(hs) )
            return 0;
    }
    slot = hash(prop,strlen(prop))%hs->num_buckets;
    b = hs->buckets[slot];
    if ( b == NULL )
    {
        hs->buckets[slot] = hs_bucket_create(prop,hs->id++);
        if ( hs->buckets[slot] == NULL )
            return 0;
    }
    else
    {
        do
        {
            // if key already present, just return
            if ( strcmp(prop,b->key)==0 )
                return 0;
            else if ( b->next != NULL )
                b = b->next;
        }
        while ( b->next != NULL );
        // key not found
        b->next = hs_bucket_create(prop,hs->id++);
        if ( b->next == NULL )
            return 0;
    }
    hs->num_keys++;
    return 1;
}
Example #2
0
/* Add k:d to ht.  If k was already in ht, replace old entry by k:d.
   Rehash if necessary.  Returns TRUE if k was not already in ht. */
HASH_FUNC_INLINE
bool hashset_table_insert(hashset_table ht, hash_fn hash, keyeq_fn cmp,
                          hash_key k)
{
  assert(ht);

  if (ht->log2size == 0) {
    // array mode

    // replace?
    size_t i;
    for (i = 0; i < ht->used; ++i) {
      hash_key key = ht->table[i];
      if (key == k || cmp(key, k)) {
        ht->table[i] = k;
        return FALSE; /* replace */
      }
    }

    if (ht->used >= HASHSET_TABLE_ARRAY_THRESHOLD) {
      hashset_table_convert_to_hash_mode(ht, hash, cmp);
      // hash mode now
      assert(ht->log2size != 0);
      hashset_table_insert_internal(ht, hash, cmp, k);
      ht->used += 1;
    } else {
      // Resize.  We depend on the system realloc being smart and only
      // re-allocating if necessary (i.e. between 4 and 8 bytes, or if nothing
      // after, don't need to reallocate).
      ht->table = realloc(ht->table, (sizeof (hash_key))*(ht->used + 1));

      // append
      ht->table[ht->used] = k;
      ht->used += 1;
    }

    return TRUE; /* new key */

  } else {
    // hash mode

    if (ht->used > 3 * hashset_table_capacity(ht) / 4)
      hashset_rehash(ht, hash, cmp);
    if (ht->used >= HASHSET_TABLE_MAXSIZE) {
      abort();
    }

    size_t hashVal = hashset_find_bucket(ht, hash, k);
    size_t curIndex = hashVal;
    size_t tombstoneIndex = (size_t) -1;
    size_t i = 0;
    while (1) {
      hash_key key = ht->table[curIndex];

      if (key == NULL) {
        if (tombstoneIndex != (size_t) -1) {
          assert(ht->table[tombstoneIndex] == HASHSET_TOMBSTONE);
          ht->table[tombstoneIndex] = k;
          // don't increment ht->used since it already counts tombstones.
        } else {
          ht->table[curIndex] = k;
          ht->used++;
        }
        return TRUE; /* new key */
      }

      if (key == HASHSET_TOMBSTONE) {
        // quarl 2006-10-24
        //     We can replace this tombstone entry with the new key.  BUT, we
        //     still have to see if the key is currently in the table.  So keep
        //     looking, and if we don't find it, then replace the first tombstone
        //     we found with the new key.  Thanks to Simon Goldsmith & trendprof.
        if (tombstoneIndex == (size_t) -1) {
          tombstoneIndex = curIndex;
        }
      }

      if (hashset_do_cmp(key, k, cmp)) {
        // Update the data.
        //
        // quarl 2006-05-28:
        //     We *must* update the key since keys are potentially mutable and
        //     thus not the same even if they compare the same; not updating
        //     will cause inconsistencies later.
        ht->table[curIndex] = k;
        return FALSE; /* replace */
      }

      ++i;
      curIndex = hashset_probe(ht, hashVal, i);
      assert(i < hashset_table_capacity(ht)); // can't be 100% full - would have rehashed
      assert(curIndex != hashVal);
    }
  }
}