Looks good, In heap_raw_insert() why not use x2nrealloc() instead of xrealloc()?
I didn't read the testing code closely, but I have two minor questions: 1) You've ifdef'd out some code. Any reason not to simply delete it? 2) You've implemented print_heap() without using it. I suppose that's for debugging purposes? Ethan On Fri, Jan 13, 2012 at 16:43, Ben Pfaff <b...@nicira.com> wrote: > Signed-off-by: Ben Pfaff <b...@nicira.com> > --- > lib/automake.mk | 4 +- > lib/heap.c | 216 ++++++++++++++++++++++ > lib/heap.h | 163 +++++++++++++++++ > tests/.gitignore | 1 + > tests/automake.mk | 7 + > tests/heap.at | 13 ++ > tests/test-heap.c | 504 > ++++++++++++++++++++++++++++++++++++++++++++++++++++ > tests/testsuite.at | 3 +- > 8 files changed, 909 insertions(+), 2 deletions(-) > create mode 100644 lib/heap.c > create mode 100644 lib/heap.h > create mode 100644 tests/heap.at > create mode 100644 tests/test-heap.c > > diff --git a/lib/automake.mk b/lib/automake.mk > index 4e2fcf3..3531ba9 100644 > --- a/lib/automake.mk > +++ b/lib/automake.mk > @@ -1,4 +1,4 @@ > -# Copyright (C) 2009, 2010, 2011 Nicira Networks, Inc. > +# Copyright (C) 2009, 2010, 2011, 2012 Nicira Networks, Inc. > # > # Copying and distribution of this file, with or without modification, > # are permitted in any medium without royalty provided the copyright > @@ -45,6 +45,8 @@ lib_libopenvswitch_a_SOURCES = \ > lib/dpif-provider.h \ > lib/dpif.c \ > lib/dpif.h \ > + lib/heap.c \ > + lib/heap.h \ > lib/dynamic-string.c \ > lib/dynamic-string.h \ > lib/entropy.c \ > diff --git a/lib/heap.c b/lib/heap.c > new file mode 100644 > index 0000000..77b7955 > --- /dev/null > +++ b/lib/heap.c > @@ -0,0 +1,216 @@ > +/* > + * Copyright (c) 2012 Nicira Networks. > + * > + * 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. > + */ > + > +#include <config.h> > +#include "heap.h" > +#include <stdlib.h> > +#include "util.h" > + > +static void put_node(struct heap *, struct heap_node *, size_t i); > +static void swap_nodes(struct heap *, size_t i, size_t j); > +static bool float_up(struct heap *, size_t i); > +static void float_down(struct heap *, size_t i); > +static void float_up_or_down(struct heap *, size_t i); > + > +/* Initializes 'heap' as an empty heap. */ > +void > +heap_init(struct heap *heap) > +{ > + heap->array = NULL; > + heap->n = 0; > + heap->allocated = 0; > +} > + > +/* Frees memory owned internally by 'heap'. The caller is responsible for > + * freeing 'heap' itself, if necessary. */ > +void > +heap_destroy(struct heap *heap) > +{ > + if (heap) { > + free(heap->array); > + } > +} > + > +/* Removes all of the elements from 'heap', without freeing any allocated > + * memory. */ > +void > +heap_clear(struct heap *heap) > +{ > + heap->n = 0; > +} > + > +/* Exchanges the contents of 'a' and 'b'. */ > +void > +heap_swap(struct heap *a, struct heap *b) > +{ > + struct heap tmp = *a; > + *a = *b; > + *b = tmp; > +} > + > +/* Inserts 'node' into 'heap' with the specified 'priority'. > + * > + * This takes time O(lg n). */ > +void > +heap_insert(struct heap *heap, struct heap_node *node, uint32_t priority) > +{ > + heap_raw_insert(heap, node, priority); > + float_up(heap, node->idx); > +} > + > +/* Removes 'node' from 'heap'. > + * > + * This takes time O(lg n). */ > +void > +heap_remove(struct heap *heap, struct heap_node *node) > +{ > + size_t i = node->idx; > + > + heap_raw_remove(heap, node); > + if (i <= heap->n) { > + float_up_or_down(heap, i); > + } > +} > + > +/* Changes the priority of 'node' (which must be in 'heap') to 'priority'. > + * > + * This takes time O(lg n). */ > +void > +heap_change(struct heap *heap, struct heap_node *node, uint32_t priority) > +{ > + heap_raw_change(node, priority); > + float_up_or_down(heap, node->idx); > +} > + > +/* Inserts 'node' into 'heap' with the specified 'priority', without > + * maintaining the heap invariant. > + * > + * After this call, heap_max() will no longer necessarily return the maximum > + * value in the heap, and HEAP_FOR_EACH will no longer necessarily iterate in > + * heap level order, until the next call to heap_rebuild(heap). > + * > + * This takes time O(1). */ > +void > +heap_raw_insert(struct heap *heap, struct heap_node *node, uint32_t priority) > +{ > + if (heap->n >= heap->allocated) { > + heap->allocated = heap->n == 0 ? 1 : 2 * heap->n; > + heap->array = xrealloc(heap->array, > + (heap->allocated + 1) * sizeof *heap->array); > + } > + > + put_node(heap, node, ++heap->n); > + node->priority = priority; > +} > + > +/* Removes 'node' from 'heap', without maintaining the heap invariant. > + * > + * After this call, heap_max() will no longer necessarily return the maximum > + * value in the heap, and HEAP_FOR_EACH will no longer necessarily iterate in > + * heap level order, until the next call to heap_rebuild(heap). > + * > + * This takes time O(1). */ > +void > +heap_raw_remove(struct heap *heap, struct heap_node *node) > +{ > + size_t i = node->idx; > + if (i < heap->n) { > + put_node(heap, heap->array[heap->n], i); > + } > + heap->n--; > +} > + > +/* Rebuilds 'heap' to restore the heap invariant following a series of one or > + * more calls to heap_raw_*() functions. (Otherwise this function need not > be > + * called.) > + * > + * This takes time O(n) in the current size of the heap. */ > +void > +heap_rebuild(struct heap *heap) > +{ > + size_t i; > + > + for (i = heap->n / 2; i >= 1; i--) { > + float_down(heap, i); > + } > +} > + > +static void > +put_node(struct heap *heap, struct heap_node *node, size_t i) > +{ > + heap->array[i] = node; > + node->idx = i; > +} > + > +static void > +swap_nodes(struct heap *heap, size_t i, size_t j) > +{ > + struct heap_node *old_i = heap->array[i]; > + struct heap_node *old_j = heap->array[j]; > + > + put_node(heap, old_j, i); > + put_node(heap, old_i, j); > +} > + > +static bool > +float_up(struct heap *heap, size_t i) > +{ > + bool moved = false; > + size_t parent; > + > + for (; i > 1; i = parent) { > + parent = heap_parent__(i); > + if (heap->array[parent]->priority >= heap->array[i]->priority) { > + break; > + } > + swap_nodes(heap, parent, i); > + moved = true; > + } > + return moved; > +} > + > +static void > +float_down(struct heap *heap, size_t i) > +{ > + while (!heap_is_leaf__(heap, i)) { > + size_t left = heap_left__(i); > + size_t right = heap_right__(i); > + size_t max = i; > + > + if (heap->array[left]->priority > heap->array[max]->priority) { > + max = left; > + } > + if (right <= heap->n > + && heap->array[right]->priority > heap->array[max]->priority) { > + max = right; > + } > + if (max == i) { > + break; > + } > + > + swap_nodes(heap, max, i); > + i = max; > + } > +} > + > +static void > +float_up_or_down(struct heap *heap, size_t i) > +{ > + if (!float_up(heap, i)) { > + float_down(heap, i); > + } > +} > + > diff --git a/lib/heap.h b/lib/heap.h > new file mode 100644 > index 0000000..8cfcf70 > --- /dev/null > +++ b/lib/heap.h > @@ -0,0 +1,163 @@ > +/* > + * Copyright (c) 2012 Nicira Networks. > + * > + * 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. > + */ > + > +#ifndef HEAP_H > +#define HEAP_H 1 > + > +#include <stdbool.h> > +#include <stddef.h> > +#include <stdint.h> > + > +/* A heap node, to be embedded inside the data structure in the heap. */ > +struct heap_node { > + size_t idx; > + uint32_t priority; > +}; > + > +/* A max-heap. */ > +struct heap { > + struct heap_node **array; /* Data in elements 1...n, element 0 unused. > */ > + size_t n; /* Number of nodes currently in the heap. */ > + size_t allocated; /* Max 'n' before 'array' must be enlarged. > */ > +}; > + > +/* Initialization. */ > +void heap_init(struct heap *); > +void heap_destroy(struct heap *); > +void heap_clear(struct heap *); > +void heap_swap(struct heap *a, struct heap *b); > +static inline size_t heap_count(const struct heap *); > +static inline bool heap_is_empty(const struct heap *); > + > +/* Insertion and deletion. */ > +void heap_insert(struct heap *, struct heap_node *, uint32_t priority); > +void heap_change(struct heap *, struct heap_node *, uint32_t priority); > +void heap_remove(struct heap *, struct heap_node *); > +static inline struct heap_node *heap_pop(struct heap *); > + > +/* Maximum. */ > +static inline struct heap_node *heap_max(const struct heap *); > + > +/* The "raw" functions below do not preserve the heap invariants. After you > + * call them, heap_max() will not necessarily return the right value until > you > + * subsequently call heap_rebuild(). */ > +void heap_raw_insert(struct heap *, struct heap_node *, uint32_t priority); > +static inline void heap_raw_change(struct heap_node *, uint32_t priority); > +void heap_raw_remove(struct heap *, struct heap_node *); > +void heap_rebuild(struct heap *); > + > +/* Iterates through each NODE in HEAP, where NODE->MEMBER must be a "struct > + * heap_node". Iterates in heap level order, which in particular means that > + * the first node visited is the maximum value in the heap. > + * > + * If a heap_raw_*() function has been called without a later call to > + * heap_rebuild(), then the first node visited may not be the maximum > + * element. */ > +#define HEAP_FOR_EACH(NODE, MEMBER, HEAP) \ > + for (((HEAP)->n > 0 \ > + ? ASSIGN_CONTAINER(NODE, (HEAP)->array[1], MEMBER) \ > + : ((NODE) = NULL, 1)); \ > + (NODE) != NULL; \ > + ((NODE)->MEMBER.idx < (HEAP)->n \ > + ? ASSIGN_CONTAINER(NODE, \ > + (HEAP)->array[(NODE)->MEMBER.idx + 1], \ > + MEMBER) \ > + : ((NODE) = NULL, 1))) > + > +/* Returns the index of the node that is the parent of the node with the > given > + * 'idx' within a heap. */ > +static inline size_t > +heap_parent__(size_t idx) > +{ > + return idx / 2; > +} > + > +/* Returns the index of the node that is the left child of the node with the > + * given 'idx' within a heap. */ > +static inline size_t > +heap_left__(size_t idx) > +{ > + return idx * 2; > +} > + > +/* Returns the index of the node that is the right child of the node with the > + * given 'idx' within a heap. */ > +static inline size_t > +heap_right__(size_t idx) > +{ > + return idx * 2 + 1; > +} > + > +/* Returns true if 'idx' is the index of a leaf node in 'heap', false > + * otherwise. */ > +static inline bool > +heap_is_leaf__(const struct heap *heap, size_t idx) > +{ > + return heap_left__(idx) > heap->n; > +} > + > +/* Returns the number of elements in 'heap'. */ > +static inline size_t > +heap_count(const struct heap *heap) > +{ > + return heap->n; > +} > + > +/* Returns true if 'heap' is empty, false if it contains at least one > + * element. */ > +static inline bool > +heap_is_empty(const struct heap *heap) > +{ > + return heap->n == 0; > +} > + > +/* Returns the largest element in 'heap'. > + * > + * The caller must ensure that 'heap' contains at least one element. > + * > + * The return value may be wrong (i.e. not the maximum element but some other > + * element) if a heap_raw_*() function has been called without a later call > to > + * heap_rebuild(). */ > +static inline struct heap_node * > +heap_max(const struct heap *heap) > +{ > + return heap->array[1]; > +} > + > +/* Removes an arbitrary node from 'heap', in O(1), maintaining the heap > + * invariant. Returns the node removed. > + * > + * The caller must ensure that 'heap' contains at least one element. */ > +static inline struct heap_node * > +heap_pop(struct heap *heap) > +{ > + return heap->array[heap->n--]; > +} > + > +/* Changes the priority of 'node' (which must be in 'heap') to 'priority'. > + * > + * After this call, heap_max() will no longer necessarily return the maximum > + * value in the heap, and HEAP_FOR_EACH will no longer necessarily iterate in > + * heap level order, until the next call to heap_rebuild(heap). > + * > + * This takes time O(1). */ > +static inline void > +heap_raw_change(struct heap_node *node, uint32_t priority) > +{ > + node->priority = priority; > +} > + > +#endif /* heap.h */ > diff --git a/tests/.gitignore b/tests/.gitignore > index affb2ef..76b6fed 100644 > --- a/tests/.gitignore > +++ b/tests/.gitignore > @@ -16,6 +16,7 @@ > /test-file_name > /test-flows > /test-hash > +/test-heap > /test-hmap > /test-json > /test-jsonrpc > diff --git a/tests/automake.mk b/tests/automake.mk > index 9ae4c5c..8757466 100644 > --- a/tests/automake.mk > +++ b/tests/automake.mk > @@ -8,6 +8,7 @@ TESTSUITE_AT = \ > tests/testsuite.at \ > tests/ovsdb-macros.at \ > tests/library.at \ > + tests/heap.at \ > tests/bundle.at \ > tests/classifier.at \ > tests/check-structs.at \ > @@ -82,6 +83,7 @@ lcov_wrappers = \ > tests/lcov/test-file_name \ > tests/lcov/test-flows \ > tests/lcov/test-hash \ > + tests/lcov/test-heap \ > tests/lcov/test-hmap \ > tests/lcov/test-json \ > tests/lcov/test-jsonrpc \ > @@ -138,6 +140,7 @@ valgrind_wrappers = \ > tests/valgrind/test-file_name \ > tests/valgrind/test-flows \ > tests/valgrind/test-hash \ > + tests/valgrind/test-heap \ > tests/valgrind/test-hmap \ > tests/valgrind/test-json \ > tests/valgrind/test-jsonrpc \ > @@ -225,6 +228,10 @@ noinst_PROGRAMS += tests/test-hash > tests_test_hash_SOURCES = tests/test-hash.c > tests_test_hash_LDADD = lib/libopenvswitch.a > > +noinst_PROGRAMS += tests/test-heap > +tests_test_heap_SOURCES = tests/test-heap.c > +tests_test_heap_LDADD = lib/libopenvswitch.a > + > noinst_PROGRAMS += tests/test-hmap > tests_test_hmap_SOURCES = tests/test-hmap.c > tests_test_hmap_LDADD = lib/libopenvswitch.a > diff --git a/tests/heap.at b/tests/heap.at > new file mode 100644 > index 0000000..4e6e8ff > --- /dev/null > +++ b/tests/heap.at > @@ -0,0 +1,13 @@ > +AT_BANNER([heap library]) > + > +m4_define([TEST_HEAP], > + [AT_SETUP([heap library -- m4_bpatsubst([$1], [-], [ ])]) > + AT_CHECK([test-heap $1]) > + AT_CLEANUP]) > + > +TEST_HEAP([insert-delete-same-order]) > +TEST_HEAP([insert-delete-reverse-order]) > +TEST_HEAP([insert-delete-every-order]) > +TEST_HEAP([insert-delete-same-order-with-dups]) > +TEST_HEAP([raw-insert]) > +TEST_HEAP([raw-delete]) > diff --git a/tests/test-heap.c b/tests/test-heap.c > new file mode 100644 > index 0000000..83580d3 > --- /dev/null > +++ b/tests/test-heap.c > @@ -0,0 +1,504 @@ > +/* > + * Copyright (c) 2012 Nicira Networks. > + * > + * 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. > + */ > + > +/* A test for for functions and macros declared in heap.h. */ > + > +#include <config.h> > +#include "heap.h" > +#include <inttypes.h> > +#include <limits.h> > +#include <stdlib.h> > +#include "command-line.h" > +#include "random.h" > +#include "util.h" > + > +#undef NDEBUG > +#include <assert.h> > + > +/* Sample heap element. */ > +struct element { > + uint32_t full_pri; > + struct heap_node heap_node; > +}; > + > +static struct element * > +element_from_heap_node(const struct heap_node *node) > +{ > + return CONTAINER_OF(node, struct element, heap_node); > +} > + > +static int > +compare_uint32s(const void *a_, const void *b_) > +{ > + const uint32_t *a = a_; > + const uint32_t *b = b_; > + return *a < *b ? -1 : *a > *b; > +} > + > +/* Verifies that 'heap' is internally consistent and contains all 'n' of the > + * 'priorities'. */ > +static void > +check_heap(const struct heap *heap, const uint32_t priorities[], size_t n) > +{ > + uint32_t *priorities_copy; > + uint32_t *elements_copy; > + struct element *element; > + size_t i; > + > + assert(heap_count(heap) == n); > + assert(heap_is_empty(heap) == !n); > + if (n > 0) { > + assert(heap_max(heap) == heap->array[1]); > + } > + > + /* Check indexes. */ > + for (i = 1; i <= n; i++) { > + assert(heap->array[i]->idx == i); > + } > + > + /* Check that priority values are internally consistent. */ > + for (i = 1; i <= n; i++) { > + element = element_from_heap_node(heap->array[i]); > + assert(element->heap_node.priority == (element->full_pri >> 16)); > + } > + > + /* Check the heap property. */ > + for (i = 1; i <= n; i++) { > + size_t parent = heap_parent__(i); > + size_t left = heap_left__(i); > + size_t right = heap_right__(i); > + > + if (parent >= 1) { > + assert(heap->array[parent]->priority >= > heap->array[i]->priority); > + } > + if (left <= n) { > + assert(heap->array[left]->priority <= heap->array[i]->priority); > + } > + if (right <= n) { > + assert(heap->array[right]->priority <= heap->array[i]->priority); > + } > + } > + > + /* Check that HEAP_FOR_EACH iterates all the nodes in order. */ > + i = 0; > + HEAP_FOR_EACH (element, heap_node, heap) { > + assert(i < n); > + assert(&element->heap_node == heap->array[i + 1]); > + i++; > + } > + assert(i == n); > + > + priorities_copy = xmemdup(priorities, n * sizeof *priorities); > + elements_copy = xmalloc(n * sizeof *priorities); > + i = 0; > + HEAP_FOR_EACH (element, heap_node, heap) { > + elements_copy[i++] = element->heap_node.priority; > + } > + > + qsort(priorities_copy, n, sizeof *priorities_copy, compare_uint32s); > + qsort(elements_copy, n, sizeof *elements_copy, compare_uint32s); > + for (i = 0; i < n; i++) { > + assert((priorities_copy[i] >> 16) == elements_copy[i]); > + } > + > + free(priorities_copy); > + free(elements_copy); > +} > + > +#if 0 > +/* Puts the 'n' values in 'priorities' into 'elements', and then puts those > + * elements into 'heap'. */ > +static void > +make_heap(struct heap *heap, struct element elements[], > + uint32_t priorities[], size_t n) > +{ > + size_t i; > + > + heap_init(heap); > + for (i = 0; i < n; i++) { > + elements[i].priority_copy = i; > + heap_insert(heap, &elements[i].heap_node, priorities[i]); > + priorities[i] = i; > + } > +} > +#endif > + > +static void > +shuffle(uint32_t *p, size_t n) > +{ > + for (; n > 1; n--, p++) { > + uint32_t *q = &p[random_range(n)]; > + uint32_t tmp = *p; > + *p = *q; > + *q = tmp; > + } > +} > + > +/* Prints the values in 'heap', plus 'name' as a title. */ > +static void OVS_UNUSED > +print_heap(const char *name, struct heap *heap) > +{ > + struct element *e; > + > + printf("%s:", name); > + HEAP_FOR_EACH (e, heap_node, heap) { > + printf(" %"PRIu32":%"PRIu32, e->full_pri >> 16, e->full_pri & > 0xffff); > + } > + printf("\n"); > +} > + > +static int > +factorial(int n_items) > +{ > + int n, i; > + > + n = 1; > + for (i = 2; i <= n_items; i++) { > + n *= i; > + } > + return n; > +} > + > +static void > +swap(uint32_t *a, uint32_t *b) > +{ > + uint32_t tmp = *a; > + *a = *b; > + *b = tmp; > +} > + > +static void > +reverse(uint32_t *a, int n) > +{ > + int i; > + > + for (i = 0; i < n / 2; i++) { > + int j = n - (i + 1); > + swap(&a[i], &a[j]); > + } > +} > + > +static bool > +next_permutation(uint32_t *a, int n) > +{ > + int k; > + > + for (k = n - 2; k >= 0; k--) { > + if ((a[k] >> 16) < (a[k + 1] >> 16)) { > + int l; > + > + for (l = n - 1; ; l--) { > + if ((a[l] >> 16) > (a[k] >> 16)) { > + swap(&a[k], &a[l]); > + reverse(a + (k + 1), n - (k + 1)); > + return true; > + } > + } > + } > + } > + return false; > +} > + > +static void > +test_insert_delete__(struct element *elements, > + const uint32_t *insert, > + const uint32_t *delete, > + size_t n) > +{ > + struct heap heap; > + size_t i; > + > + heap_init(&heap); > + check_heap(&heap, NULL, 0); > + for (i = 0; i < n; i++) { > + uint32_t priority = insert[i]; > + > + elements[i].full_pri = priority; > + heap_insert(&heap, &elements[i].heap_node, priority >> 16); > + check_heap(&heap, insert, i + 1); > + } > + > + for (i = 0; i < n; i++) { > + struct element *element; > + > + HEAP_FOR_EACH (element, heap_node, &heap) { > + if (element->full_pri == delete[i]) { > + goto found; > + } > + } > + NOT_REACHED(); > + > + found: > + heap_remove(&heap, &element->heap_node); > + check_heap(&heap, delete + i + 1, n - (i + 1)); > + } > + heap_destroy(&heap); > +} > + > +static void > +test_insert_delete_raw__(struct element *elements, > + const uint32_t *insert, unsigned int insert_pattern, > + const uint32_t *delete, unsigned int delete_pattern, > + size_t n) > +{ > + struct heap heap; > + size_t i; > + > + heap_init(&heap); > + check_heap(&heap, NULL, 0); > + for (i = 0; i < n; i++) { > + uint32_t priority = insert[i]; > + > + elements[i].full_pri = priority; > + heap_raw_insert(&heap, &elements[i].heap_node, priority >> 16); > + if (insert_pattern & (1u << i)) { > + heap_rebuild(&heap); > + check_heap(&heap, insert, i + 1); > + } > + } > + > + for (i = 0; i < n; i++) { > + struct element *element; > + > + HEAP_FOR_EACH (element, heap_node, &heap) { > + if (element->full_pri == delete[i]) { > + goto found; > + } > + } > + NOT_REACHED(); > + > + found: > + heap_raw_remove(&heap, &element->heap_node); > + if (delete_pattern & (1u << i)) { > + heap_rebuild(&heap); > + check_heap(&heap, delete + i + 1, n - (i + 1)); > + } > + } > + heap_destroy(&heap); > +} > + > +static void > +test_heap_insert_delete_same_order(int argc OVS_UNUSED, > + char *argv[] OVS_UNUSED) > +{ > + enum { N_ELEMS = 7 }; > + > + uint32_t insert[N_ELEMS]; > + int n_permutations; > + size_t i; > + > + for (i = 0; i < N_ELEMS; i++) { > + insert[i] = i << 16; > + } > + > + n_permutations = 0; > + do { > + struct element elements[N_ELEMS]; > + > + n_permutations++; > + test_insert_delete__(elements, insert, insert, N_ELEMS); > + } while (next_permutation(insert, N_ELEMS)); > + assert(n_permutations == factorial(N_ELEMS)); > +} > + > +static void > +test_heap_insert_delete_reverse_order(int argc OVS_UNUSED, > + char *argv[] OVS_UNUSED) > +{ > + enum { N_ELEMS = 7 }; > + > + uint32_t insert[N_ELEMS]; > + int n_permutations; > + size_t i; > + > + for (i = 0; i < N_ELEMS; i++) { > + insert[i] = i << 16; > + } > + > + n_permutations = 0; > + do { > + struct element elements[N_ELEMS]; > + uint32_t delete[N_ELEMS]; > + > + n_permutations++; > + > + for (i = 0; i < N_ELEMS; i++) { > + delete[N_ELEMS - i - 1] = insert[i]; > + } > + > + test_insert_delete__(elements, insert, delete, N_ELEMS); > + } while (next_permutation(insert, N_ELEMS)); > + assert(n_permutations == factorial(N_ELEMS)); > +} > + > +static void > +test_heap_insert_delete_every_order(int argc OVS_UNUSED, > + char *argv[] OVS_UNUSED) > +{ > + enum { N_ELEMS = 5 }; > + > + uint32_t insert[N_ELEMS]; > + int outer_permutations; > + size_t i; > + > + for (i = 0; i < N_ELEMS; i++) { > + insert[i] = i << 16; > + } > + > + outer_permutations = 0; > + do { > + struct element elements[N_ELEMS]; > + uint32_t delete[N_ELEMS]; > + int inner_permutations; > + > + outer_permutations++; > + > + for (i = 0; i < N_ELEMS; i++) { > + delete[i] = i << 16; > + } > + > + inner_permutations = 0; > + do { > + inner_permutations++; > + test_insert_delete__(elements, insert, delete, N_ELEMS); > + } while (next_permutation(delete, N_ELEMS)); > + assert(inner_permutations == factorial(N_ELEMS)); > + } while (next_permutation(insert, N_ELEMS)); > + assert(outer_permutations == factorial(N_ELEMS)); > +} > + > +static void > +test_heap_insert_delete_same_order_with_dups(int argc OVS_UNUSED, > + char *argv[] OVS_UNUSED) > +{ > + enum { N_ELEMS = 7 }; > + > + unsigned int pattern; > + size_t i; > + > + for (pattern = 0; pattern < (1u << N_ELEMS); pattern += 2) { > + int n_permutations, expected_permutations; > + uint32_t insert[N_ELEMS]; > + int j; > + > + j = 0; > + for (i = 0; i < N_ELEMS; i++) { > + if (i && !(pattern & (1u << i))) { > + j++; > + } > + insert[i] = (j << 16) | i; > + } > + > + expected_permutations = factorial(N_ELEMS); > + for (i = 0; i < N_ELEMS; ) { > + j = i + 1; > + if (pattern & (1u << i)) { > + for (; j < N_ELEMS; j++) { > + if (!(pattern & (1u << j))) { > + break; > + } > + } > + expected_permutations /= factorial(j - i + 1); > + } > + i = j; > + } > + > + n_permutations = 0; > + do { > + struct element elements[N_ELEMS]; > + > + n_permutations++; > + test_insert_delete__(elements, insert, insert, N_ELEMS); > + } while (next_permutation(insert, N_ELEMS)); > + assert(n_permutations == expected_permutations); > + } > +} > + > +static void > +test_heap_raw_insert(int argc OVS_UNUSED, char *argv[] OVS_UNUSED) > +{ > + enum { N_ELEMS = 7 }; > + > + uint32_t insert[N_ELEMS]; > + int n_permutations; > + size_t i; > + > + for (i = 0; i < N_ELEMS; i++) { > + insert[i] = i << 16; > + } > + > + n_permutations = 0; > + do { > + struct element elements[N_ELEMS]; > + > + n_permutations++; > + test_insert_delete_raw__(elements, > + insert, 1u << (N_ELEMS - 1), > + insert, UINT_MAX, > + N_ELEMS); > + } while (next_permutation(insert, N_ELEMS)); > + assert(n_permutations == factorial(N_ELEMS)); > +} > + > +static void > +test_heap_raw_delete(int argc OVS_UNUSED, char *argv[] OVS_UNUSED) > +{ > + enum { N_ELEMS = 16 }; > + > + uint32_t insert[N_ELEMS]; > + uint32_t delete[N_ELEMS]; > + size_t i; > + > + for (i = 0; i < N_ELEMS; i++) { > + insert[i] = i << 16; > + delete[i] = i << 16; > + } > + > + for (i = 0; i < 1000; i++) { > + struct element elements[N_ELEMS]; > + > + shuffle(insert, N_ELEMS); > + shuffle(delete, N_ELEMS); > + > + test_insert_delete_raw__(elements, > + insert, 0, > + delete, > + (1u << (N_ELEMS - 1)) | (1u << (N_ELEMS / > 2)), > + N_ELEMS); > + } > +} > + > +static const struct command commands[] = { > + { "insert-delete-same-order", 0, 0, test_heap_insert_delete_same_order, > }, > + { "insert-delete-reverse-order", 0, 0, > + test_heap_insert_delete_reverse_order, }, > + { "insert-delete-every-order", 0, 0, > + test_heap_insert_delete_every_order, }, > + { "insert-delete-same-order-with-dups", 0, 0, > + test_heap_insert_delete_same_order_with_dups, }, > + { "raw-insert", 0, 0, test_heap_raw_insert, }, > + { "raw-delete", 0, 0, test_heap_raw_delete, }, > +}; > + > +int > +main(int argc, char *argv[]) > +{ > + set_program_name(argv[0]); > + > + run_command(argc - 1, argv + 1, commands); > + > + return 0; > +} > diff --git a/tests/testsuite.at b/tests/testsuite.at > index d8af592..7711ba3 100644 > --- a/tests/testsuite.at > +++ b/tests/testsuite.at > @@ -1,6 +1,6 @@ > AT_INIT > > -AT_COPYRIGHT([Copyright (c) 2009, 2010, 2011 Nicira Networks. > +AT_COPYRIGHT([Copyright (c) 2009, 2010, 2011, 2012 Nicira Networks. > > Licensed under the Apache License, Version 2.0 (the "License"); > you may not use this file except in compliance with the License. > @@ -40,6 +40,7 @@ m4_include([tests/ofproto-macros.at]) > > m4_include([tests/lacp.at]) > m4_include([tests/library.at]) > +m4_include([tests/heap.at]) > m4_include([tests/bundle.at]) > m4_include([tests/classifier.at]) > m4_include([tests/check-structs.at]) > -- > 1.7.2.5 > > _______________________________________________ > dev mailing list > dev@openvswitch.org > http://openvswitch.org/mailman/listinfo/dev _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev