/* * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * ----------------------------------------------------------------------------- * File: HashTable.c * Description: * This file contains the functions for modifying the Hash Table. It includes functions * to get, Insert, Remove, check if has key and check if empty. * * Author: Mineplay * ----------------------------------------------------------------------------- */ #include "../../Include/Fledasty/Core/HashTable.h" #include #include #include static const int FLEDASTY_HASH_TABLE_SIZE_THRESHOLD = 75; FledastyError fledasty_hash_table_initialize(FledastyHashTable *new_hash_table, const size_t key_byte_size, const size_t value_byte_size, size_t (*hash_function)(const void *key)) { if (new_hash_table == NULL || hash_function == NULL) { return FLEDASTY_ERROR_INVALID_POINTER; } new_hash_table->key_byte_size = key_byte_size; new_hash_table->value_byte_size = value_byte_size; new_hash_table->hash_function = hash_function; new_hash_table->size = 0; new_hash_table->capacity = 1024; new_hash_table->Table = (FledastyDynamicArray*)hallocy_calloc(sizeof(FledastyDynamicArray), new_hash_table->capacity); if (new_hash_table->Table == NULL) { return FLEDASTY_ERROR_FAILED_ALLOCATION; } return FLEDASTY_ERROR_NONE; } FledastyError fledasty_hash_table_destroy(FledastyHashTable *current_hash_table) { if (current_hash_table == NULL) { return FLEDASTY_ERROR_INVALID_POINTER; } for (size_t i = 0; i < current_hash_table->capacity; i += 1) { FledastyError result = fledasty_dynamic_array_destroy(¤t_hash_table->Table[i]); if (result != FLEDASTY_ERROR_NONE) { return result; } } if (hallocy_free(current_hash_table->Table) != HALLOCY_ERROR_NONE) { return FLEDASTY_ERROR_FAILED_ALLOCATION; } return FLEDASTY_ERROR_NONE; } FledastyError fledasty_hash_table_insert(FledastyHashTable *current_hash_table, void *key, void *value) { if (current_hash_table == NULL || key == NULL || value == NULL) { return FLEDASTY_ERROR_INVALID_POINTER; } current_hash_table->size += 1; if (current_hash_table->size >= (current_hash_table->capacity * FLEDASTY_HASH_TABLE_SIZE_THRESHOLD) / 100) { const size_t old_capacity = current_hash_table->capacity; FledastyDynamicArray *previous_table = current_hash_table->Table; current_hash_table->capacity += current_hash_table->capacity; current_hash_table->Table = (FledastyDynamicArray*)hallocy_calloc(sizeof(FledastyDynamicArray), current_hash_table->capacity); if (current_hash_table->Table == NULL) { return FLEDASTY_ERROR_FAILED_ALLOCATION; } for (size_t index = 0; index < old_capacity; index += 1) { FledastyDynamicArray *current_dynamic_array = previous_table + index; if (current_dynamic_array->buffer != NULL) { for (size_t list_index = 0; list_index < current_dynamic_array->size; list_index += 1) { FledastyHashTablePair *pair = (FledastyHashTablePair*)fledasty_dynamic_array_get(current_dynamic_array, list_index); const size_t key_index = current_hash_table->hash_function(pair->key) % current_hash_table->capacity; if (current_hash_table->Table[key_index].buffer == NULL) { FledastyError result = fledasty_dynamic_array_initialize(current_hash_table->Table + key_index, NULL, 0, sizeof(FledastyHashTablePair)); if (result != FLEDASTY_ERROR_NONE) { return result; } } fledasty_dynamic_array_append(current_hash_table->Table + key_index, pair); } fledasty_dynamic_array_destroy(current_dynamic_array); } } hallocy_free(previous_table); } const size_t index = current_hash_table->hash_function(key) % current_hash_table->capacity; if (current_hash_table->Table[index].buffer == NULL) { FledastyError result = fledasty_dynamic_array_initialize(¤t_hash_table->Table[index], NULL, 0, sizeof(FledastyHashTablePair)); if (result != FLEDASTY_ERROR_NONE) { return result; } } FledastyHashTablePair pair; pair.key = hallocy_malloc(current_hash_table->key_byte_size); if (pair.key == NULL) { return FLEDASTY_ERROR_FAILED_ALLOCATION; } hallocy_copy_memory(pair.key, key, current_hash_table->key_byte_size); pair.value = hallocy_malloc(current_hash_table->value_byte_size); if (pair.value == NULL) { return FLEDASTY_ERROR_FAILED_ALLOCATION; } hallocy_copy_memory(pair.value, value, current_hash_table->value_byte_size); fledasty_dynamic_array_append(¤t_hash_table->Table[index], &pair); return FLEDASTY_ERROR_NONE; } void *fledasty_hash_table_get(const FledastyHashTable *current_hash_table, void *key) { if (current_hash_table == NULL || key == NULL) { return NULL; } const size_t index = current_hash_table->hash_function(key) % current_hash_table->capacity; if (current_hash_table->Table[index].buffer == NULL) { return NULL; } size_t list_index = 0; while (list_index < current_hash_table->Table[index].size) { const FledastyHashTablePair *value = (FledastyHashTablePair*)fledasty_dynamic_array_get(¤t_hash_table->Table[index], list_index); if (hallocy_compare_memory(value->key, key, current_hash_table->key_byte_size)) { return value->value; } list_index += 1; } return NULL; } FledastyError fledasty_hash_table_remove(FledastyHashTable *current_hash_table, void *key) { if (current_hash_table == NULL || key == NULL) { return FLEDASTY_ERROR_INVALID_POINTER; } const size_t index = current_hash_table->hash_function(key) % current_hash_table->capacity; if (current_hash_table->Table[index].buffer == NULL) { return FLEDASTY_ERROR_KEY_NOT_FOUND; } size_t list_index = 0; while (list_index < current_hash_table->Table[index].size) { FledastyHashTablePair *value = (FledastyHashTablePair*)fledasty_dynamic_array_get(¤t_hash_table->Table[index], list_index); if (hallocy_compare_memory(value->key, key, current_hash_table->key_byte_size)) { if (hallocy_free(value->key) != HALLOCY_ERROR_NONE) { return FLEDASTY_ERROR_FAILED_ALLOCATION; } if (hallocy_free(value->value) != HALLOCY_ERROR_NONE) { return FLEDASTY_ERROR_FAILED_ALLOCATION; } fledasty_dynamic_array_remove_at_index(¤t_hash_table->Table[index], list_index); current_hash_table->size -= 1; return FLEDASTY_ERROR_NONE; } list_index += 1; } return FLEDASTY_ERROR_KEY_NOT_FOUND; } FledastyError fledasty_hash_table_clear(FledastyHashTable *current_hash_table) { if (current_hash_table == NULL) { return FLEDASTY_ERROR_INVALID_POINTER; } for (size_t index = 0; index < current_hash_table->capacity; index += 1) { if (current_hash_table->Table[index].buffer != NULL) { FledastyError result = fledasty_dynamic_array_destroy(¤t_hash_table->Table[index]); if (result != FLEDASTY_ERROR_NONE) { return result; } } } current_hash_table->size = 0; return FLEDASTY_ERROR_NONE; } bool fledasty_hash_table_has_key(const FledastyHashTable *current_hash_table, void *key) { if (current_hash_table == NULL || key == NULL) { return false; } const size_t index = current_hash_table->hash_function(key) % current_hash_table->capacity; if (current_hash_table->Table[index].buffer == NULL) { return false; } size_t list_index = 0; while (list_index < current_hash_table->Table[index].size) { const FledastyHashTablePair *value = (FledastyHashTablePair*)fledasty_dynamic_array_get(¤t_hash_table->Table[index], list_index); if (hallocy_compare_memory(value->key, key, current_hash_table->key_byte_size)) { return true; } list_index += 1; } return false; }