commit e34fc0ca7f7d0959bba5a9f6772e33e5ed620dd8 Author: ari melody Date: Fri Mar 13 02:56:29 2026 +0000 hashmapp. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c3cfdde --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +hashmap diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..dfce404 --- /dev/null +++ b/Makefile @@ -0,0 +1,7 @@ +.PHONY: hashmap + +hashmap: main.c + $(CC) -o hashmap -g main.c hashmap.c + +clean: + rm -rf hashmap diff --git a/hashmap.c b/hashmap.c new file mode 100644 index 0000000..f34ffec --- /dev/null +++ b/hashmap.c @@ -0,0 +1,61 @@ +#include "hashmap.h" +#include +#include + +void init_map(HashMap *map) { + memset(map, 0, sizeof(HashMap)); +} + +long long hash(const char *s) { + const int p = 100; + const int m = 1e9 + 9; + long p_pow = 1; + long value = 0; + const unsigned long len = strlen(s); + for (unsigned long i = 0; i < len; i++) { + unsigned char c = s[i]; + value = (value + (c - 'a' + 1) * p_pow) % m; + p_pow = (p_pow * p) % m; + } + return value; +} + +void *get(HashMap *map, char *key) { + Bucket *bucket = &map->buckets[hash(key) % HASHMAP_BUCKETS]; + Entry *entry = NULL; + + for (size_t i = 0; i < bucket->n_entries; i++) { + if (!strcmp(bucket->entries[i].key, key)) + return bucket->entries[i].data; + } + + return NULL; +} + +Entry *set(HashMap *map, char *key, void *data, size_t data_size) { + Bucket *bucket = &map->buckets[hash(key) % HASHMAP_BUCKETS]; + Entry *entry = NULL; + + size_t i = 0; + for (; i < bucket->n_entries; i++) { + entry = &bucket->entries[i]; + if (!strcmp(entry->key, key)) { + // entry exists; replace data + entry->data = data; + return entry; + } + } + + // entry doesn't exist; insert data + if (i >= BUCKET_ENTRIES) { + fprintf(stderr, "set \"%s\": bucket is full\n", key); + return NULL; + } + + entry = &bucket->entries[i]; + entry->key = strdup(key); + entry->data = data; + entry->data_size = data_size; + bucket->n_entries++; + return entry; +} diff --git a/hashmap.h b/hashmap.h new file mode 100644 index 0000000..873d66c --- /dev/null +++ b/hashmap.h @@ -0,0 +1,28 @@ +#ifndef _HASHMAP_H +#define _HASHMAP_H + +#include + +#define BUCKET_ENTRIES 20 +#define HASHMAP_BUCKETS 2048 + +typedef struct Entry { + char *key; + void *data; + size_t data_size; +} Entry; + +typedef struct Bucket { + size_t n_entries; + Entry entries[BUCKET_ENTRIES]; +} Bucket; + +typedef struct HashMap { + Bucket buckets[HASHMAP_BUCKETS]; +} HashMap; + +void init_map(HashMap *map); +void *get(HashMap *map, char *key); +Entry *set(HashMap *map, char *key, void *data, size_t data_size); + +#endif // _HASHMAP_H diff --git a/main.c b/main.c new file mode 100644 index 0000000..d49d595 --- /dev/null +++ b/main.c @@ -0,0 +1,64 @@ +#include "hashmap.h" +#include +#include +#include +#include + +#define INPUT_BUF_SIZE 1024 + +int main(int argc, char *argv[]) { + printf("hashmapp. the map to app all hashes. wait-\n" + "\":q\" to exit\n\n"); + + HashMap map; + init_map(&map); + + char running = 1; + while (running) { + printf("> "); + + char buf[INPUT_BUF_SIZE]; + if (fgets(buf, INPUT_BUF_SIZE, stdin) == NULL) { + fprintf(stderr, "failed to read stdin: %u\n", errno); + return EXIT_FAILURE; + } + size_t buf_len = strnlen(buf, INPUT_BUF_SIZE); + buf[buf_len - 1] = 0; + + if (!strcmp(buf, ":q")) + break; + + char *eq = strchr(buf, '='); + if (eq == NULL) { + void *data = get(&map, buf); + if (data == NULL) + printf("\n"); + else + printf("%s\n", (char*)data); + + continue; + } + + size_t key_len = eq - buf + 1; + char key[key_len]; + strncpy(key, buf, key_len); + key[key_len - 1] = 0; + + size_t value_len = strlen(buf + key_len); + char *value = malloc(sizeof(char) * value_len); + strncpy(value, buf + key_len, value_len); + value[value_len] = 0; + + set(&map, key, value, value_len); + } + + for (size_t bucket_i = 0; bucket_i < HASHMAP_BUCKETS; bucket_i++) { + Bucket *bucket = &map.buckets[bucket_i]; + for (size_t i = 0; i < bucket->n_entries; i++) { + free(bucket->entries[i].key); + free(bucket->entries[i].data); + } + } + + return EXIT_SUCCESS; +}