Started implementing a hashmap that includes tags for the all the game

objects.
This commit is contained in:
abdelrahman committed 2022-09-12 01:28:29 +01:00
1 parent 6b1197bfca
commit 20f476c4ab
7 files changed
+196 -3

No files matched your search

+3
View File
@@ -25,6 +25,8 @@ add_library(${PROJECT_NAME} SHARED
src/Game.c src/Game.c
src/Window.c src/Window.c
src/Renderer.c src/Renderer.c
src/ObjectStore.c
src/Hashmap.c
) )
target_include_directories(${PROJECT_NAME} PUBLIC target_include_directories(${PROJECT_NAME} PUBLIC
@@ -49,6 +51,7 @@ install(FILES
include/Window.h include/Window.h
include/Renderer.h include/Renderer.h
include/ObjectStore.h include/ObjectStore.h
include/Hashmap.h
CONFIGURATIONS Release CONFIGURATIONS Release
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
) )
+13
View File
@@ -0,0 +1,13 @@
#ifndef HASHMAP_H
#define HASHMAP_H
#include <stddef.h>
#include <stdint.h>
void init_hashmap();
int32_t add_object_to_map(const char *key);
int32_t get_object_index(const char *key);
void delete_object_from_map(const char *key);
void destroy_hashmap();
#endif // !HASHMAP_H
+9 -1
View File
@@ -2,12 +2,20 @@
#define OBJECT_STORE_H #define OBJECT_STORE_H
#include "Renderer.h" #include "Renderer.h"
#include "SDL_events.h"
typedef void (*EventHandlerPtr)(const SDL_Event *event, void *object);
typedef void (*UpdateFuncPtr)(float delta, void *object); typedef void (*UpdateFuncPtr)(float delta, void *object);
typedef void (*RenderFuncPtr)(Renderer *renderer, void *object); typedef void (*RenderFuncPtr)(Renderer *renderer, void *object);
typedef struct object_store ObjectStore; typedef struct object_store ObjectStore;
void add_object_to_store(ObjectStore *os, UpdateFuncPtr uf, RenderFuncPtr rf); void add_object_to_store(ObjectStore *os, const char *object_tag,
EventHandlerPtr eh, UpdateFuncPtr uf,
RenderFuncPtr rf);
void handle_all_object_events(ObjectStore *os);
void update_all_objects(ObjectStore *os);
void render_all_objects(ObjectStore *os);
void remove_object_from_store(ObjectStore *os, const char *object_tag);
#endif // !OBJECT_STORE_H #endif // !OBJECT_STORE_H
+4
View File
@@ -3,4 +3,8 @@
#define INTERNAL static #define INTERNAL static
#define MAX_OBJ_COUNT 10000
#define HASH_PRIME_01 1987
#define HASH_PRIME_02 7919
#endif // !CONSTANTS_H #endif // !CONSTANTS_H
+164
View File
@@ -0,0 +1,164 @@
#include "Hashmap.h"
#include "constants.h"
#include "engine_build_config.h"
#include <math.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#ifdef DEBUG_ENGINE
#include <stdio.h>
#endif /* DEBUG_ENGINE */
INTERNAL struct objects_hashmap {
size_t count;
char *keys[MAX_OBJ_COUNT];
int32_t active_indices[MAX_OBJ_COUNT];
} map = {};
void init_hashmap() {
// Technically, memset shouldn't be used to set the values of any thing other
// than byte arrays, but since it works in certain cases (e.g. 0 and -1) and
// it is faster than doing a for loop, I am using it here to initialise the
// active_indices array to -1
memset(map.active_indices, -1, sizeof(map.active_indices));
}
size_t hash_key(const char *key) {
size_t i = 0;
for (size_t j = 0; key[j]; ++j) {
i += (size_t)key[j] * HASH_PRIME_01 % MAX_OBJ_COUNT;
}
i = (i * HASH_PRIME_02) % MAX_OBJ_COUNT;
return i;
}
int32_t add_object_to_map(const char *key) {
if (map.count + 1 == MAX_OBJ_COUNT) {
#ifdef DEBUG_ENGINE
printf("Map full\n");
#endif /* DEBUG_ENGINE */
return -1;
}
size_t index = hash_key(key);
if (map.keys[index]) {
if (strcmp(map.keys[index], key) == 0) {
#ifdef DEBUG_ENGINE
printf("Key \"%s\" already exists\n", key);
#endif /* DEBUG_ENGINE */
} else {
// TODO (Abdelrahman): Implement a way to resolve collisions between
// multiple keys
#ifdef DEBUG_ENGINE
printf("Collision detected. Key \"%s\" collides with key \"%s\"\n", key,
map.keys[index]);
#endif /* DEBUG_ENGINE */
}
return -1;
}
map.keys[index] = malloc(strlen(key) + 1);
strcpy(map.keys[index], key);
map.active_indices[map.count] = index;
map.count += 1;
return index;
}
int32_t get_object_index(const char *key) {
if (map.count == 0) {
#ifdef DEBUG_ENGINE
printf("Key \"%s\" doesn't exist\n", key);
#endif /* DEBUG_ENGINE */
return -1;
}
size_t index = hash_key(key);
if (!(map.keys[index]) || strcmp(map.keys[index], key) != 0) {
#ifdef DEBUG_ENGINE
printf("Key \"%s\" doesn't exist\n", key);
#endif /* DEBUG_ENGINE */
return -1;
}
return (int32_t)index;
}
void delete_object_from_map(const char *key) {
if (map.count == 0) {
#ifdef DEBUG_ENGINE
printf("Key \"%s\" doesn't exist\n", key);
#endif /* DEBUG_ENGINE */
return;
}
size_t index = hash_key(key);
if (!(map.keys[index]) || strcmp(map.keys[index], key) != 0) {
#ifdef DEBUG_ENGINE
printf("Key \"%s\" doesn't exist\n", key);
#endif /* DEBUG_ENGINE */
return;
}
free(map.keys[index]);
map.keys[index] = NULL;
size_t packing_start_index = 0;
for (size_t i = 0; i < map.count; ++i) {
if (map.active_indices[i] == index) {
map.active_indices[i] = -1;
packing_start_index = i;
break;
}
}
// Make sure the indices are packed in the array
for (; packing_start_index < map.count; ++packing_start_index) {
if (packing_start_index + 1 == MAX_OBJ_COUNT) {
// Make sure we don't go out of bounds if we are at the last item
map.active_indices[packing_start_index] = -1;
continue;
}
map.active_indices[packing_start_index] =
map.active_indices[packing_start_index + 1];
}
map.count -= 1;
}
void destroy_hashmap() {
for (size_t i = 0; i < map.count; ++i) {
size_t index = map.active_indices[i];
if (index == -1) {
continue;
}
free(map.keys[index]);
map.keys[index] = NULL;
}
map.count = 0;
// Technically, memset shouldn't be used to set the values of any thing other
// than byte arrays, but since it works in certain cases (e.g. 0 and -1) and
// it is faster than doing a for loop, I am using it here to initialise the
// active_indices array to -1
memset(map.active_indices, -1, sizeof(map.active_indices));
}
+1
View File
@@ -0,0 +1 @@
#include "ObjectStore.h"
+2 -2
View File
@@ -9,9 +9,9 @@
#include <stdio.h> #include <stdio.h>
#endif /* DEBUG_ENGINE */ #endif /* DEBUG_ENGINE */
typedef struct renderer { struct renderer {
SDL_Renderer *SDL_base_renderer; SDL_Renderer *SDL_base_renderer;
} Renderer; };
Renderer *create_renderer() { return (Renderer *)malloc(sizeof(Renderer)); } Renderer *create_renderer() { return (Renderer *)malloc(sizeof(Renderer)); }