From 3fc7adac10e9cb47237160f1f274dbbcf619422c Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Thu, 21 Apr 2016 12:06:26 -0400 Subject: [PATCH] ex35 bits --- lcthw-remnants-2/ex35.c | 57 +++++++ .../liblcthw/src/lcthw/radixmap.c | 140 ++++++++++++++++++ .../liblcthw/src/lcthw/radixmap.h | 35 +++++ .../liblcthw/tests/lcthw/radixmap_tests.c | 105 +++++++++++++ 4 files changed, 337 insertions(+) create mode 100644 lcthw-remnants-2/ex35.c create mode 100644 lcthw-remnants-2/liblcthw/src/lcthw/radixmap.c create mode 100644 lcthw-remnants-2/liblcthw/src/lcthw/radixmap.h create mode 100644 lcthw-remnants-2/liblcthw/tests/lcthw/radixmap_tests.c diff --git a/lcthw-remnants-2/ex35.c b/lcthw-remnants-2/ex35.c new file mode 100644 index 0000000..ae7f95b --- /dev/null +++ b/lcthw-remnants-2/ex35.c @@ -0,0 +1,57 @@ +#include + +typedef enum { + TYPE_INT, + TYPE_FLOAT, + TYPE_STRING, +} VariantType; + +struct Variant { + VariantType type; + union { + int as_integer; + float as_float; + char *as_string; + } data; +}; + +typedef struct Variant Variant; + +void Variant_print(Variant *var) +{ + switch(var->type) { + case TYPE_INT: + printf("INT: %d\n", var->data.as_integer); + break; + case TYPE_FLOAT: + printf("FLOAT: %f\n", var->data.as_float); + break; + case TYPE_STRING: + printf("STRING: %s\n", var->data.as_string); + break; + default: + printf("UNKNOWN TYPE: %d", var->type); + } +} + +int main(int argc, char *argv[]) +{ + Variant a_int = {.type = TYPE_INT, .data.as_integer = 100}; + Variant a_float = {.type = TYPE_FLOAT, .data.as_float = 100.34}; + Variant a_string = {.type = TYPE_STRING, .data.as_string = "YO DUDE!"}; + + Variant_print(&a_int); + Variant_print(&a_float); + Variant_print(&a_string); + + // here's how you access them + a_int.data.as_integer = 200; + a_float.data.as_float = 2.345; + a_string.data.as_string = "Hi there."; + + Variant_print(&a_int); + Variant_print(&a_float); + Variant_print(&a_string); + + return 0; +} diff --git a/lcthw-remnants-2/liblcthw/src/lcthw/radixmap.c b/lcthw-remnants-2/liblcthw/src/lcthw/radixmap.c new file mode 100644 index 0000000..776e5bb --- /dev/null +++ b/lcthw-remnants-2/liblcthw/src/lcthw/radixmap.c @@ -0,0 +1,140 @@ +/* + * Based on code by Andre Reinald then heavily modified by Zed A. Shaw + */ + +#include +#include +#include +#include +#include +#include + +RadixMap *RadixMap_create(size_t max) +{ + RadixMap *map = calloc(sizeof(RadixMap), 1); + check_mem(map); + + map->contents = calloc(sizeof(RMElement), max + 1); + check_mem(map->contents); + + map->temp = calloc(sizeof(RMElement), max + 1); + check_mem(map->temp); + + map->max = max; + map->end = 0; + + return map; +error: + return NULL; +} + +void RadixMap_destroy(RadixMap *map) +{ + if(map) { + free(map->contents); + free(map->temp); + free(map); + } +} + + +#define ByteOf(x,y) (((uint8_t *)x)[y]) + +static inline void radix_sort(short offset, uint64_t max, uint64_t *source, uint64_t *dest) +{ + uint64_t count[256] = {0}; + uint64_t *cp = NULL; + uint64_t *sp = NULL; + uint64_t *end = NULL; + uint64_t s = 0; + uint64_t c = 0; + + // count occurences of every byte value + for(sp = source, end = source + max; sp < end; sp++) { + count[ByteOf(sp, offset)]++; + } + + // transform count into index by summing elements and storing into same array + for(s = 0, cp = count, end = count + 256; cp < end; cp++) { + c = *cp; + *cp = s; + s += c; + } + + // fill dest with the right values in the right place + for(sp = source, end = source + max; sp < end; sp++) { + cp = count + ByteOf(sp, offset); + dest[*cp] = *sp; + ++(*cp); + } +} + +void RadixMap_sort(RadixMap *map) +{ + uint64_t *source = &map->contents[0].raw; + uint64_t *temp = &map->temp[0].raw; + + radix_sort(0, map->end, source, temp); + radix_sort(1, map->end, temp, source); + radix_sort(2, map->end, source, temp); + radix_sort(3, map->end, temp, source); +} + +RMElement *RadixMap_find(RadixMap *map, uint32_t to_find) +{ + int low = 0; + int high = map->end - 1; + RMElement *data = map->contents; + + while(low <= high) { + int middle = low + (high - low)/2; + uint32_t key = data[middle].data.key; + + if(to_find < key) { + high = middle - 1; + } else if(to_find > key) { + low = middle + 1; + } else { + return &data[middle]; + } + } + + return NULL; +} + +int RadixMap_add(RadixMap *map, uint32_t key, uint32_t value) +{ + check(key < UINT32_MAX, "Key can't be equal to UINT32_MAX."); + + RMElement element = {.data = {.key = key, .value = value}}; + check(map->end + 1 < map->max, "RadixMap is full."); + + map->contents[map->end++] = element; + + RadixMap_sort(map); + + return 0; + +error: + return -1; +} + + +int RadixMap_delete(RadixMap *map, RMElement *el) +{ + check(map->end > 0, "There is nothing to delete."); + check(el != NULL, "Can't delete a NULL element."); + + el->data.key = UINT32_MAX; + + if(map->end > 1) { + // don't bother resorting a map of 1 length + RadixMap_sort(map); + } + + map->end--; + + return 0; +error: + return -1; +} diff --git a/lcthw-remnants-2/liblcthw/src/lcthw/radixmap.h b/lcthw-remnants-2/liblcthw/src/lcthw/radixmap.h new file mode 100644 index 0000000..95ae52d --- /dev/null +++ b/lcthw-remnants-2/liblcthw/src/lcthw/radixmap.h @@ -0,0 +1,35 @@ +#ifndef lcthw_radixmap_h +#define lcthw_radixmap_h + +#include + +typedef union RMElement { + uint64_t raw; + struct { + uint32_t key; + uint32_t value; + } data; +} RMElement; + +typedef struct RadixMap { + size_t max; + size_t end; + uint32_t counter; + RMElement *contents; + RMElement *temp; +} RadixMap; + + +RadixMap *RadixMap_create(size_t max); + +void RadixMap_destroy(RadixMap *map); + +void RadixMap_sort(RadixMap *map); + +RMElement *RadixMap_find(RadixMap *map, uint32_t key); + +int RadixMap_add(RadixMap *map, uint32_t key, uint32_t value); + +int RadixMap_delete(RadixMap *map, RMElement *el); + +#endif diff --git a/lcthw-remnants-2/liblcthw/tests/lcthw/radixmap_tests.c b/lcthw-remnants-2/liblcthw/tests/lcthw/radixmap_tests.c new file mode 100644 index 0000000..9e3e6e1 --- /dev/null +++ b/lcthw-remnants-2/liblcthw/tests/lcthw/radixmap_tests.c @@ -0,0 +1,105 @@ +#include "../minunit.h" +#include +#include +#include +#include + +static int make_random(RadixMap *map) +{ + size_t i = 0; + + for(i = 0; i < map->max - 1; i++) { + uint32_t key = (uint32_t)(rand() | (rand() << 16)); + check(RadixMap_add(map, key, i) == 0, "Failed to add key %u", key); + } + + return i; + +error: + return 0; +} + +static int check_order(RadixMap *map) +{ + RMElement d1, d2; + unsigned int i = 0; + + // only signal errors if any (should not be) + for(i = 0; map->end > 0 && i < map->end-1; i++) { + d1 = map->contents[i]; + d2 = map->contents[i+1]; + + if(d1.data.key > d2.data.key) { + debug("FAIL:i=%u, key: %u, value: %u, equals max? %d\n", i, d1.data.key, d1.data.value, + d2.data.key == UINT32_MAX); + return 0; + } + } + + return 1; +} + +static int test_search(RadixMap *map) +{ + unsigned int i = 0; + RMElement *d = NULL; + RMElement *found = NULL; + + for(i = map->end / 2; i < map->end; i++) { + d = &map->contents[i]; + found = RadixMap_find(map, d->data.key); + check(found != NULL, "Didn't find %u at %u.", d->data.key, i); + check(found->data.key == d->data.key, "Got the wrong result: %p:%u looking for %u at %u", + found, found->data.key, d->data.key, i); + } + + return 1; +error: + return 0; +} + +// test for big number of elements +static char *test_operations() +{ + size_t N = 200; + + RadixMap *map = RadixMap_create(N); + mu_assert(map != NULL, "Failed to make the map."); + mu_assert(make_random(map), "Didn't make a random fake radix map."); + + RadixMap_sort(map); + mu_assert(check_order(map), "Failed to properly sort the RadixMap."); + + mu_assert(test_search(map), "Failed the search test."); + mu_assert(check_order(map), "RadixMap didn't stay sorted after search."); + + while(map->end > 0) { + RMElement *el = RadixMap_find(map, map->contents[map->end / 2].data.key); + mu_assert(el != NULL, "Should get a result."); + + size_t old_end = map->end; + + mu_assert(RadixMap_delete(map, el) == 0, "Didn't delete it."); + mu_assert(old_end - 1 == map->end, "Wrong size after delete."); + + // test that the end is now the old value, but uint32 max so it trails off + mu_assert(check_order(map), "RadixMap didn't stay sorted after delete."); + } + + RadixMap_destroy(map); + + return NULL; +} + + +char *all_tests() +{ + mu_suite_start(); + srand(time(NULL)); + + mu_run_test(test_operations); + + return NULL; +} + +RUN_TESTS(all_tests);