improve paging logic, remove unused map code
This commit is contained in:
parent
242041da34
commit
5b9254211f
4 changed files with 31 additions and 190 deletions
|
@ -127,17 +127,31 @@ int success_handler(const void *key, size_t size, uintptr_t val, void *usr) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int suggest_command(char *command, char *command_re, hashmap *polls,
|
char *handle_pages(char *command, char *invs) {
|
||||||
char *name) {
|
|
||||||
char *invs = "/suggest ";
|
|
||||||
|
|
||||||
char *page;
|
|
||||||
|
|
||||||
if (strncmp(command, invs, strlen(invs)) == 0) {
|
if (strncmp(command, invs, strlen(invs)) == 0) {
|
||||||
page = &command[strlen(invs)];
|
return &command[strlen(invs)];
|
||||||
} else {
|
} else {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int handle_pages_int(char *command, char *invs) {
|
||||||
|
if (strncmp(command, invs, strlen(invs)) == 0) {
|
||||||
|
return stoi(&command[strlen(invs)]);
|
||||||
|
} else if (strncmp(command, invs, strlen(invs) - 1) == 0) {
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int suggest_command(char *command, char *command_re, hashmap *polls,
|
||||||
|
char *name) {
|
||||||
|
|
||||||
|
char *page = handle_pages(command, "/suggest ");
|
||||||
|
|
||||||
|
if (!page)
|
||||||
|
return 0;
|
||||||
page[strlen(page) - 1] = '\0';
|
page[strlen(page) - 1] = '\0';
|
||||||
|
|
||||||
if (strstr(page, "\n") || strstr(page, ";") || strstr(page, ",") ||
|
if (strstr(page, "\n") || strstr(page, ";") || strstr(page, ",") ||
|
||||||
|
@ -199,35 +213,21 @@ int suggest_command(char *command, char *command_re, hashmap *polls,
|
||||||
}
|
}
|
||||||
|
|
||||||
int help_command(char *command) {
|
int help_command(char *command) {
|
||||||
char *invs = "/help";
|
char *page = handle_pages(command, "/help");
|
||||||
|
|
||||||
int page;
|
if (!page)
|
||||||
|
|
||||||
if (strncmp(command, invs, strlen(invs)) == 0) {
|
|
||||||
|
|
||||||
printf("Available "
|
|
||||||
"commands:\n- elem1;elem2...\n- elem1+elem2...\n- elem1,elem2...\n- "
|
|
||||||
"/help\n- /inv [page]\n- /suggest [combo]\n- /polls [page]\n");
|
|
||||||
} else {
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
printf("Available "
|
||||||
|
"commands:\n- elem1;elem2...\n- elem1+elem2...\n- elem1,elem2...\n- "
|
||||||
|
"/help\n- /inv [page]\n- /suggest [combo]\n- /polls [page]\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int polls_command(char *command, hashmap *polls, hashmap *cmd) {
|
int polls_command(char *command, hashmap *polls, hashmap *cmd) {
|
||||||
|
|
||||||
char *invs = "/polls ";
|
int page = handle_pages_int(command, "/polls ");
|
||||||
|
if (page == 0)
|
||||||
int page;
|
|
||||||
|
|
||||||
if (strncmp(command, invs, strlen(invs)) == 0) {
|
|
||||||
page = stoi(&command[strlen(invs)]);
|
|
||||||
} else if (strncmp(command, invs, strlen(invs) - 1) == 0) {
|
|
||||||
page = 1;
|
|
||||||
} else {
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
|
|
||||||
printf("Current polls (page %i):\n", page);
|
printf("Current polls (page %i):\n", page);
|
||||||
struct pager i = {.page = page - 1, .i = -1, .is_poll = 1, .cmd = cmd};
|
struct pager i = {.page = page - 1, .i = -1, .is_poll = 1, .cmd = cmd};
|
||||||
|
@ -238,17 +238,9 @@ int polls_command(char *command, hashmap *polls, hashmap *cmd) {
|
||||||
|
|
||||||
int slash_command(char *command, hashmap *inv) {
|
int slash_command(char *command, hashmap *inv) {
|
||||||
|
|
||||||
char *invs = "/inv ";
|
int page = handle_pages_int(command, "/inv ");
|
||||||
|
if (page == 0)
|
||||||
int page;
|
|
||||||
|
|
||||||
if (strncmp(command, invs, strlen(invs)) == 0) {
|
|
||||||
page = stoi(&command[strlen(invs)]);
|
|
||||||
} else if (strncmp(command, invs, strlen(invs) - 1) == 0) {
|
|
||||||
page = 1;
|
|
||||||
} else {
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
|
|
||||||
printf("Your inventory (page %i):\n", page);
|
printf("Your inventory (page %i):\n", page);
|
||||||
struct pager i = {.page = page - 1, .i = -1, .is_poll = 0};
|
struct pager i = {.page = page - 1, .i = -1, .is_poll = 0};
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
|
|
||||||
// todo: polls, help commands, spacing in combos, clean init_tables
|
// todo: spacing in combos, clean init_tables
|
||||||
|
|
||||||
void init_tables(hashmap *elements, hashmap *inv, hashmap *polls, int do_inv) {
|
void init_tables(hashmap *elements, hashmap *inv, hashmap *polls, int do_inv) {
|
||||||
load_elements(elements, "../elem_data/" combo_file, 0);
|
load_elements(elements, "../elem_data/" combo_file, 0);
|
||||||
|
|
95
src/map.c
95
src/map.c
|
@ -199,67 +199,6 @@ int hashmap_set(hashmap *m, const void *key, size_t ksize, uintptr_t val,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int hashmap_get_set(hashmap *m, const void *key, size_t ksize,
|
|
||||||
uintptr_t *out_in) {
|
|
||||||
if (m->count + 1 > HASHMAP_MAX_LOAD * m->capacity) {
|
|
||||||
if (hashmap_resize(m) == -1)
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t hash = hash_data(key, ksize);
|
|
||||||
struct bucket *entry = find_entry(m, key, ksize, hash);
|
|
||||||
if (entry->key == NULL) {
|
|
||||||
m->last->next = entry;
|
|
||||||
m->last = entry;
|
|
||||||
entry->next = NULL;
|
|
||||||
|
|
||||||
++m->count;
|
|
||||||
|
|
||||||
entry->value = *out_in;
|
|
||||||
entry->key = key;
|
|
||||||
entry->ksize = ksize;
|
|
||||||
entry->hash = hash;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
*out_in = entry->value;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int hashmap_set_free(hashmap *m, const void *key, size_t ksize, uintptr_t val,
|
|
||||||
hashmap_callback c, void *usr) {
|
|
||||||
if (m->count + 1 > HASHMAP_MAX_LOAD * m->capacity) {
|
|
||||||
if (hashmap_resize(m) == -1)
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t hash = hash_data(key, ksize);
|
|
||||||
struct bucket *entry = find_entry(m, key, ksize, hash);
|
|
||||||
if (entry->key == NULL) {
|
|
||||||
m->last->next = entry;
|
|
||||||
m->last = entry;
|
|
||||||
entry->next = NULL;
|
|
||||||
|
|
||||||
++m->count;
|
|
||||||
|
|
||||||
entry->key = key;
|
|
||||||
entry->ksize = ksize;
|
|
||||||
entry->hash = hash;
|
|
||||||
entry->value = val;
|
|
||||||
// there was no overwrite, exit the function.
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
// allow the callback to free entry data.
|
|
||||||
// use old key and value so the callback can free them.
|
|
||||||
// the old key and value will be overwritten after this call.
|
|
||||||
int error = c(entry->key, ksize, entry->value, usr);
|
|
||||||
|
|
||||||
// overwrite the old key pointer in case the callback frees it.
|
|
||||||
entry->key = key;
|
|
||||||
entry->value = val;
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
int hashmap_get(hashmap *m, const void *key, size_t ksize, uintptr_t *out_val) {
|
int hashmap_get(hashmap *m, const void *key, size_t ksize, uintptr_t *out_val) {
|
||||||
uint32_t hash = hash_data(key, ksize);
|
uint32_t hash = hash_data(key, ksize);
|
||||||
struct bucket *entry = find_entry(m, key, ksize, hash);
|
struct bucket *entry = find_entry(m, key, ksize, hash);
|
||||||
|
@ -270,40 +209,6 @@ int hashmap_get(hashmap *m, const void *key, size_t ksize, uintptr_t *out_val) {
|
||||||
return entry->key != NULL ? 1 : 0;
|
return entry->key != NULL ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// doesn't "remove" the element per se, but it will be ignored.
|
|
||||||
// the element will eventually be removed when the map is resized.
|
|
||||||
void hashmap_remove(hashmap *m, const void *key, size_t ksize) {
|
|
||||||
uint32_t hash = hash_data(key, ksize);
|
|
||||||
struct bucket *entry = find_entry(m, key, ksize, hash);
|
|
||||||
|
|
||||||
if (entry->key != NULL) {
|
|
||||||
|
|
||||||
// "tombstone" entry is signified by a NULL key with a nonzero value
|
|
||||||
// element removal is optional because of the overhead of tombstone checks
|
|
||||||
entry->key = NULL;
|
|
||||||
entry->value = 0xDEAD; // I mean, it's a tombstone...
|
|
||||||
|
|
||||||
++m->tombstone_count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void hashmap_remove_free(hashmap *m, const void *key, size_t ksize,
|
|
||||||
hashmap_callback c, void *usr) {
|
|
||||||
uint32_t hash = hash_data(key, ksize);
|
|
||||||
struct bucket *entry = find_entry(m, key, ksize, hash);
|
|
||||||
|
|
||||||
if (entry->key != NULL) {
|
|
||||||
c(entry->key, entry->ksize, entry->value, usr);
|
|
||||||
|
|
||||||
// "tombstone" entry is signified by a NULL key with a nonzero value
|
|
||||||
// element removal is optional because of the overhead of tombstone checks
|
|
||||||
entry->key = NULL;
|
|
||||||
entry->value = 0xDEAD; // I mean, it's a tombstone...
|
|
||||||
|
|
||||||
++m->tombstone_count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int hashmap_size(hashmap *m) { return m->count - m->tombstone_count; }
|
int hashmap_size(hashmap *m) { return m->count - m->tombstone_count; }
|
||||||
|
|
||||||
int hashmap_iterate(hashmap *m, hashmap_callback c, void *user_ptr) {
|
int hashmap_iterate(hashmap *m, hashmap_callback c, void *user_ptr) {
|
||||||
|
|
56
src/map.h
56
src/map.h
|
@ -11,10 +11,6 @@
|
||||||
#define hashmap_str_lit(str) (str), sizeof(str) - 1
|
#define hashmap_str_lit(str) (str), sizeof(str) - 1
|
||||||
#define hashmap_static_arr(arr) (arr), sizeof(arr)
|
#define hashmap_static_arr(arr) (arr), sizeof(arr)
|
||||||
|
|
||||||
// removal of map elements is disabled by default because of its slight
|
|
||||||
// overhead. if you want to enable this feature, uncomment the line below:
|
|
||||||
// #define __HASHMAP_REMOVABLE
|
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
@ -44,69 +40,17 @@ struct hashmap {
|
||||||
struct bucket *last;
|
struct bucket *last;
|
||||||
};
|
};
|
||||||
|
|
||||||
// hashmaps can associate keys with pointer values or integral types.
|
|
||||||
typedef struct hashmap hashmap;
|
typedef struct hashmap hashmap;
|
||||||
|
|
||||||
// a callback type used for iterating over a map/freeing entries:
|
|
||||||
// `int <function name>(const void* key, size_t size, uintptr_t value, void*
|
|
||||||
// usr)` `usr` is a user pointer which can be passed through `hashmap_iterate`.
|
|
||||||
typedef int (*hashmap_callback)(const void *key, size_t ksize, uintptr_t value,
|
typedef int (*hashmap_callback)(const void *key, size_t ksize, uintptr_t value,
|
||||||
void *usr);
|
void *usr);
|
||||||
|
|
||||||
hashmap *hashmap_create(void);
|
hashmap *hashmap_create(void);
|
||||||
|
|
||||||
// only frees the hashmap object and buckets.
|
|
||||||
// does not call free on each element's `key` or `value`.
|
|
||||||
// to free data associated with an element, call `hashmap_iterate`.
|
|
||||||
void hashmap_free(hashmap *map);
|
void hashmap_free(hashmap *map);
|
||||||
|
|
||||||
// does not make a copy of `key`.
|
|
||||||
// you must copy it yourself if you want to guarantee its lifetime,
|
|
||||||
// or if you intend to call `hashmap_key_free`.
|
|
||||||
// returns -1 on error.
|
|
||||||
int hashmap_set(hashmap *map, const void *key, size_t ksize, uintptr_t value,
|
int hashmap_set(hashmap *map, const void *key, size_t ksize, uintptr_t value,
|
||||||
int free_old);
|
int free_old);
|
||||||
|
|
||||||
// adds an entry if it doesn't exist, using the value of `*out_in`.
|
|
||||||
// if it does exist, it sets value in `*out_in`, meaning the value
|
|
||||||
// of the entry will be in `*out_in` regardless of whether or not
|
|
||||||
// it existed in the first place.
|
|
||||||
// returns -1 on error.
|
|
||||||
// returns 1 if the entry already existed, returns 0 otherwise.
|
|
||||||
int hashmap_get_set(hashmap *map, const void *key, size_t ksize,
|
|
||||||
uintptr_t *out_in);
|
|
||||||
|
|
||||||
// similar to `hashmap_set()`, but when overwriting an entry,
|
|
||||||
// you'll be able properly free the old entry's data via a callback.
|
|
||||||
// unlike `hashmap_set()`, this function will overwrite the original key
|
|
||||||
// pointer, which means you can free the old key in the callback if applicable.
|
|
||||||
int hashmap_set_free(hashmap *map, const void *key, size_t ksize,
|
|
||||||
uintptr_t value, hashmap_callback c, void *usr);
|
|
||||||
|
|
||||||
int hashmap_get(hashmap *map, const void *key, size_t ksize,
|
int hashmap_get(hashmap *map, const void *key, size_t ksize,
|
||||||
uintptr_t *out_val);
|
uintptr_t *out_val);
|
||||||
|
|
||||||
#ifdef __HASHMAP_REMOVABLE
|
|
||||||
void hashmap_remove(hashmap *map, const void *key, size_t ksize);
|
|
||||||
|
|
||||||
// same as `hashmap_remove()`, but it allows you to free an entry's data first
|
|
||||||
// via a callback.
|
|
||||||
void hashmap_remove_free(hashmap *m, const void *key, size_t ksize,
|
|
||||||
hashmap_callback c, void *usr);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int hashmap_size(hashmap *map);
|
int hashmap_size(hashmap *map);
|
||||||
|
|
||||||
// iterate over the map, calling `c` on every element.
|
|
||||||
// goes through elements in the order they were added.
|
|
||||||
// the element's key, key size, value, and `usr` will be passed to `c`.
|
|
||||||
// if `c` returns -1 the iteration is aborted.
|
|
||||||
// returns the last result of `c`
|
|
||||||
int hashmap_iterate(hashmap *map, hashmap_callback c, void *usr);
|
int hashmap_iterate(hashmap *map, hashmap_callback c, void *usr);
|
||||||
|
|
||||||
// dumps bucket info for debugging.
|
|
||||||
// allows you to see how many collisions you are getting.
|
|
||||||
// `0` is an empty bucket, `1` is occupied, and `x` is removed.
|
|
||||||
// void bucket_dump(hashmap *m);
|
|
||||||
|
|
||||||
#endif // map_h
|
#endif // map_h
|
||||||
|
|
Loading…
Reference in a new issue