diff --git a/src/multiset.c b/src/multiset.c new file mode 100644 index 0000000..bb82ea4 --- /dev/null +++ b/src/multiset.c @@ -0,0 +1,632 @@ +/* + * Copyright (c) 2017 Bailey Thompson + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include "multiset.h" + +struct _multiset { + size_t key_size; + int (*comparator)(const void *const one, const void *const two); + int size; + struct node *root; +}; + +struct node { + int count; + struct node *parent; + int balance; + void *key; + struct node *left; + struct node *right; +}; + +/** + * Initializes a multiset, which is a collection of key-value pairs, sorted by + * keys, keys are unique + * + * @param key_size The size of each element in the multiset. + * @param comparator The comparator function used for key ordering. + * + * @return The newly-initialized multiset, or NULL if memory allocation error. + */ +multiset multiset_init(const size_t key_size, + int (*const comparator)(const void *const, + const void *const)) +{ + struct _multiset *const init = malloc(sizeof(struct _multiset)); + if (init == NULL) { + return NULL; + } + init->key_size = key_size; + init->comparator = comparator; + init->size = 0; + init->root = NULL; + return init; +} + +/** + * Gets the size of the multiset. + * + * @param me The multiset to check. + * + * @return The size of the multiset. + */ +int multiset_size(multiset me) +{ + return me->size; +} + +/** + * Determines whether or not the multiset is empty. + * + * @param me The multiset to check. + * + * @return If the multiset is empty. + */ +bool multiset_is_empty(multiset me) +{ + return multiset_size(me) == 0; +} + +/* + * Resets the parent reference. + */ +static void multiset_reference_parent(multiset me, + struct node *const parent, + struct node *const child) +{ + child->parent = parent->parent; + if (parent->parent == NULL) { + me->root = child; + } else if (parent->parent->left == parent) { + parent->parent->left = child; + } else { + parent->parent->right = child; + } +} + +/* + * Rotates the AVL tree to the left. + */ +static void multiset_rotate_left(multiset me, + struct node *const parent, + struct node *const child) +{ + multiset_reference_parent(me, parent, child); + struct node *const grand_child = child->left; + if (grand_child != NULL) { + grand_child->parent = parent; + } + parent->parent = child; + parent->right = grand_child; + child->left = parent; +} + +/* + * Rotates the AVL tree to the right. + */ +static void multiset_rotate_right(multiset me, + struct node *const parent, + struct node *const child) +{ + multiset_reference_parent(me, parent, child); + struct node *const grand_child = child->right; + if (grand_child != NULL) { + grand_child->parent = parent; + } + parent->parent = child; + parent->left = grand_child; + child->right = parent; +} + +/* + * Repairs the AVL tree on insert. + */ +static struct node *multiset_repair(multiset me, + struct node *const parent, + struct node *const child, + struct node *const grand_child) +{ + if (parent->balance == 2 && child->balance >= 0) { + multiset_rotate_left(me, parent, child); + if (child->balance == 0) { + parent->balance = 1; + child->balance = -1; + } else { + parent->balance = 0; + child->balance = 0; + } + return child; + } + if (parent->balance == -2 && child->balance <= 0) { + multiset_rotate_right(me, parent, child); + if (child->balance == 0) { + parent->balance = -1; + child->balance = 1; + } else { + parent->balance = 0; + child->balance = 0; + } + return child; + } + if (parent->balance == -2 && child->balance == 1) { + multiset_rotate_left(me, child, grand_child); + multiset_rotate_right(me, parent, grand_child); + if (grand_child->balance == 1) { + parent->balance = 0; + child->balance = -1; + } else if (grand_child->balance == 0) { + parent->balance = 0; + child->balance = 0; + } else { + parent->balance = 1; + child->balance = 0; + } + grand_child->balance = 0; + return grand_child; + } + if (parent->balance == 2 && child->balance == -1) { + multiset_rotate_right(me, child, grand_child); + multiset_rotate_left(me, parent, grand_child); + if (grand_child->balance == 1) { + parent->balance = -1; + child->balance = 0; + } else if (grand_child->balance == 0) { + parent->balance = 0; + child->balance = 0; + } else { + parent->balance = 0; + child->balance = 1; + } + grand_child->balance = 0; + return grand_child; + } + // Impossible to get here. + return NULL; +} + +/* + * Balances the AVL tree on insert. + */ +static void multiset_insert_balance(multiset me, struct node *const item) +{ + struct node *grand_child = NULL; + struct node *child = item; + struct node *parent = item->parent; + while (parent != NULL) { + if (parent->left == child) { + parent->balance--; + } else { + parent->balance++; + } + // If balance is zero after modification, then the tree is balanced. + if (parent->balance == 0) { + return; + } + // Must re-balance if not in {-1, 0, 1} + if (parent->balance > 1 || parent->balance < -1) { + // After one repair, the tree is balanced. + multiset_repair(me, parent, child, grand_child); + return; + } + grand_child = child; + child = parent; + parent = parent->parent; + } +} + +/* + * Creates and allocates a node. + */ +static struct node *multiset_create_node(multiset me, + const void *const data, + struct node *const parent) +{ + struct node *const insert = malloc(sizeof(struct node)); + if (insert == NULL) { + return NULL; + } + insert->count = 1; + insert->parent = parent; + insert->balance = 0; + insert->key = malloc(me->key_size); + if (insert->key == NULL) { + free(insert); + return NULL; + } + memcpy(insert->key, data, me->key_size); + insert->left = NULL; + insert->right = NULL; + return insert; +} + +/** + * Adds an element to the multiset if the multiset does not already contain it. + * + * @param me The multiset to add to. + * @param key The element to add. + * + * @return 0 No error. + * -ENOMEM Out of memory. + */ +int multiset_put(multiset me, void *const key) +{ + if (me->root == NULL) { + struct node *insert = multiset_create_node(me, key, NULL); + if (insert == NULL) { + return -ENOMEM; + } + me->root = insert; + me->size++; + return 0; + } + struct node *traverse = me->root; + while (true) { + const int compare = me->comparator(key, traverse->key); + if (compare < 0) { + if (traverse->left != NULL) { + traverse = traverse->left; + } else { + struct node *insert = multiset_create_node(me, key, traverse); + if (insert == NULL) { + return -ENOMEM; + } + traverse->left = insert; + multiset_insert_balance(me, insert); + me->size++; + return 0; + } + } else if (compare > 0) { + if (traverse->right != NULL) { + traverse = traverse->right; + } else { + struct node *insert = multiset_create_node(me, key, traverse); + if (insert == NULL) { + return -ENOMEM; + } + traverse->right = insert; + multiset_insert_balance(me, insert); + me->size++; + return 0; + } + } else { + traverse->count++; + me->size++; + return 0; + } + } +} + +/* + * If a match occurs, returns the match. Else, returns NULL. + */ +static struct node *multiset_equal_match(multiset me, const void *const key) +{ + struct node *traverse = me->root; + if (traverse == NULL) { + return false; + } + while (true) { + const int compare = me->comparator(key, traverse->key); + if (compare < 0) { + if (traverse->left != NULL) { + traverse = traverse->left; + } else { + return NULL; + } + } else if (compare > 0) { + if (traverse->right != NULL) { + traverse = traverse->right; + } else { + return NULL; + } + } else { + return traverse; + } + } +} + +/** + * Determines the count of a specific key in the multiset. + * + * @param me The multiset to check for the count. + * @param key The element to check. + * + * @return The count of a specific key in the multiset. + */ +int multiset_count(multiset me, void *const key) +{ + const struct node *const item = multiset_equal_match(me, key); + if (item == NULL) { + return 0; + } + return item->count; +} + +/** + * Determines if the multiset contains the specified element. + * + * @param me The multiset to check for the element. + * @param key The element to check. + * + * @return If the multiset contained the element. + */ +bool multiset_contains(multiset me, void *const key) +{ + return multiset_equal_match(me, key) != NULL; +} + +/* + * Repairs the AVL tree by pivoting on an item. + */ +static struct node *multiset_repair_pivot(multiset me, + struct node *const item, + const bool is_left_pivot) +{ + struct node *const child = is_left_pivot ? item->right : item->left; + struct node *const grand_child = + child->balance == 1 ? child->right : child->left; + return multiset_repair(me, item, child, grand_child); +} + +/* + * Balances the AVL tree on deletion. + */ +static void multiset_delete_balance(multiset me, + struct node *item, + const bool is_left_deleted) +{ + if (is_left_deleted) { + item->balance++; + } else { + item->balance--; + } + // If balance is -1 or +1 after modification, then the tree is balanced. + if (item->balance == -1 || item->balance == 1) { + return; + } + // Must re-balance if not in {-1, 0, 1} + if (item->balance > 1 || item->balance < -1) { + item = multiset_repair_pivot(me, item, is_left_deleted); + if (item->parent == NULL || item->balance == -1 || item->balance == 1) { + return; + } + } + struct node *child = item; + struct node *parent = item->parent; + while (parent != NULL) { + if (parent->left == child) { + parent->balance++; + } else { + parent->balance--; + } + // If balance is -1 or +1 after modification, then the tree is balanced. + if (parent->balance == -1 || parent->balance == 1) { + return; + } + // Must re-balance if not in {-1, 0, 1} + if (parent->balance > 1 || parent->balance < -1) { + child = multiset_repair_pivot(me, parent, parent->left == child); + parent = child->parent; + // If balance is -1 or +1 after modification or the parent is NULL, + // then the tree is balanced. + if (parent == NULL || child->balance == -1 || child->balance == 1) { + return; + } + } else { + child = parent; + parent = parent->parent; + } + } +} + +/* + * Removes traverse when it has no children. + */ +static void multiset_remove_no_children(multiset me, + const struct node *const traverse) +{ + struct node *const parent = traverse->parent; + // If no parent and no children, then the only node is traverse. + if (parent == NULL) { + me->root = NULL; + return; + } + // No re-reference needed since traverse has no children. + if (parent->left == traverse) { + parent->left = NULL; + multiset_delete_balance(me, parent, true); + } else { + parent->right = NULL; + multiset_delete_balance(me, parent, false); + } +} + +/* + * Removes traverse when it has one child. + */ +static void multiset_remove_one_child(multiset me, + const struct node *const traverse) +{ + struct node *const parent = traverse->parent; + // If no parent, make the child of traverse the new root. + if (parent == NULL) { + if (traverse->left != NULL) { + traverse->left->parent = NULL; + me->root = traverse->left; + } else { + traverse->right->parent = NULL; + me->root = traverse->right; + } + return; + } + // The parent of traverse now references the child of traverse. + if (parent->left == traverse) { + if (traverse->left != NULL) { + parent->left = traverse->left; + traverse->left->parent = parent; + } else { + parent->left = traverse->right; + traverse->right->parent = parent; + } + multiset_delete_balance(me, parent, true); + } else { + if (traverse->left != NULL) { + parent->right = traverse->left; + traverse->left->parent = parent; + } else { + parent->right = traverse->right; + traverse->right->parent = parent; + } + multiset_delete_balance(me, parent, false); + } +} + +/* + * Removes traverse when it has two children. + */ +static void multiset_remove_two_children(multiset me, + const struct node *const traverse) +{ + struct node *item; + struct node *parent; + const bool is_left_deleted = traverse->right->left != NULL; + if (!is_left_deleted) { + item = traverse->right; + parent = item; + item->balance = traverse->balance; + item->parent = traverse->parent; + item->left = traverse->left; + item->left->parent = item; + } else { + item = traverse->right->left; + while (item->left != NULL) { + item = item->left; + } + parent = item->parent; + item->balance = traverse->balance; + item->parent->left = item->right; + if (item->right != NULL) { + item->right->parent = item->parent; + } + item->left = traverse->left; + item->left->parent = item; + item->right = traverse->right; + item->right->parent = item; + item->parent = traverse->parent; + } + if (traverse->parent == NULL) { + me->root = item; + } else if (traverse->parent->left == traverse) { + item->parent->left = item; + } else { + item->parent->right = item; + } + multiset_delete_balance(me, parent, is_left_deleted); +} + +/* + * Removes the element from the set. + */ +static void multiset_remove_element(multiset me, struct node *const traverse) +{ + if (traverse->left == NULL && traverse->right == NULL) { + multiset_remove_no_children(me, traverse); + } else if (traverse->left == NULL || traverse->right == NULL) { + multiset_remove_one_child(me, traverse); + } else { + multiset_remove_two_children(me, traverse); + } + free(traverse->key); + free(traverse); +} + +/** + * Removes an element from the multiset if it contains it. + * + * @param me The multiset to remove an element from. + * @param key The element to remove. + * + * @return If the multiset contained the element. + */ +bool multiset_remove(multiset me, void *const key) +{ + struct node *const traverse = multiset_equal_match(me, key); + if (traverse == NULL) { + return false; + } + traverse->count--; + if (traverse->count == 0) { + multiset_remove_element(me, traverse); + } + me->size--; + return true; +} + +/** + * Removes all the elements specified by the key from an multiset if it contains + * the key. + * + * @param me The multiset to remove an element from. + * @param key The element to remove. + * + * @return If the multiset contained the element. + */ +bool multiset_remove_all(multiset me, void *const key) +{ + struct node *const traverse = multiset_equal_match(me, key); + if (traverse == NULL) { + return false; + } + me->size -= traverse->count; + multiset_remove_element(me, traverse); + return true; +} + +/** + * Clears the elements from the multiset. + * + * @param me The multiset to clear. + */ +void multiset_clear(multiset me) +{ + while (me->root != NULL) { + multiset_remove_element(me, me->root); + } + me->size = 0; +} + +/** + * Frees the multiset memory. + * + * @param me The multiset to free from memory. + * + * @return NULL + */ +multiset multiset_destroy(multiset me) +{ + multiset_clear(me); + free(me); + return NULL; +} diff --git a/src/multiset.h b/src/multiset.h new file mode 100644 index 0000000..33ab1d8 --- /dev/null +++ b/src/multiset.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2017 Bailey Thompson + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef CONTAINERS_MULTISET_H +#define CONTAINERS_MULTISET_H + +#include + +typedef struct _multiset *multiset; + +// Starting +multiset multiset_init(size_t key_size, + int (*comparator)(const void *const one, + const void *const two)); + +// Capacity +int multiset_size(multiset me); +bool multiset_is_empty(multiset me); + +// Accessing +int multiset_put(multiset me, void *key); +int multiset_count(multiset me, void *key); +bool multiset_contains(multiset me, void *key); +bool multiset_remove(multiset me, void *key); +bool multiset_remove_all(multiset me, void *key); + +// Ending +void multiset_clear(multiset me); +multiset multiset_destroy(multiset me); + +#endif /* CONTAINERS_MULTISET_H */ diff --git a/src/set.c b/src/set.c index 014c1e3..5fc5aef 100644 --- a/src/set.c +++ b/src/set.c @@ -267,7 +267,7 @@ static struct node *set_create_node(set me, * @return 0 No error. * -ENOMEM Out of memory. */ -int set_add(set me, void *const key) +int set_put(set me, void *const key) { if (me->root == NULL) { struct node *insert = set_create_node(me, key, NULL); diff --git a/src/set.h b/src/set.h index 5da1750..cb700c9 100644 --- a/src/set.h +++ b/src/set.h @@ -36,7 +36,7 @@ int set_size(set me); bool set_is_empty(set me); // Accessing -int set_add(set me, void *key); +int set_put(set me, void *key); bool set_contains(set me, void *key); bool set_remove(set me, void *key); diff --git a/tst/multiset.c b/tst/multiset.c new file mode 100644 index 0000000..8c4a8c1 --- /dev/null +++ b/tst/multiset.c @@ -0,0 +1,137 @@ +#include "test.h" +#include "../src/multiset.h" + +static int compare_int(const void *const one, const void *const two) +{ + const int a = *(int *) one; + const int b = *(int *) two; + return a - b; +} + +void test_multiset(void) +{ + multiset a = multiset_init(sizeof(int), compare_int); + assert(multiset_size(a) == 0); + assert(multiset_is_empty(a)); + int b = 4; + multiset_put(a, &b); + assert(multiset_size(a) == 1); + multiset_put(a, &b); + assert(multiset_size(a) == 2); + assert(multiset_count(a, &b) == 2); + assert(!multiset_is_empty(a)); + assert(multiset_contains(a, &b)); + b = 7; + assert(!multiset_contains(a, &b)); + multiset_put(a, &b); + assert(multiset_size(a) == 3); + assert(multiset_contains(a, &b)); + multiset_remove(a, &b); + assert(multiset_size(a) == 2); + assert(!multiset_contains(a, &b)); + b = 4; + multiset_remove(a, &b); + assert(multiset_size(a) == 1); + multiset_remove(a, &b); + assert(multiset_size(a) == 0); + int c[10] = {5, 9, 4, -5, 0, 6, 1, 5, 7, 2}; + for (int i = 0; i < 10; i++) { + multiset_put(a, &c[i]); + assert(multiset_contains(a, &c[i])); + } + assert(multiset_size(a) == 10); + for (int i = 0; i < 10; i++) { + assert(multiset_contains(a, &c[i])); + } + for (int i = -100; i < 100; i++) { + bool contains = false; + for (int j = 0; j < 10; j++) { + if (c[j] == i) { + contains = true; + } + } + assert(multiset_contains(a, &i) == contains); + } + int num = -3; + assert(!multiset_remove(a, &num)); + assert(multiset_size(a) == 10); + assert(!multiset_contains(a, &num)); + num = 6; + assert(multiset_remove(a, &num)); + assert(multiset_size(a) == 9); + assert(!multiset_contains(a, &num)); + num = 4; + assert(multiset_remove(a, &num)); + assert(multiset_size(a) == 8); + assert(!multiset_contains(a, &num)); + num = 7; + assert(multiset_remove(a, &num)); + assert(multiset_size(a) == 7); + assert(!multiset_contains(a, &num)); + num = 9; + assert(multiset_remove(a, &num)); + assert(multiset_size(a) == 6); + assert(!multiset_contains(a, &num)); + num = -5; + assert(multiset_remove(a, &num)); + assert(multiset_size(a) == 5); + assert(!multiset_contains(a, &num)); + num = 0; + assert(multiset_remove(a, &num)); + assert(multiset_size(a) == 4); + assert(!multiset_contains(a, &num)); + num = 1; + assert(multiset_remove(a, &num)); + assert(multiset_size(a) == 3); + assert(!multiset_contains(a, &num)); + num = 5; + assert(multiset_remove(a, &num)); + assert(multiset_size(a) == 2); + assert(multiset_contains(a, &num)); + num = 2; + assert(multiset_remove(a, &num)); + assert(multiset_size(a) == 1); + assert(!multiset_contains(a, &num)); + num = 5; + assert(multiset_remove(a, &num)); + assert(multiset_size(a) == 0); + assert(!multiset_contains(a, &num)); + // Add a lot of items and remove individually. + for (int i = 5000; i < 6000; i++) { + multiset_put(a, &i); + assert(multiset_contains(a, &i)); + } + assert(multiset_size(a) == 1000); + for (int i = 5000; i < 6000; i++) { + multiset_remove(a, &i); + assert(!multiset_contains(a, &i)); + } + assert(multiset_size(a) == 0); + assert(multiset_is_empty(a)); + multiset_clear(a); + assert(multiset_size(a) == 0); + assert(multiset_is_empty(a)); + // Add a lot of items and clear. + for (int i = 5000; i < 6000; i++) { + multiset_put(a, &i); + assert(multiset_contains(a, &i)); + } + assert(multiset_size(a) == 1000); + multiset_clear(a); + int p = 0xdeadbeef; + assert(!multiset_remove(a, &p)); + assert(multiset_size(a) == 0); + assert(multiset_is_empty(a)); + int m = 5; + multiset_put(a, &m); + assert(multiset_size(a) == 1); + m = 7; + for (int i = 0; i < 10; i++) { + multiset_put(a, &m); + } + assert(multiset_size(a) == 11); + multiset_remove_all(a, &m); + assert(multiset_size(a) == 1); + a = multiset_destroy(a); + assert(a == NULL); +} diff --git a/tst/set.c b/tst/set.c index 580d6e9..1574bc3 100644 --- a/tst/set.c +++ b/tst/set.c @@ -2,7 +2,7 @@ #include "../src/set.h" // Used for thorough testing, but takes longer to run. -#define LONG_TEST +//#define LONG_TEST /* * Include this struct for the stubs. @@ -71,9 +71,9 @@ static void set_verify(set me) #endif } -static int stub_set_add(set me, void *const key) +static int stub_set_put(set me, void *const key) { - const int ret = set_add(me, key); + const int ret = set_put(me, key); set_verify(me); return ret; } @@ -118,111 +118,111 @@ void test_set(void) int b; // left-left b = 5; - stub_set_add(a, &b); + stub_set_put(a, &b); b = 3; - stub_set_add(a, &b); + stub_set_put(a, &b); b = 1; - stub_set_add(a, &b); + stub_set_put(a, &b); b = 0xdeadbeef; stub_set_contains(a, &b); stub_set_clear(a); // right-right b = 1; - stub_set_add(a, &b); + stub_set_put(a, &b); b = 3; - stub_set_add(a, &b); + stub_set_put(a, &b); b = 5; - stub_set_add(a, &b); + stub_set_put(a, &b); b = 0xdeadbeef; stub_set_contains(a, &b); stub_set_clear(a); // left-right b = 5; - stub_set_add(a, &b); + stub_set_put(a, &b); b = 1; - stub_set_add(a, &b); + stub_set_put(a, &b); b = 3; - stub_set_add(a, &b); + stub_set_put(a, &b); b = 0xdeadbeef; stub_set_contains(a, &b); stub_set_clear(a); // right-left b = 1; - stub_set_add(a, &b); + stub_set_put(a, &b); b = 5; - stub_set_add(a, &b); + stub_set_put(a, &b); b = 3; - stub_set_add(a, &b); + stub_set_put(a, &b); b = 0xdeadbeef; stub_set_contains(a, &b); stub_set_clear(a); // Two children edge case. b = 8; - stub_set_add(a, &b); + stub_set_put(a, &b); b = 5; - stub_set_add(a, &b); + stub_set_put(a, &b); b = 11; - stub_set_add(a, &b); + stub_set_put(a, &b); b = 2; - stub_set_add(a, &b); + stub_set_put(a, &b); b = 6; - stub_set_add(a, &b); + stub_set_put(a, &b); b = 10; - stub_set_add(a, &b); + stub_set_put(a, &b); b = 15; - stub_set_add(a, &b); + stub_set_put(a, &b); b = 1; - stub_set_add(a, &b); + stub_set_put(a, &b); b = 3; - stub_set_add(a, &b); + stub_set_put(a, &b); b = 4; - stub_set_add(a, &b); + stub_set_put(a, &b); b = 7; - stub_set_add(a, &b); + stub_set_put(a, &b); b = 9; - stub_set_add(a, &b); + stub_set_put(a, &b); b = 12; - stub_set_add(a, &b); + stub_set_put(a, &b); b = 13; - stub_set_add(a, &b); + stub_set_put(a, &b); b = 16; - stub_set_add(a, &b); + stub_set_put(a, &b); b = 14; - stub_set_add(a, &b); + stub_set_put(a, &b); stub_set_clear(a); // Two children edge case. b = 8; - stub_set_add(a, &b); + stub_set_put(a, &b); b = 4; - stub_set_add(a, &b); + stub_set_put(a, &b); b = 12; - stub_set_add(a, &b); + stub_set_put(a, &b); b = 2; - stub_set_add(a, &b); + stub_set_put(a, &b); b = 6; - stub_set_add(a, &b); + stub_set_put(a, &b); b = 10; - stub_set_add(a, &b); + stub_set_put(a, &b); b = 15; - stub_set_add(a, &b); + stub_set_put(a, &b); b = 1; - stub_set_add(a, &b); + stub_set_put(a, &b); b = 3; - stub_set_add(a, &b); + stub_set_put(a, &b); b = 5; - stub_set_add(a, &b); + stub_set_put(a, &b); b = 7; - stub_set_add(a, &b); + stub_set_put(a, &b); b = 9; - stub_set_add(a, &b); + stub_set_put(a, &b); b = 11; - stub_set_add(a, &b); + stub_set_put(a, &b); b = 13; - stub_set_add(a, &b); + stub_set_put(a, &b); b = 16; - stub_set_add(a, &b); + stub_set_put(a, &b); b = 14; - stub_set_add(a, &b); + stub_set_put(a, &b); stub_set_clear(a); // Add a lot of items. int count = 0; @@ -230,7 +230,7 @@ void test_set(void) for (int i = 1234; i < 82400; i++) { int n = i % 765; const bool is_already_present = stub_set_contains(a, &n); - stub_set_add(a, &n); + stub_set_put(a, &n); const bool is_now_present = stub_set_contains(a, &n); assert(is_now_present); if (!is_already_present && is_now_present) { @@ -248,20 +248,20 @@ void test_set(void) assert(set_size(a) == 0); assert(set_is_empty(a)); b = 4; - stub_set_add(a, &b); + stub_set_put(a, &b); assert(set_size(a) == 1); - stub_set_add(a, &b); + stub_set_put(a, &b); assert(set_size(a) == 1); assert(!set_is_empty(a)); assert(stub_set_contains(a, &b)); b = 7; assert(!stub_set_contains(a, &b)); - stub_set_add(a, &b); + stub_set_put(a, &b); assert(set_size(a) == 2); assert(stub_set_contains(a, &b)); int c[10] = {5, 9, 4, -5, 0, 6, 1, 5, 7, 2}; for (int i = 0; i < 10; i++) { - stub_set_add(a, &c[i]); + stub_set_put(a, &c[i]); assert(stub_set_contains(a, &c[i])); } assert(set_size(a) == 9); @@ -319,7 +319,7 @@ void test_set(void) assert(!stub_set_contains(a, &num)); // Add a lot of items and remove individually. for (int i = 5000; i < 6000; i++) { - stub_set_add(a, &i); + stub_set_put(a, &i); assert(stub_set_contains(a, &i)); } assert(set_size(a) == 1000); @@ -334,7 +334,7 @@ void test_set(void) assert(set_is_empty(a)); // Add a lot of items and clear. for (int i = 5000; i < 6000; i++) { - stub_set_add(a, &i); + stub_set_put(a, &i); assert(stub_set_contains(a, &i)); } assert(set_size(a) == 1000); @@ -348,19 +348,19 @@ void test_set(void) // Create odd shape graph. a = set_init(sizeof(int), compare_int); int tmp = 10; - stub_set_add(a, &tmp); + stub_set_put(a, &tmp); tmp = 5; - stub_set_add(a, &tmp); + stub_set_put(a, &tmp); tmp = 15; - stub_set_add(a, &tmp); + stub_set_put(a, &tmp); tmp = 3; - stub_set_add(a, &tmp); + stub_set_put(a, &tmp); tmp = 8; - stub_set_add(a, &tmp); + stub_set_put(a, &tmp); tmp = 12; - stub_set_add(a, &tmp); + stub_set_put(a, &tmp); tmp = 18; - stub_set_add(a, &tmp); + stub_set_put(a, &tmp); tmp = 12; stub_set_remove(a, &tmp); tmp = 5; @@ -372,7 +372,7 @@ void test_set(void) stub_set_clear(a); // Allocate many nodes. for (int i = 8123; i < 12314; i += 3) { - stub_set_add(a, &i); + stub_set_put(a, &i); assert(stub_set_contains(a, &i)); } for (int i = 13000; i > 8000; i--) { @@ -382,31 +382,31 @@ void test_set(void) stub_set_clear(a); // Create another odd shape graph. tmp = 20; - stub_set_add(a, &tmp); + stub_set_put(a, &tmp); tmp = 10; - stub_set_add(a, &tmp); + stub_set_put(a, &tmp); tmp = 40; - stub_set_add(a, &tmp); + stub_set_put(a, &tmp); tmp = 5; - stub_set_add(a, &tmp); + stub_set_put(a, &tmp); tmp = 15; - stub_set_add(a, &tmp); + stub_set_put(a, &tmp); tmp = 30; - stub_set_add(a, &tmp); + stub_set_put(a, &tmp); tmp = 50; - stub_set_add(a, &tmp); + stub_set_put(a, &tmp); tmp = 25; - stub_set_add(a, &tmp); + stub_set_put(a, &tmp); tmp = 35; - stub_set_add(a, &tmp); + stub_set_put(a, &tmp); tmp = 36; - stub_set_add(a, &tmp); + stub_set_put(a, &tmp); tmp = 34; - stub_set_add(a, &tmp); + stub_set_put(a, &tmp); tmp = 33; - stub_set_add(a, &tmp); + stub_set_put(a, &tmp); tmp = 32; - stub_set_add(a, &tmp); + stub_set_put(a, &tmp); tmp = 30; stub_set_remove(a, &tmp); tmp = 32; @@ -414,13 +414,13 @@ void test_set(void) stub_set_clear(a); // One sided tree. tmp = 10; - stub_set_add(a, &tmp); + stub_set_put(a, &tmp); tmp = 9; - stub_set_add(a, &tmp); + stub_set_put(a, &tmp); tmp = 8; - stub_set_add(a, &tmp); + stub_set_put(a, &tmp); tmp = 7; - stub_set_add(a, &tmp); + stub_set_put(a, &tmp); tmp = 8; stub_set_remove(a, &tmp); tmp = 7; @@ -429,47 +429,47 @@ void test_set(void) // Replace two sided two children. a = set_init(sizeof(int), compare_int); b = 5; - stub_set_add(a, &b); + stub_set_put(a, &b); b = 1; - stub_set_add(a, &b); + stub_set_put(a, &b); b = 6; - stub_set_add(a, &b); + stub_set_put(a, &b); b = -1; - stub_set_add(a, &b); + stub_set_put(a, &b); b = 3; - stub_set_add(a, &b); + stub_set_put(a, &b); b = 7; - stub_set_add(a, &b); + stub_set_put(a, &b); b = -2; - stub_set_add(a, &b); + stub_set_put(a, &b); b = 0; - stub_set_add(a, &b); + stub_set_put(a, &b); b = 2; - stub_set_add(a, &b); + stub_set_put(a, &b); b = 4; - stub_set_add(a, &b); + stub_set_put(a, &b); b = 1; stub_set_remove(a, &b); assert(!stub_set_contains(a, &b)); stub_set_clear(a); b = 5; - stub_set_add(a, &b); + stub_set_put(a, &b); b = 1; - stub_set_add(a, &b); + stub_set_put(a, &b); b = 6; - stub_set_add(a, &b); + stub_set_put(a, &b); b = -1; - stub_set_add(a, &b); + stub_set_put(a, &b); b = 3; - stub_set_add(a, &b); + stub_set_put(a, &b); b = 7; - stub_set_add(a, &b); + stub_set_put(a, &b); b = -2; - stub_set_add(a, &b); + stub_set_put(a, &b); b = 0; - stub_set_add(a, &b); + stub_set_put(a, &b); b = 4; - stub_set_add(a, &b); + stub_set_put(a, &b); b = 1; stub_set_remove(a, &b); assert(!stub_set_contains(a, &b)); diff --git a/tst/test.c b/tst/test.c index eebedf6..fa8834f 100644 --- a/tst/test.c +++ b/tst/test.c @@ -2,17 +2,18 @@ int main(void) { - test_vector(); - test_list(); - test_forward_list(); - test_deque(); - test_stack(); - test_queue(); - test_set(); test_array(); + test_vector(); + test_deque(); + test_forward_list(); + test_list(); + test_set(); + test_multiset(); test_unordered_set(); test_unordered_map(); test_unordered_multiset(); test_unordered_multimap(); + test_stack(); + test_queue(); return 0; } diff --git a/tst/test.h b/tst/test.h index 0cf1e22..968dca0 100644 --- a/tst/test.h +++ b/tst/test.h @@ -5,17 +5,18 @@ #include #include -void test_vector(void); -void test_list(void); -void test_forward_list(void); -void test_deque(void); -void test_stack(void); -void test_queue(void); -void test_set(void); void test_array(void); +void test_vector(void); +void test_deque(void); +void test_forward_list(void); +void test_list(void); +void test_set(void); +void test_multiset(void); void test_unordered_set(void); void test_unordered_map(void); void test_unordered_multiset(void); void test_unordered_multimap(void); +void test_stack(void); +void test_queue(void); #endif /* CONTAINERS_TEST_H */