void hash_destroy (hash_t h) { int i; struct hash_node *p, *q; if (!h) { errno = EINVAL; return; } lsd_mutex_lock (&h->mutex); assert (h->magic == HASH_MAGIC); for (i = 0; i < h->size; i++) { for (p = h->table[i]; p != NULL; p = q) { q = p->next; if (h->del_f) h->del_f (p->data); hash_node_free (p); } } assert (h->magic = ~HASH_MAGIC); /* clear magic via assert abuse */ lsd_mutex_unlock (&h->mutex); lsd_mutex_destroy (&h->mutex); free (h->table); free (h); return; }
void hash_destroy (hash_t h) { int i; struct hash_node *p, *q; if (!h) { errno = EINVAL; return; } lsd_mutex_lock (&h->mutex); for (i = 0; i < h->size; i++) { for (p = h->table[i]; p != NULL; p = q) { q = p->next; if (h->del_f) h->del_f (p->data); hash_node_free (p); } } lsd_mutex_unlock (&h->mutex); lsd_mutex_destroy (&h->mutex); free (h->table); free (h); return; }
static replay_t replay_alloc (void) { /* Allocates a replay struct. * Returns a ptr to the object, or NULL if memory allocation fails. */ int i; replay_t r; assert (REPLAY_ALLOC > 0); lsd_mutex_lock (&replay_free_lock); if (!replay_free_list) { if ((replay_free_list = malloc (REPLAY_ALLOC * sizeof (*r)))) { for (i = 0; i < REPLAY_ALLOC - 1; i++) replay_free_list[i].alloc.next = &replay_free_list[i+1]; replay_free_list[i].alloc.next = NULL; } } if ((r = replay_free_list)) { replay_free_list = r->alloc.next; } else { errno = ENOMEM; } lsd_mutex_unlock (&replay_free_lock); return (r); }
int hash_delete_if (hash_t h, hash_arg_f arg_f, void *arg) { int i; struct hash_node **pp; struct hash_node *p; int n = 0; if (!h || !arg_f) { errno = EINVAL; return (-1); } lsd_mutex_lock (&h->mutex); for (i = 0; i < h->size; i++) { pp = &(h->table[i]); while ((p = *pp) != NULL) { if (arg_f (p->data, p->hkey, arg) > 0) { if (h->del_f) h->del_f (p->data); *pp = p->next; hash_node_free (p); h->count--; n++; } else { pp = &(p->next); } } } lsd_mutex_unlock (&h->mutex); return (n); }
void * hash_remove (hash_t h, const void *key) { struct hash_node **pp; struct hash_node *p; unsigned int slot; void *data = NULL; if (!h || !key) { errno = EINVAL; return (NULL); } errno = 0; lsd_mutex_lock (&h->mutex); assert (h->magic == HASH_MAGIC); slot = h->key_f (key) % h->size; for (pp = &(h->table[slot]); (p = *pp) != NULL; pp = &((*pp)->next)) { if (!h->cmp_f (p->hkey, key)) { data = p->data; *pp = p->next; hash_node_free (p); h->count--; break; } } lsd_mutex_unlock (&h->mutex); return (data); }
void * hash_remove (hash_t h, const void *key) { unsigned int slot; int cmpval; struct hash_node **pp; struct hash_node *p; void *data = NULL; if (!h || !key) { errno = EINVAL; return (NULL); } errno = 0; lsd_mutex_lock (&h->mutex); slot = h->key_f (key) % h->size; for (pp = &(h->table[slot]); (p = *pp) != NULL; pp = &(p->next)) { cmpval = h->cmp_f (p->hkey, key); if (cmpval < 0) { continue; } if (cmpval == 0) { data = p->data; *pp = p->next; hash_node_free (p); h->count--; } break; } lsd_mutex_unlock (&h->mutex); return (data); }
void * hash_find (hash_t h, const void *key) { unsigned int slot; int cmpval; struct hash_node *p; void *data = NULL; if (!h || !key) { errno = EINVAL; return (NULL); } errno = 0; lsd_mutex_lock (&h->mutex); slot = h->key_f (key) % h->size; for (p = h->table[slot]; p != NULL; p = p->next) { cmpval = h->cmp_f (p->hkey, key); if (cmpval < 0) { continue; } if (cmpval == 0) { data = p->data; } break; } lsd_mutex_unlock (&h->mutex); return (data); }
void * hash_insert (hash_t h, const void *key, void *data) { struct hash_node *p; unsigned int slot; if (!h || !key || !data) { errno = EINVAL; return (NULL); } lsd_mutex_lock (&h->mutex); assert (h->magic == HASH_MAGIC); slot = h->key_f (key) % h->size; for (p = h->table[slot]; p != NULL; p = p->next) { if (!h->cmp_f (p->hkey, key)) { errno = EEXIST; data = NULL; goto end; } } if (!(p = hash_node_alloc ())) { data = lsd_nomem_error (__FILE__, __LINE__, "hash_insert"); goto end; } p->hkey = key; p->data = data; p->next = h->table[slot]; h->table[slot] = p; h->count++; end: lsd_mutex_unlock (&h->mutex); return (data); }
static void hash_node_free (struct hash_node *node) { /* De-allocates the object [node], returning it to the freelist. */ assert (node != NULL); lsd_mutex_lock (&hash_free_list_lock); node->next = hash_free_list; hash_free_list = node; lsd_mutex_unlock (&hash_free_list_lock); return; }
static void replay_free (replay_t r) { /* De-allocates the replay struct [r]. */ assert (r != NULL); lsd_mutex_lock (&replay_free_lock); r->alloc.next = replay_free_list; replay_free_list = r; lsd_mutex_unlock (&replay_free_lock); return; }
int hash_count (hash_t h) { int n; if (!h) { errno = EINVAL; return (-1); } lsd_mutex_lock (&h->mutex); n = h->count; lsd_mutex_unlock (&h->mutex); return (n); }
void hash_drop_memory (void) { struct hash_node *p; lsd_mutex_lock (&hash_free_list_lock); while (hash_mem_list != NULL) { p = hash_mem_list; hash_mem_list = p->next; free (p); } hash_free_list = NULL; lsd_mutex_unlock (&hash_free_list_lock); return; }
int hash_count (hash_t h) { int n; if (!h) { errno = EINVAL; return (0); } lsd_mutex_lock (&h->mutex); assert (h->magic == HASH_MAGIC); n = h->count; lsd_mutex_unlock (&h->mutex); return (n); }
static void hash_node_free (struct hash_node *node) { /* De-allocates the object [node], returning it to the freelist. */ assert (node != NULL); memset (node, 0, sizeof (*node)); #if 0 lsd_mutex_lock (&hash_free_lock); node->next = hash_free_list; hash_free_list = node; lsd_mutex_unlock (&hash_free_lock); #else free (node); #endif return; }
static struct hash_node * hash_node_alloc (void) { /* Allocates a hash node from the freelist. * Returns a ptr to the object, or NULL if memory allocation fails. */ size_t size; struct hash_node *p; int i; assert (HASH_NODE_ALLOC_NUM > 0); lsd_mutex_lock (&hash_free_list_lock); if (!hash_free_list) { size = sizeof (p) + (HASH_NODE_ALLOC_NUM * sizeof (*p)); p = malloc (size); if (p != NULL) { p->next = hash_mem_list; hash_mem_list = p; hash_free_list = (struct hash_node *) ((unsigned char *) p + sizeof (p)); for (i = 0; i < HASH_NODE_ALLOC_NUM - 1; i++) { hash_free_list[i].next = &hash_free_list[i+1]; } hash_free_list[i].next = NULL; } } if (hash_free_list) { p = hash_free_list; hash_free_list = p->next; memset (p, 0, sizeof (*p)); } else { errno = ENOMEM; } lsd_mutex_unlock (&hash_free_list_lock); return (p); }
void * hash_insert (hash_t h, const void *key, void *data) { unsigned int slot; int cmpval; struct hash_node **pp; struct hash_node *p; if (!h || !key || !data) { errno = EINVAL; return (NULL); } lsd_mutex_lock (&h->mutex); slot = h->key_f (key) % h->size; for (pp = &(h->table[slot]); (p = *pp) != NULL; pp = &(p->next)) { cmpval = h->cmp_f (p->hkey, key); if (cmpval < 0) { continue; } if (cmpval == 0) { errno = EEXIST; data = NULL; goto end; } break; } if (!(p = hash_node_alloc ())) { data = NULL; goto end; } p->hkey = key; p->data = data; p->next = *pp; *pp = p; h->count++; end: lsd_mutex_unlock (&h->mutex); return (data); }
int hash_for_each (hash_t h, hash_arg_f arg_f, void *arg) { int i; struct hash_node *p; int n = 0; if (!h || !arg_f) { errno = EINVAL; return (-1); } lsd_mutex_lock (&h->mutex); for (i = 0; i < h->size; i++) { for (p = h->table[i]; p != NULL; p = p->next) { if (arg_f (p->data, p->hkey, arg) > 0) { n++; } } } lsd_mutex_unlock (&h->mutex); return (n); }
static struct hash_node * hash_node_alloc (void) { /* Allocates a hash node from the freelist. * Memory is allocated in chunks of HASH_ALLOC. * Returns a ptr to the object, or NULL if memory allocation fails. */ #if 0 int i; #endif struct hash_node *p = NULL; assert (HASH_ALLOC > 0); #if 0 lsd_mutex_lock (&hash_free_lock); if (!hash_free_list) { if ((hash_free_list = malloc (HASH_ALLOC * sizeof (*p)))) { for (i = 0; i < HASH_ALLOC - 1; i++) hash_free_list[i].next = &hash_free_list[i+1]; hash_free_list[i].next = NULL; } } if (hash_free_list) { p = hash_free_list; hash_free_list = p->next; } else { errno = ENOMEM; } lsd_mutex_unlock (&hash_free_lock); #else if (!(p = malloc (sizeof(*p)))) errno = ENOMEM; #endif return (p); }
void * hash_find (hash_t h, const void *key) { unsigned int slot; struct hash_node *p; void *data = NULL; if (!h || !key) { errno = EINVAL; return (NULL); } errno = 0; lsd_mutex_lock (&h->mutex); assert (h->magic == HASH_MAGIC); slot = h->key_f (key) % h->size; for (p = h->table[slot]; p != NULL; p = p->next) { if (!h->cmp_f (p->hkey, key)) { data = p->data; break; } } lsd_mutex_unlock (&h->mutex); return (data); }