blob: dbe76282ae47512bbdd5cc8e0dd288cc9962164a (
plain) (
tree)
|
|
/*
* %CopyrightBegin%
*
* Copyright Ericsson AB 1998-2009. All Rights Reserved.
*
* The contents of this file are subject to the Erlang Public License,
* Version 1.1, (the "License"); you may not use this file except in
* compliance with the License. You should have received a copy of the
* Erlang Public License along with this software. If not, it can be
* retrieved online at http://www.erlang.org/.
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
* the License for the specific language governing rights and limitations
* under the License.
*
* %CopyrightEnd%
*
*/
#include <stdlib.h>
#include <string.h>
#include "hash.h"
/* this function returns a bucket - from the freelist if one was found
* there, or from malloc(). Only "small" buckets, i.e. those whose
* keys are short enough to be stored in the bucket itself, are saved
* on the freelist.
*/
static ei_bucket *ei_hash_bmalloc(ei_hash *tab)
{
ei_bucket *new;
if (tab->freelist) {
new = tab->freelist;
tab->freelist = new->next;
/* fprintf(stderr,"getting bucket from freelist\n"); */
}
else {
new = malloc(sizeof(*new));
/* fprintf(stderr,"allocating new (small) bucket\n"); */
}
return new;
}
/* insert a new key-value pair. The old value (if any) is returned. If
* the malloc fails the function returns NULL. This is potentially a
* problem since the function returns the same thing when malloc fails
* as when a item is inserted that did not previously exist in the
* table. */
void *ei_hash_insert(ei_hash *tab, const char *key, const void *value)
{
const void *oldval=NULL;
ei_bucket *b=NULL;
int h, rh;
rh = tab->hash(key);
h = rh % tab->size;
b=tab->tab[h];
while (b) {
if ((rh == b->rawhash) && (!strcmp(key,b->key)))
break;
b=b->next;
}
if (b) {
/* replace existing value, return old value */
oldval = b->value;
b->value = value;
}
else {
int keylen = strlen(key);
/* this element is new */
if (keylen < EI_SMALLKEY) {
/* short keys stored directly in bucket */
/* try to get bucket from freelist */
if ((b = ei_hash_bmalloc(tab)) == NULL) return NULL;
b->key = b->keybuf;
}
else {
/* for longer keys we allocate space */
int keypos=sizeof(*b);
ei_align(keypos);
if ((b = malloc(keypos+keylen+1)) == NULL) return NULL;
b->key = (char *)b + keypos;
/* fprintf(stderr,"allocating new (large) bucket\n"); */
}
/* fill in the blanks */
b->rawhash = rh;
strcpy((char *)b->key,key);
b->value = value;
/* some statistiscs */
if (!tab->tab[h]) tab->npos++;
tab->nelem++;
/* link in the new element */
b->next = tab->tab[h];
tab->tab[h] = b;
}
return (void *)oldval;
}
|