rsys

Basic data structures and low-level features
git clone git://git.meso-star.fr/rsys.git
Log | Files | Refs | README | LICENSE

commit 56f8c7a245561abeaee4f5914c733a052aa51e21
parent 2d557370b263137daf4d599a97fb23fb800dd553
Author: vaplv <vaplv@free.fr>
Date:   Sat, 29 Mar 2014 22:53:31 +0100

Add and test the binary heap data structure

Diffstat:
Mcmake/CMakeLists.txt | 1+
Asrc/binary_heap.h | 194+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/dynamic_array.h | 10++++++++++
Asrc/test_binary_heap.c | 77+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 282 insertions(+), 0 deletions(-)

diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt @@ -109,6 +109,7 @@ new_test(test_free_list rsys) new_test(test_library rsys) new_test(test_list rsys) new_test(test_mem_allocator rsys) +new_test(test_binary_heap rsys) new_test(test_ref) new_test(test_signal rsys) new_test(test_str rsys) diff --git a/src/binary_heap.h b/src/binary_heap.h @@ -0,0 +1,194 @@ +#if !defined(BHEAP_DATA) && !defined(BHEAP_NAME) +#ifndef BINARY_HEAP_H +#define BINARY_HEAP_H + +#include "rsys.h" +#include "dynamic_array.h" + +#endif /* BINARY_HEAP_H */ +#else +/* + * Generate the binary heap data type and functions with respect to the + * following macros: + * - BHEAP_NAME: prefix of the binary heap type and its functions; + * - BHEAP_DATA: type of the data registered into the binary heap; + * - BHEAP_FUNCTOR_COMPARE: comparison functor on binary heap data. Its + * profile is int (*)(const BHEAP_DATA* , const BHEAP_DATA* ). It returns + * an integer less than, equal to, or greater than zero if the first + * argument is considered to be sorted respectively before, at the same + * position, or after the second. If not defined the `<' operator is used + * to sort the BHEAP_DATA; + * - BHEAP_FUNCTOR_INIT: init functor on BHEAP_DATA. If not defined, no + * specific treatment is performed on the created data; + * - BHEAP_FUNCTOR_COPY: copy functor on DHEAP_DATA. If not defined a + * bitwise copy is used instead; + * - BHEAP_FUNCTOR_RELEASE: release functor on BHEAP_DATA. If not defined + * nothing is done on the release of an element; + * - BHEAP_FUNCTOR_COPY_AND_RELEASE: copy and release of a DHEAP_DATA. If + * not defined the copy and the release functors is used. + * + * The name of the generated type is: struct bheap_<BHEAP_NAME> + * while the generated functions are: bheap_<BHEAP_NAME>_<FUNCTION_NAME> + */ +#ifndef BHEAP_NAME + #error "Missing the BHEAP_NAME macro defining the structure name" +#endif +#ifndef BHEAP_DATA + #error "Missing the BHEAP_DATA macro defining the heap data type" +#endif + +#define DARRAY_NAME CONCAT(BHEAP_NAME, __) +#define DARRAY_DATA BHEAP_DATA +#ifdef BHEAP_FUNCTOR_INIT + #define DARRAY_FUNCTOR_INIT BHEAP_FUNCTOR_INIT +#endif +#ifdef BHEAP_FUNCTOR_COPY + #define DARRAY_FUNCTOR_COPY BHEAP_FUNCTOR_COPY +#endif +#ifdef BHEAP_FUNCTOR_RELEASE + #define DARRAY_FUNCTOR_RELEASE BHEAP_FUNCTOR_RELEASE +#endif +#ifdef BHEAP_FUNCTOR_COPY_AND_RELEASE + #define DARRAY_FUNCTOR_COPY_AND_RELEASE BHEAP_FUNCTOR_COPY_AND_RELEASE +#endif +#include "dynamic_array.h" + +/* Helper macros */ +#define BHEAP_FUNC__(Func) CONCAT(CONCAT(CONCAT(bheap_, BHEAP_NAME), _), Func) +#define BHEAP_TYPE__ CONCAT(bheap_, BHEAP_NAME) +#define BHEAP_NODES__ CONCAT(CONCAT(darray_, BHEAP_NAME), __) +#define BHEAP_NODES_FUNC__(Func) CONCAT(CONCAT(BHEAP_NODES__, _), Func) + +struct BHEAP_TYPE__ { + struct BHEAP_NODES__ nodes; +}; + +/******************************************************************************* + * Internal default functors + ******************************************************************************/ +#ifndef BHEAP_FUNCTOR_COMPARE +static FINLINE int +BHEAP_FUNC__(functor_cmp__)(const BHEAP_DATA* a, const BHEAP_DATA* b) +{ + ASSERT(a && b); + if(*a < *b) return -1; + if(*a > *b) return 1; + return 0; +} +#define BHEAP_FUNCTOR_COMPARE BHEAP_FUNC__(functor_cmp__) +#endif + +/******************************************************************************* + * Binary heap API + ******************************************************************************/ +static INLINE void +BHEAP_FUNC__(init) + (struct mem_allocator* allocator, /* May be NULL <=> use default allocator */ + struct BHEAP_TYPE__* heap) +{ + ASSERT(heap); + BHEAP_NODES_FUNC__(init)(allocator, &heap->nodes); +} + +static INLINE void +BHEAP_FUNC__(release)(struct BHEAP_TYPE__* heap) +{ + ASSERT(heap); + BHEAP_NODES_FUNC__(release)(&heap->nodes); +} + +static INLINE void +BHEAP_FUNC__(clear)(struct BHEAP_TYPE__* heap) +{ + ASSERT(heap); + BHEAP_NODES_FUNC__(clear)(&heap->nodes); +} + +static INLINE char +BHEAP_FUNC__(is_empty)(struct BHEAP_TYPE__* heap) +{ + ASSERT(heap); + return BHEAP_NODES_FUNC__(size_get)(&heap->nodes) == 0; +} + +static INLINE int +BHEAP_FUNC__(insert)(struct BHEAP_TYPE__* heap, const uint64_t value) +{ + uint64_t* nodes = NULL; + uint64_t node; + size_t inode = 0; + + ASSERT(heap); + inode = BHEAP_NODES_FUNC__(size_get)(&heap->nodes); + + node = value; + if(BHEAP_NODES_FUNC__(push_back)(&heap->nodes, &node)) + return -1; + + nodes = BHEAP_NODES_FUNC__(data_get)(&heap->nodes); + while(inode) { + const size_t iparent = (inode - 1) / 2; + if(BHEAP_FUNC__(functor_cmp__)(&nodes[iparent], &nodes[inode]) <= 0) + break; + SWAP(uint64_t, nodes[iparent], nodes[inode]); + inode = iparent; + } + return 0; +} + +static INLINE uint64_t +BHEAP_FUNC__(top)(struct BHEAP_TYPE__* heap) +{ + ASSERT(heap && !BHEAP_FUNC__(is_empty)(&heap->nodes)); + return BHEAP_NODES_FUNC__(data_get)(&heap->nodes)[0]; +} + +static INLINE uint64_t +BHEAP_FUNC__(pop)(struct BHEAP_TYPE__* heap) +{ + uint64_t* nodes = NULL; + uint64_t head = 0; + uint64_t last = 0; + size_t size = 0; + size_t inode = 0; + size_t ichild = 0; + ASSERT(heap && !BHEAP_FUNC__(is_empty)(&heap->nodes)); + + nodes = BHEAP_NODES_FUNC__(data_get)(&heap->nodes); + head = nodes[0]; + inode = BHEAP_NODES_FUNC__(size_get)(&heap->nodes) - 1; + last = nodes[inode]; + BHEAP_NODES_FUNC__(pop_back)(&heap->nodes); + if(!inode) + return head; + + nodes = BHEAP_NODES_FUNC__(data_get)(&heap->nodes); + nodes[0] = last; + size = inode; + for(inode=0, ichild=1; ichild < size; inode = ichild, ichild = 2*inode + 1) { + if(ichild + 1 < size && nodes[ichild] > nodes[ichild+1]) + ++ichild; + + if(nodes[inode] < nodes[ichild]) + break; + + SWAP(uint64_t, nodes[inode], nodes[ichild]); + inode = ichild; + } + return head; +} + +#undef BHEAP_NAME +#undef BHEAP_DATA +#undef BHEAP_FUNCTOR_COMPARE +#undef BHEAP_FUNCTOR_INIT +#undef BHEAP_FUNCTOR_COPY +#undef BHEAP_FUNCTOR_RELEASE +#undef BHEAP_FUNCTOR_COPY_AND_RELEASE +#undef BHEAP_FUNC__ +#undef BHEAP_TYPE__ +#undef BHEAP_NODES__ +#undef BHEAP_NODES_FUNC__ + +#endif /* !BHEAP_NAME || !BHEAP_DATA */ + diff --git a/src/dynamic_array.h b/src/dynamic_array.h @@ -183,6 +183,16 @@ DARRAY_FUNC__(push_back) return 0; } +static INLINE void +DARRAY_FUNC__(pop_back)(struct DARRAY_TYPE__* darray) +{ + ASSERT(darray); + if(darray->size > 0) { + const int err = DARRAY_FUNC__(resize)(darray, darray->size - 1); + ASSERT(!err); (void)err; + } +} + static INLINE size_t DARRAY_FUNC__(size_get)(const struct DARRAY_TYPE__* darray) { diff --git a/src/test_binary_heap.c b/src/test_binary_heap.c @@ -0,0 +1,77 @@ +#include "binary_heap.h" +#include "mem_allocator.h" + +#define BHEAP_NAME u64 +#define BHEAP_DATA uint64_t +#include "binary_heap.h" + +int +main(int argc, char** argv) +{ + struct mem_allocator allocator_proxy; + struct bheap_u64 heap; + uint64_t i; + (void)argc, (void)argv; + + mem_init_proxy_allocator(&allocator_proxy, &mem_default_allocator); + + bheap_u64_init(&allocator_proxy, &heap); + CHECK(bheap_u64_is_empty(&heap), 1); + bheap_u64_clear(&heap); + CHECK(bheap_u64_is_empty(&heap), 1); + + CHECK(bheap_u64_is_empty(&heap), 1); + CHECK(bheap_u64_insert(&heap, 48), 0); + CHECK(bheap_u64_insert(&heap, 51), 0); + CHECK(bheap_u64_insert(&heap, 1), 0); + CHECK(bheap_u64_insert(&heap, 7), 0); + CHECK(bheap_u64_insert(&heap, 78), 0); + CHECK(bheap_u64_insert(&heap, 4), 0); + CHECK(bheap_u64_insert(&heap, 61), 0); + CHECK(bheap_u64_insert(&heap, 72), 0); + CHECK(bheap_u64_is_empty(&heap), 0); + + CHECK(bheap_u64_top(&heap), 1); + CHECK(bheap_u64_top(&heap), 1); + CHECK(bheap_u64_pop(&heap), 1); + CHECK(bheap_u64_pop(&heap), 4); + CHECK(bheap_u64_pop(&heap), 7); + CHECK(bheap_u64_pop(&heap), 48); + + CHECK(bheap_u64_insert(&heap, 5), 0); + CHECK(bheap_u64_insert(&heap, 50), 0); + CHECK(bheap_u64_insert(&heap, 51), 0); + CHECK(bheap_u64_top(&heap), 5); + CHECK(bheap_u64_pop(&heap), 5); + CHECK(bheap_u64_pop(&heap), 50); + CHECK(bheap_u64_pop(&heap), 51); + CHECK(bheap_u64_pop(&heap), 51); + CHECK(bheap_u64_pop(&heap), 61); + CHECK(bheap_u64_pop(&heap), 72); + CHECK(bheap_u64_pop(&heap), 78);; + + CHECK(bheap_u64_is_empty(&heap), 1); + + FOR_EACH(i, 0, 17689) { + CHECK(bheap_u64_insert(&heap, (uint64_t)rand()), 0); + } + CHECK(bheap_u64_is_empty(&heap), 0); + i = bheap_u64_pop(&heap); + while(!bheap_u64_is_empty(&heap)) { + uint64_t j = bheap_u64_pop(&heap); + CHECK(j >= i, 1); + i = j; + } + + bheap_u64_release(&heap); + + if(MEM_ALLOCATED_SIZE(&allocator_proxy)) { + char dump[512]; + MEM_DUMP(&allocator_proxy, dump, sizeof(dump)/sizeof(char)); + fprintf(stderr, "%s\n", dump); + FATAL("Memory leaks\n"); + } + mem_shutdown_proxy_allocator(&allocator_proxy); + CHECK(mem_allocated_size(), 0); + return 0; +}