Significantly simplify dictionaries

Significantly simplify dictionaries so that dictionary keys are always
uint32_t; this number can be an arbitrary integer, be it a file
descriptor, for instance, or a hashed value
This commit is contained in:
XANTRONIX Development 2020-07-08 17:12:40 -04:00 committed by XANTRONIX Industrial
parent a7cab09e47
commit b281925eba
5 changed files with 84 additions and 136 deletions

View file

@ -4,17 +4,14 @@
#include <stdint.h> #include <stdint.h>
#include <sys/types.h> #include <sys/types.h>
#include <patty/hash.h>
#define PATTY_DICT_BUCKET_SIZE 16 #define PATTY_DICT_BUCKET_SIZE 16
typedef struct _patty_dict_slot { typedef struct _patty_dict_slot {
uint32_t hash; uint32_t key;
void * key; void *value;
size_t keysz; int set;
void * value;
struct _patty_dict_slot * next; struct _patty_dict_slot *next;
} patty_dict_slot; } patty_dict_slot;
typedef struct _patty_dict_bucket { typedef struct _patty_dict_bucket {
@ -27,10 +24,9 @@ typedef struct _patty_dict {
patty_dict *patty_dict_new(); patty_dict *patty_dict_new();
patty_dict_slot *patty_dict_slot_find(patty_dict *dict, uint32_t hash); patty_dict_slot *patty_dict_slot_find(patty_dict *dict, uint32_t key);
typedef int (*patty_dict_callback)(void *key, typedef int (*patty_dict_callback)(uint32_t key,
size_t keysz,
void *value, void *value,
void *ctx); void *ctx);
@ -38,21 +34,11 @@ int patty_dict_each(patty_dict *dict,
patty_dict_callback callback, patty_dict_callback callback,
void *ctx); void *ctx);
void *patty_dict_get_with_hash(patty_dict *dict, uint32_t hash); void *patty_dict_get(patty_dict *dict, uint32_t key);
void *patty_dict_get(patty_dict *dict, void *key, size_t keysz); void *patty_dict_set(patty_dict *dict, uint32_t key, void *value);
void *patty_dict_set_with_hash(patty_dict *dict, int patty_dict_delete(patty_dict *dict, uint32_t key);
void *key,
size_t keysz,
void *value,
uint32_t hash);
void *patty_dict_set(patty_dict *dict, void *key, size_t keysz, void *value);
int patty_dict_delete_with_hash(patty_dict *dict, uint32_t hash);
int patty_dict_delete(patty_dict *dict, void *key, size_t keysz);
void patty_dict_destroy(patty_dict *dict); void patty_dict_destroy(patty_dict *dict);

View file

@ -2,7 +2,6 @@
#include <string.h> #include <string.h>
#include <patty/dict.h> #include <patty/dict.h>
#include <patty/hash.h>
patty_dict *patty_dict_new() { patty_dict *patty_dict_new() {
patty_dict *dict; patty_dict *dict;
@ -19,24 +18,24 @@ error_malloc_dict:
return NULL; return NULL;
} }
patty_dict_slot *patty_dict_slot_find(patty_dict *dict, uint32_t hash) { patty_dict_slot *patty_dict_slot_find(patty_dict *dict, uint32_t key) {
patty_dict_bucket *bucket = &dict->bucket; patty_dict_bucket *bucket = &dict->bucket;
int collisions; int collisions;
for (collisions = 0; collisions < 7; collisions++) { for (collisions = 0; collisions < 7; collisions++) {
uint32_t mask = 0x0f << (4 * collisions); uint32_t mask = 0x0f << (4 * collisions);
uint8_t index = (hash & mask) >> (4 * collisions); uint8_t index = (key & mask) >> (4 * collisions);
patty_dict_slot *slot = &bucket->slots[index]; patty_dict_slot *slot = &bucket->slots[index];
if (slot->hash == 0x00000000) { if (!slot->set) {
/* /*
* In this case, we have determined that there is no value in the * In this case, we have determined that there is no value in the
* dict for the given hash. * dict for the given key.
*/ */
return NULL; return NULL;
} else if (slot->hash == hash) { } else if (slot->key == key) {
/* /*
* We have found the desired slot, so return that. * We have found the desired slot, so return that.
*/ */
@ -59,7 +58,10 @@ patty_dict_slot *patty_dict_slot_find(patty_dict *dict, uint32_t hash) {
return NULL; return NULL;
} }
static int bucket_each_slot(int level, patty_dict_bucket *bucket, patty_dict_callback callback, void *ctx) { static int bucket_each_slot(int level,
patty_dict_bucket *bucket,
patty_dict_callback callback,
void *ctx) {
int i; int i;
if (level > 7) { if (level > 7) {
@ -69,8 +71,8 @@ static int bucket_each_slot(int level, patty_dict_bucket *bucket, patty_dict_cal
for (i=0; i<PATTY_DICT_BUCKET_SIZE; i++) { for (i=0; i<PATTY_DICT_BUCKET_SIZE; i++) {
patty_dict_slot *slot = &bucket->slots[i]; patty_dict_slot *slot = &bucket->slots[i];
if (slot->key != NULL && slot->keysz > 0) { if (slot->set) {
if (callback(slot->key, slot->keysz, slot->value, ctx) < 0) { if (callback(slot->key, slot->value, ctx) < 0) {
goto error_callback; goto error_callback;
} }
} }
@ -96,46 +98,39 @@ int patty_dict_each(patty_dict *dict, patty_dict_callback callback, void *ctx) {
return bucket_each_slot(0, &dict->bucket, callback, ctx); return bucket_each_slot(0, &dict->bucket, callback, ctx);
} }
void *patty_dict_get_with_hash(patty_dict *dict, uint32_t hash) { void *patty_dict_get(patty_dict *dict, uint32_t key) {
patty_dict_slot *slot; patty_dict_slot *slot;
if ((slot = patty_dict_slot_find(dict, hash)) == NULL) { if ((slot = patty_dict_slot_find(dict, key)) == NULL) {
return NULL; return NULL;
} }
return slot->value; return slot->value;
} }
void *patty_dict_get(patty_dict *dict, void *key, size_t keysz) { void *patty_dict_set(patty_dict *dict,
return patty_dict_get_with_hash(dict, patty_hash(key, keysz)); uint32_t key,
} void *value) {
void *patty_dict_set_with_hash(patty_dict *dict,
void *key,
size_t keysz,
void *value,
uint32_t hash) {
patty_dict_bucket *bucket = &dict->bucket; patty_dict_bucket *bucket = &dict->bucket;
int collisions; int collisions;
for (collisions = 0; collisions < 7; collisions++) { for (collisions = 0; collisions < 7; collisions++) {
uint32_t mask = 0x0f << (4 * collisions); uint32_t mask = 0x0f << (4 * collisions);
uint8_t index = (hash & mask) >> (4 * collisions); uint8_t index = (key & mask) >> (4 * collisions);
patty_dict_slot *slot = &bucket->slots[index]; patty_dict_slot *slot = &bucket->slots[index];
if (slot->hash == 0x00000000 && slot->key == NULL) { if (!slot->set) {
/* /*
* We have found an empty hash slot, so let's store the value. * We have found an empty slot, so let's store the value.
*/ */
slot->hash = hash;
slot->key = key; slot->key = key;
slot->keysz = keysz;
slot->value = value; slot->value = value;
slot->set = 1;
return value; return value;
} else if (slot->hash == hash) { } else if (slot->key == key) {
/* /*
* Otherwise, we've found an existing slot, so let's update that * Otherwise, we've found an existing slot, so let's update that
* and bail. * and bail.
@ -168,18 +163,10 @@ error_malloc_bucket:
return NULL; return NULL;
} }
void *patty_dict_set(patty_dict *dict, void *key, size_t keysz, void *value) { int patty_dict_delete(patty_dict *dict, uint32_t key) {
return patty_dict_set_with_hash(dict,
key,
keysz,
value,
patty_hash(key, keysz));
}
int patty_dict_delete_with_hash(patty_dict *dict, uint32_t hash) {
patty_dict_slot *slot; patty_dict_slot *slot;
if ((slot = patty_dict_slot_find(dict, hash)) == NULL) { if ((slot = patty_dict_slot_find(dict, key)) == NULL) {
goto error_dict_slot_find; goto error_dict_slot_find;
} }
@ -191,10 +178,6 @@ error_dict_slot_find:
return -1; return -1;
} }
int patty_dict_delete(patty_dict *dict, void *key, size_t keysz) {
return patty_dict_delete_with_hash(dict, patty_hash(key, keysz));
}
void patty_dict_destroy(patty_dict *dict) { void patty_dict_destroy(patty_dict *dict) {
free(dict); free(dict);
} }

View file

@ -273,32 +273,30 @@ error_ntop:
int patty_ax25_if_promisc_add(patty_ax25_if *iface, int patty_ax25_if_promisc_add(patty_ax25_if *iface,
int fd) { int fd) {
if (patty_dict_get_with_hash(iface->promisc_fds, (uint32_t)fd)) { if (patty_dict_get(iface->promisc_fds, (uint32_t)fd)) {
errno = EEXIST; errno = EEXIST;
goto error_exists; goto error_exists;
} }
if (patty_dict_set_with_hash(iface->promisc_fds, if (patty_dict_set(iface->promisc_fds,
NULL + fd, (uint32_t)fd,
sizeof(fd), NULL + fd) == NULL) {
NULL + fd,
(uint32_t)fd) == NULL) {
errno = ENOMEM; errno = ENOMEM;
goto error_dict_set_with_hash; goto error_dict_set;
} }
return 0; return 0;
error_dict_set_with_hash: error_dict_set:
error_exists: error_exists:
return -1; return -1;
} }
int patty_ax25_if_promisc_delete(patty_ax25_if *iface, int patty_ax25_if_promisc_delete(patty_ax25_if *iface,
int fd) { int fd) {
if (patty_dict_delete_with_hash(iface->promisc_fds, if (patty_dict_delete(iface->promisc_fds,
(uint32_t)fd) < 0) { (uint32_t)fd) < 0) {
errno = ENOENT; errno = ENOENT;
@ -317,11 +315,10 @@ struct promisc_frame {
patty_ax25_if *iface; patty_ax25_if *iface;
}; };
static int handle_promisc_frame(void *key, static int handle_promisc_frame(uint32_t key,
size_t keysz,
void *value, void *value,
void *ctx) { void *ctx) {
int fd = (int)(value - NULL); int fd = (int)key;
struct promisc_frame *frame = ctx; struct promisc_frame *frame = ctx;
if (write(fd, frame->buf, frame->len) < 0) { if (write(fd, frame->buf, frame->len) < 0) {

View file

@ -71,7 +71,7 @@ patty_ax25_route *patty_ax25_route_table_find(patty_ax25_route_table *table,
patty_ax25_addr_hash(&hash, dest); patty_ax25_addr_hash(&hash, dest);
patty_hash_end(&hash); patty_hash_end(&hash);
route = patty_dict_get_with_hash(table, hash); route = patty_dict_get(table, hash);
if (route) { if (route) {
return route; return route;
@ -91,7 +91,7 @@ patty_ax25_route *patty_ax25_route_table_default(patty_ax25_route_table *table)
patty_ax25_addr_hash(&hash, &empty); patty_ax25_addr_hash(&hash, &empty);
patty_hash_end(&hash); patty_hash_end(&hash);
return patty_dict_get_with_hash(table, hash); return patty_dict_get(table, hash);
} }
int patty_ax25_route_table_add(patty_ax25_route_table *table, int patty_ax25_route_table_add(patty_ax25_route_table *table,
@ -108,17 +108,13 @@ int patty_ax25_route_table_add(patty_ax25_route_table *table,
goto error_exists; goto error_exists;
} }
if (patty_dict_set_with_hash(table, if (patty_dict_set(table, hash, route) == NULL) {
&route->dest, goto error_dict_set;
sizeof(route->dest),
route,
hash) == NULL) {
goto error_dict_set_with_hash;
} }
return 0; return 0;
error_dict_set_with_hash: error_dict_set:
error_exists: error_exists:
return -1; return -1;
} }
@ -131,5 +127,5 @@ int patty_ax25_route_table_delete(patty_ax25_route_table *route,
patty_ax25_addr_hash(&hash, dest); patty_ax25_addr_hash(&hash, dest);
patty_hash_end(&hash); patty_hash_end(&hash);
return patty_dict_delete_with_hash(route, hash); return patty_dict_delete(route, hash);
} }

View file

@ -10,6 +10,7 @@
#include <errno.h> #include <errno.h>
#include <patty/ax25.h> #include <patty/ax25.h>
#include <patty/hash.h>
typedef int (*patty_ax25_server_call)(patty_ax25_server *, int); typedef int (*patty_ax25_server_call)(patty_ax25_server *, int);
@ -154,7 +155,7 @@ static inline void clear_fd(patty_ax25_server *server, int fd) {
static patty_ax25_sock *sock_by_fd(patty_dict *dict, static patty_ax25_sock *sock_by_fd(patty_dict *dict,
int fd) { int fd) {
return patty_dict_get_with_hash(dict, (uint32_t)fd); return patty_dict_get(dict, (uint32_t)fd);
} }
static patty_ax25_sock *sock_by_addr(patty_dict *dict, static patty_ax25_sock *sock_by_addr(patty_dict *dict,
@ -165,7 +166,7 @@ static patty_ax25_sock *sock_by_addr(patty_dict *dict,
patty_ax25_addr_hash(&hash, addr); patty_ax25_addr_hash(&hash, addr);
patty_hash_end(&hash); patty_hash_end(&hash);
return patty_dict_get_with_hash(dict, hash); return patty_dict_get(dict, hash);
} }
static patty_ax25_sock *sock_by_addrpair(patty_dict *dict, static patty_ax25_sock *sock_by_addrpair(patty_dict *dict,
@ -178,15 +179,13 @@ static patty_ax25_sock *sock_by_addrpair(patty_dict *dict,
patty_ax25_addr_hash(&hash, remote); patty_ax25_addr_hash(&hash, remote);
patty_hash_end(&hash); patty_hash_end(&hash);
return patty_dict_get_with_hash(dict, hash); return patty_dict_get(dict, hash);
} }
static int sock_save_by_fd(patty_dict *dict, patty_ax25_sock *sock) { static int sock_save_by_fd(patty_dict *dict, patty_ax25_sock *sock) {
if (patty_dict_set_with_hash(dict, if (patty_dict_set(dict,
NULL + sock->fd, (uint32_t)sock->fd,
sizeof(sock->fd), sock) == NULL) {
sock,
(uint32_t)sock->fd) == NULL) {
goto error_dict_set; goto error_dict_set;
} }
@ -200,37 +199,35 @@ static inline int client_by_sock(patty_ax25_server *server,
patty_ax25_sock *sock) { patty_ax25_sock *sock) {
void *value; void *value;
if ((value = patty_dict_get_with_hash(server->clients_by_sock, if ((value = patty_dict_get(server->clients_by_sock,
(uint32_t)sock->fd)) == NULL) { (uint32_t)sock->fd)) == NULL) {
goto error_dict_get_with_hash; goto error_dict_get;
} }
return (int)((int64_t)value); return (int)((int64_t)value);
error_dict_get_with_hash: error_dict_get:
return -1; return -1;
} }
static inline int client_save_by_sock(patty_ax25_server *server, static inline int client_save_by_sock(patty_ax25_server *server,
int client, int client,
patty_ax25_sock *sock) { patty_ax25_sock *sock) {
if (patty_dict_set_with_hash(server->clients_by_sock, if (patty_dict_set(server->clients_by_sock,
NULL + sock->fd, (uint32_t)sock->fd,
sizeof(sock->fd), NULL + client) == NULL) {
NULL + client, goto error_dict_set;
(uint32_t)sock->fd) == NULL) {
goto error_dict_set_with_hash;
} }
return 0; return 0;
error_dict_set_with_hash: error_dict_set:
return -1; return -1;
} }
static inline int client_delete_by_sock(patty_ax25_server *server, static inline int client_delete_by_sock(patty_ax25_server *server,
patty_ax25_sock *sock) { patty_ax25_sock *sock) {
return patty_dict_delete_with_hash(server->clients_by_sock, sock->fd); return patty_dict_delete(server->clients_by_sock, (uint32_t)sock->fd);
} }
static inline uint32_t hash_addr(patty_ax25_addr *addr) { static inline uint32_t hash_addr(patty_ax25_addr *addr) {
@ -260,17 +257,15 @@ static int sock_save_by_addr(patty_dict *dict,
patty_ax25_addr *addr) { patty_ax25_addr *addr) {
uint32_t hash = hash_addr(addr); uint32_t hash = hash_addr(addr);
if (patty_dict_set_with_hash(dict, if (patty_dict_set(dict,
addr, hash,
sizeof(*addr), sock) == NULL) {
sock, goto error_dict_set;
hash) == NULL) {
goto error_dict_set_with_hash;
} }
return 0; return 0;
error_dict_set_with_hash: error_dict_set:
return -1; return -1;
} }
@ -280,17 +275,15 @@ static int sock_save_by_addrpair(patty_dict *dict,
patty_ax25_addr *remote) { patty_ax25_addr *remote) {
uint32_t hash = hash_addrpair(local, remote); uint32_t hash = hash_addrpair(local, remote);
if (patty_dict_set_with_hash(dict, if (patty_dict_set(dict,
NULL + sock->fd, hash,
sizeof(*sock), sock) == NULL) {
sock, goto error_dict_set;
hash) == NULL) {
goto error_dict_set_with_hash;
} }
return 0; return 0;
error_dict_set_with_hash: error_dict_set:
return -1; return -1;
} }
@ -298,7 +291,7 @@ static int sock_delete_by_addr(patty_dict *dict,
patty_ax25_addr *addr) { patty_ax25_addr *addr) {
uint32_t hash = hash_addr(addr); uint32_t hash = hash_addr(addr);
return patty_dict_delete_with_hash(dict, hash); return patty_dict_delete(dict, hash);
} }
static int sock_delete_by_addrpair(patty_dict *dict, static int sock_delete_by_addrpair(patty_dict *dict,
@ -306,7 +299,7 @@ static int sock_delete_by_addrpair(patty_dict *dict,
patty_ax25_addr *remote) { patty_ax25_addr *remote) {
uint32_t hash = hash_addrpair(local, remote); uint32_t hash = hash_addrpair(local, remote);
return patty_dict_delete_with_hash(dict, hash); return patty_dict_delete(dict, hash);
} }
static int sock_close(patty_ax25_server *server, static int sock_close(patty_ax25_server *server,
@ -338,7 +331,7 @@ static int sock_close(patty_ax25_server *server,
} }
} }
if (patty_dict_delete_with_hash(server->socks_by_fd, sock->fd) < 0) { if (patty_dict_delete(server->socks_by_fd, (uint32_t)sock->fd) < 0) {
goto error_dict_delete_by_fd_socks; goto error_dict_delete_by_fd_socks;
} }
@ -398,7 +391,7 @@ int patty_ax25_server_delete_if(patty_ax25_server *server,
if ((fd = patty_kiss_tnc_fd(iface->tnc)) >= 0) { if ((fd = patty_kiss_tnc_fd(iface->tnc)) >= 0) {
watch_fd(server, fd); watch_fd(server, fd);
if (patty_dict_delete(server->socks_by_fd, NULL + fd, sizeof(fd)) < 0) { if (patty_dict_delete(server->socks_by_fd, (uint32_t)fd) < 0) {
goto error_dict_delete; goto error_dict_delete;
} }
} }
@ -909,11 +902,7 @@ static int accept_client(patty_ax25_server *server) {
goto error_accept; goto error_accept;
} }
if (patty_dict_set_with_hash(server->clients, if (patty_dict_set(server->clients, (uint32_t)fd, NULL + fd) == NULL) {
NULL + fd,
sizeof(fd),
NULL + fd,
(uint32_t)fd) == NULL) {
goto error_dict_set; goto error_dict_set;
} }
@ -929,12 +918,11 @@ error_accept:
return -1; return -1;
} }
static int handle_client(void *key, static int handle_client(uint32_t key,
size_t keysz,
void *value, void *value,
void *ctx) { void *ctx) {
patty_ax25_server *server = ctx; patty_ax25_server *server = ctx;
int client = (int)(key - NULL); int client = (int)key;
ssize_t readlen; ssize_t readlen;
enum patty_ax25_call call; enum patty_ax25_call call;
@ -948,8 +936,7 @@ static int handle_client(void *key,
} else if (readlen == 0) { } else if (readlen == 0) {
clear_fd(server, client); clear_fd(server, client);
if (patty_dict_delete_with_hash(server->clients, if (patty_dict_delete(server->clients, key) < 0) {
(uint32_t)(key - NULL)) < 0) {
goto error_dict_delete; goto error_dict_delete;
} }
@ -1390,8 +1377,7 @@ error_io:
return -1; return -1;
} }
static int handle_sock(void *key, static int handle_sock(uint32_t key,
size_t keysz,
void *value, void *value,
void *ctx) { void *ctx) {
patty_ax25_server *server = ctx; patty_ax25_server *server = ctx;