/** * @file Set.c */ #include "cgds/Set.h" void _set_init(Set* set, size_t dataSize, size_t hashSize, UInt (*getHash)(void*, size_t)) { set->hashSize = hashSize; set->dataSize = dataSize; set->head = safe_malloc(hashSize * sizeof(SetCell*)); for (UInt i = 0; i < hashSize; i++) set->head[i] = NULL; set->size = 0; set->getHash = getHash; //may be NULL } Set* _set_new(size_t dataSize, size_t hashSize, UInt (*getHash)(void*, size_t)) { Set* set = (Set*) safe_malloc(sizeof(Set)); _set_init(set, dataSize, hashSize, getHash); return set; } Set* set_copy(Set* set) { Set* setCopy = _set_new(set->dataSize, set->hashSize, set->getHash); setCopy->size = set->size; for (UInt i = 0; i < set->hashSize; i++) { SetCell *cell = set->head[i], *cellCopy = setCopy->head[i], *prev = NULL; while (cell != NULL) { // cellCopy == NULL (from empty list) cellCopy = (SetCell*) safe_malloc(sizeof(SetCell)); cellCopy->item = safe_malloc(set->dataSize); memcpy(cellCopy->item, cell->item, set->dataSize); if (prev == NULL) setCopy->head[i] = cellCopy; else prev->next = cellCopy; prev = cellCopy; cell = cell->next; } if (cellCopy != NULL) cellCopy->next = NULL; } return setCopy; } bool set_empty(Set* set) { return (set->size == 0); } UInt set_size(Set* set) { return set->size; } // Function (string) key --> (integer) hash [internal usage] // Default function. Can be changed (see hashtable_new()) UInt _set_compute_hash(void* key, size_t dataSize, size_t hashSize) { UInt res = 0; // Interpret the bytes in key as a piece of string unsigned char* keyStr = (unsigned char*)key; for (size_t i = 0; i < dataSize; i++) // NOTE: '31' from here https://stackoverflow.com/a/4384446 res = (*(keyStr+i) + 31 * res) % hashSize; return res; } // Get hash index from key [internal usage] UInt _set_get_hindex(Set* set, void* key) { if (set->getHash == NULL) return _set_compute_hash(key, set->dataSize, set->hashSize); return set->getHash(key, set->hashSize); } bool set_has(Set* set, void* item) { UInt hashIdx = _set_get_hindex(set, item); SetCell* cell = set->head[hashIdx]; while (cell != NULL) { if (memcmp(cell->item, item, set->dataSize) == 0) return true; cell = cell->next; } return false; } void _set_add(Set* set, void* item) { UInt hashIdx = _set_get_hindex(set, item); SetCell *cell = set->head[hashIdx], *prev = NULL; while (cell != NULL) { if (memcmp(cell->item, item, set->dataSize) == 0) // Already here: nothing to do return; prev = cell; cell = cell->next; } // New element: insert after prev (which may be NULL) SetCell* newCell = (SetCell*) safe_malloc(sizeof(SetCell)); newCell->item = safe_malloc(set->dataSize); memcpy(newCell->item, item, set->dataSize); newCell->next = NULL; if (prev == NULL) set->head[hashIdx] = newCell; else prev->next = newCell; set->size++; } void _set_delete(Set* set, void* item) { UInt hashIdx = _set_get_hindex(set, item); SetCell *cell = set->head[hashIdx], *prev = NULL; while (cell != NULL) { if (memcmp(cell->item, item, set->dataSize) == 0) { if (prev == NULL) set->head[hashIdx] = cell->next; else prev->next = cell->next; safe_free(cell->item); safe_free(cell); set->size--; break; } prev = cell; cell = cell->next; } } Vector* set_to_vector(Set* set) { Vector* v = _vector_new(set->dataSize); for (UInt i = 0; i < set->hashSize; i++) { SetCell* cell = set->head[i]; while (cell != NULL) { _vector_push(v, cell->item); cell = cell->next; } } return v; } void set_clear(Set* set) { for (UInt i = 0; i < set->hashSize; i++) { SetCell* cell = set->head[i]; while (cell != NULL) { SetCell* next = cell->next; safe_free(cell->item); safe_free(cell); cell = next; } set->head[i] = NULL; } set->size = 0; } void set_destroy(Set* set) { set_clear(set); safe_free(set->head); safe_free(set); }