*.o
/src/obj/*.so
+/test/main.c
/test/test
/test/vgcore.*
/doc/html/
void _hashtable_set(HashTable* hashTable, char* key, void* data)
{
UInt hashIdx = _compute_hash(key, hashTable->hashSize);
- HashCell
- *cell = hashTable->head[hashIdx],
- *prev = NULL;
+ HashCell *cell = hashTable->head[hashIdx],
+ *prev = NULL;
while (cell != NULL)
{
if (strcmp(cell->key, key) == 0)
void hashtable_delete(HashTable* hashTable, char* key)
{
UInt hashIdx = _compute_hash(key, hashTable->hashSize);
- HashCell
- *cell = hashTable->head[hashIdx],
- *prev = NULL;
+ HashCell *cell = hashTable->head[hashIdx],
+ *prev = NULL;
while (cell != NULL)
{
if (strcmp(cell->key, key) == 0)
* @param key Key of the element to retrieve..
* @param data 'out' variable (ptr) to contain the result.
*
- * Usage: void hashtable_get(HashTable* hashTable, char* key, void data)
+ * Usage: void hashtable_get(HashTable* hashTable, char* key, void* data)
*/
#define hashtable_get(hashTable, key, data) \
{ \
/**
* @brief Remove the given key (+ associated value).
+ *
+ * Usage: void hashtable_delete(HashTable* hashTable, char* key)
*/
void hashtable_delete(
HashTable* hashTable, ///< "this" pointer.
--- /dev/null
+/**
+ * @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);
+}
--- /dev/null
+/**
+ * @file Set.h
+ */
+
+#ifndef CGDS_SET_H
+#define CGDS_SET_H
+
+#include <stdlib.h>
+#include <string.h>
+#include "cgds/safe_alloc.h"
+#include "cgds/types.h"
+#include "cgds/Vector.h"
+
+/**
+ * @brief Cell of a set.
+ */
+typedef struct SetCell {
+ void* item; ///< Generic data (key) contained in this cell.
+ struct SetCell* next; ///< Pointer to next cell in the list.
+} SetCell;
+
+/**
+ * @brief Generic set containing any data (of same size).
+ */
+typedef struct Set {
+ UInt size; ///< Count elements in the set.
+ size_t dataSize; ///< Size of a set cell element in bytes.
+ size_t hashSize; ///< (Maximum) Number of stored hash keys.
+ SetCell** head; ///< Pointers to the first cell in a list.
+ UInt (*getHash)(void*, size_t); ///< Custom hash function (optional)
+} Set;
+
+/**
+ * @brief Initialize an empty set.
+ */
+void _set_init(
+ Set* set, ///< "this" pointer.
+ size_t dataSize, ///< Size in bytes of a set element.
+ size_t hashSize, ///< (Maximum) Number of stored hash keys.
+ UInt (*getHash)(void*, size_t); ///< Custom hash function (optional)
+);
+
+/**
+ * @brief Return an allocated and initialized set.
+ */
+Set* _set_new(
+ size_t dataSize, ///< Size in bytes of a set element.
+ size_t hashSize, ///< (Maximum) Number of stored hash keys.
+ UInt (*getHash)(void*, size_t) ///< Custom hash function (nullable)
+);
+
+/**
+ * @brief Return an allocated and initialized set.
+ * @param type Type of a set element (int, char*, ...).
+ * @param hsize Size of the internal pointers array.
+ * @param getHash Custom hash function (nullable)
+ *
+ * Usage: Set* set_new(<Type> type, UInt hash_size, UInt (*getHash)(void*, size_t))
+ */
+#define set_new(type, hsize, getHash) \
+ _set_new(sizeof(type), hsize, getHash)
+
+/**
+ * @brief Copy constructor (shallow copy, ok for basic types).
+ */
+Set* set_copy(
+ Set* set ///< "this" pointer.
+);
+
+/**
+ * @brief Check if the set is empty.
+ */
+bool set_empty(
+ Set* set ///< "this" pointer.
+);
+
+/**
+ * @brief Return current size.
+ */
+UInt set_size(
+ Set* set ///< "this" pointer.
+);
+
+/**
+ * @brief Lookup given element.
+ *
+ * Usage: bool set_has(Set* set, void* item)
+ */
+bool set_has(
+ Set* set, ///< "this" pointer.
+ void* item ///< Element to search.
+);
+
+/**
+ * @brief Add an item to the set.
+ */
+void _set_add(
+ Set* set, ///< "this" pointer.
+ void* item ///< Element to add.
+);
+
+/**
+ * @brief Add a key to the set.
+ * @param set "this" pointer.
+ * @param item Element to add.
+ *
+ * Usage: void set_add(Set* set, void item)
+ */
+#define set_add(set, item) \
+{ \
+ typeof(item) tmp = item; \
+ _set_add(set, &tmp); \
+}
+
+/**
+ * @brief Remove the given item.
+ */
+void _set_delete(
+ Set* set, ///< "this" pointer.
+ void* item ///< Element to delete.
+);
+
+/**
+ * @brief Remove the given item.
+ * @param item Element to remove.
+ *
+ * Usage: void set_delete(Set* set, void item)
+ */
+#define set_delete(set, item) \
+{ \
+ typeof(item) tmp = item; \
+ _set_delete(set, &tmp); \
+}
+
+/**
+ * @brief Initialize a vector with (pointers to) set elements.
+ */
+Vector* set_to_vector(
+ Set* set ///< "this" pointer.
+);
+
+/**
+ * @brief Clear the entire set.
+ */
+void set_clear(
+ Set* set ///< "this" pointer.
+);
+
+/**
+ * @brief Destroy the set: clear it, and free hashes array.
+ */
+void set_destroy(
+ Set* set ///< "this" pointer.
+);
+
+#endif
t_heap_push_pop_evolved();
t_heap_copy();
+ //file ./t.Set.c :
+ t_set_clear();
+ t_set_size();
+ t_set_add_remove_basic();
+ t_set_getnull_modify();
+ t_set_copy();
+ t_set_tovect();
+
//file ./t.List.c :
t_list_clear();
t_list_size();
ckValue += 1.0;
}
- //Remove keys / values
+ // Remove keys / values
for (int i = 0; i < n; i++)
{
key[3] = (char)(48 + i);
}
for (int i = 0; i < n; i++)
{
- //another way to access elements
+ // Another way to access elements
key[3] = (char)(48 + i);
StructTest1* st1Cell;
hashtable_get(h, key, st1Cell);
--- /dev/null
+#include <stdlib.h>
+#include "cgds/Set.h"
+#include "helpers.h"
+#include "lut.h"
+
+UInt getHash_int(void* item, size_t hashSize) {
+ return *((int*)item) % hashSize;
+}
+
+void t_set_clear()
+{
+ Set* s = set_new(int, 16, getHash_int);
+ lu_assert(set_empty(s));
+
+ set_add(s, 0);
+ set_add(s, 1);
+ set_add(s, 2);
+
+ set_destroy(s);
+ s = set_new(int, 8, getHash_int);
+
+ set_add(s, 1);
+ set_add(s, 2);
+ set_add(s, 3);
+
+ set_clear(s);
+ lu_assert(set_empty(s));
+
+ set_destroy(s);
+}
+
+void t_set_size()
+{
+ Set* s = set_new(int, 16, getHash_int);
+ lu_assert(set_empty(s));
+
+ set_add(s, 0);
+ set_add(s, 1);
+ set_add(s, 2);
+ lu_assert_int_eq(set_size(s), 3);
+
+ set_add(s, 3);
+ set_add(s, 4);
+ lu_assert_int_eq(set_size(s), 5);
+
+ set_add(s, 5);
+ set_add(s, 6);
+ set_add(s, 7);
+ lu_assert_int_eq(set_size(s), 8);
+
+ set_destroy(s);
+}
+
+void t_set_add_remove_basic()
+{
+ int n = 10;
+
+ Set* s = set_new(double, 4, NULL);
+ for (double i = 0.0; i < n; i++)
+ set_add(s, i);
+ lu_assert_int_eq(set_size(s), n);
+
+ // Check values
+ for (double i = 0.0; i < n; i++)
+ lu_assert(set_has(s, &i));
+
+ // Remove items
+ for (double i = 0.0; i < n; i++)
+ set_delete(s, i);
+ lu_assert_int_eq(set_size(s), 0);
+
+ set_destroy(s);
+}
+
+void t_set_getnull_modify()
+{
+ int n = 10;
+
+ Set* s = set_new(StructTest1, 4, NULL);
+ // NOTE: using calloc() because probably StructTest1 is 4 + 8 bytes,
+ // aligned to 8 + 8 ==> 4 are left uninitialized ==> memcpy compares
+ // some junk values. TODO: custom equality function instead.
+ StructTest1* st1 = (StructTest1*) calloc(n , sizeof(StructTest1));
+ for (int i = 0; i < n; i++)
+ {
+ st1[i].a = random() % 42;
+ st1[i].b = (double) random() / RAND_MAX;
+ set_add(s, *(st1 + i));
+ }
+ for (int i = 0; i < n; i++)
+ {
+ // Another way to access elements
+ StructTest1* st1Cell = (StructTest1*) calloc(1, sizeof(StructTest1));
+ st1Cell->a = st1[7].a;
+ st1Cell->b = st1[7].b;
+ lu_assert(set_has(s, st1Cell));
+ free(st1Cell);
+ }
+
+ // has / has not:
+ StructTest1* stmp = (StructTest1*) calloc(1, sizeof(StructTest1));
+ stmp->a = 51;
+ stmp->b = 2.0;
+ lu_assert(!set_has(s, stmp));
+ free(stmp);
+ lu_assert(set_has(s, st1 + 4));
+ free(st1);
+
+ set_destroy(s);
+}
+
+void t_set_copy()
+{
+ int n = 10;
+
+ Set* s = set_new(int, 8, getHash_int);
+ for (int i = 0; i < n; i++)
+ set_add(s, i + 1);
+ Set* sc = set_copy(s);
+
+ lu_assert_int_eq(s->size, sc->size);
+ int *a, *b;
+ for (int i = 0; i < n; i++) {
+ int item = i + 1;
+ lu_assert(set_has(sc, &item));
+ }
+ set_destroy(s);
+ set_destroy(sc);
+}
+
+void t_set_tovect()
+{
+ int n = 10;
+
+ Set* s = set_new(int, 8, getHash_int);
+ for (int i = 0; i < n; i++)
+ set_add(s, i);
+
+ Vector* v = set_to_vector(s);
+ lu_assert(vector_size(v) == set_size(s));
+ vector_destroy(v);
+ set_destroy(s);
+}
vectorI_move_next(vi);
}
- // same, from end to beginning
+ // Same, from end to beginning
ckValue = n - 1;
vectorI_reset_end(vi);
while (vectorI_has_data(vi))
}
for (int i = 0; i < n; i++)
{
- //another way to access elements
+ // Another way to access elements
StructTest1 st1Cell;
vector_get(v, i, st1Cell);
lu_assert_int_eq(st1Cell.a, st1[i].a);