diff --git a/README.md b/README.md index 668a488..ce70370 100644 --- a/README.md +++ b/README.md @@ -288,3 +288,8 @@ You can use them as Stacks, Queues and Deques, but with modern memory hierarchy ### You can't structurally modify a collection when iterating over it Modifying a collection will possibly invalidate all iterators currently initialized by it. Currently, the only collection that allows this is the LinkedList (using the node-based functions, not the iterator). + +## Special Macros + +* `CMC_NO_ALLOC` - disables `"cor/alloc.h"` +* `CMC_NO_IMPORTS` - disables all imports from the standard library at `"cor/core.h"` diff --git a/src/cmc/bitset.h b/src/cmc/bitset.h new file mode 100644 index 0000000..4e7a890 --- /dev/null +++ b/src/cmc/bitset.h @@ -0,0 +1,88 @@ +/** + * Copyright (c) 2019 Leonardo Vencovsky + * + * This file is part of the C Macro Collections Libray. + * + * 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. + */ + +/** + * bitset.h + * + * Creation Date: 30/04/2020 + * + * Authors: + * Leonardo Vencovsky (https://github.com/LeoVen) + * + */ + +/** + * BitSet + * + * A Bit Set is an array where each bit can be individually modified and queried + * by using bitwise operators such as |, &, ^, ~, >> and << (or, and, xor, not, + * right shift, left shift respectively). + * + * Implementation + * + * This BitSet implementation uses an array of type cmc_bitset_word which can be + * typedefed to any unsigned type such as uint8_t, uint16_t, uint32_t, uint64_t, + * size_t, etc. The BitSet does not make use of K or V. Because of that, it also + * doesn't have Functions Tables. + * + * The BitSet is initialized with a custom capacity but, if a bit index accessed + * is greater than the total capacity, the BitSet will resize. This means that + * the BitSet will try to guarantee that every bit index is accessible, as long + * as there is enough memory. + */ + +#include "cor/bitset.h" +#include "cor/core.h" + +/** + * Used values + * SNAME - struct name and prefix of other related structs + * PFX - functions prefix + */ + +/* Structs definition */ +#include "cmc/bitset/struct.h" + +/* Function declaration */ +#include "cmc/bitset/header.h" + +/* Function implementation */ +#include "cmc/bitset/code.h" + +/** + * Extensions + * + * INIT - Initializes the struct on the stack + * ITER - bitset iterator + * STR - Print helper functions + */ +#define CMC_EXT_BITSET_PARTS INIT, ITER, STR +/**/ +#include "cmc/bitset/ext/struct.h" +/**/ +#include "cmc/bitset/ext/header.h" +/**/ +#include "cmc/bitset/ext/code.h" + +#include "cor/undef.h" diff --git a/src/cmc/cmc/bitset/code.h b/src/cmc/cmc/bitset/code.h new file mode 100644 index 0000000..dcecc08 --- /dev/null +++ b/src/cmc/cmc/bitset/code.h @@ -0,0 +1,431 @@ +/** + * Copyright (c) 2019 Leonardo Vencovsky + * + * This file is part of the C Macro Collections Libray. + * + * 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. + */ + +/* Implementation Detail Functions */ +bool CMC_(PFX, _impl_resize)(struct SNAME *_bitset_, size_t n_bits, bool do_resize); + +struct SNAME *CMC_(PFX, _new)(size_t n_bits) +{ + return CMC_(PFX, _new_custom)(n_bits, NULL, NULL); +} + +struct SNAME *CMC_(PFX, _new_custom)(size_t n_bits, struct CMC_ALLOC_NODE_NAME *alloc, + struct CMC_CALLBACKS_NAME *callbacks) +{ + CMC_CALLBACKS_MAYBE_UNUSED(callbacks); + + if (n_bits < 1) + return NULL; + + if (!alloc) + alloc = &cmc_alloc_node_default; + + size_t capacity = cmc_bidx_to_widx(n_bits - 1) + 1; + + struct SNAME *_bitset_ = alloc->malloc(sizeof(struct SNAME)); + + if (!_bitset_) + return NULL; + + _bitset_->buffer = alloc->calloc(capacity, sizeof(cmc_bitset_word)); + + if (!_bitset_->buffer) + { + alloc->free(_bitset_); + return NULL; + } + + _bitset_->capacity = capacity; + _bitset_->flag = CMC_FLAG_OK; + _bitset_->alloc = alloc; + CMC_CALLBACKS_ASSIGN(_bitset_, callbacks); + + return _bitset_; +} + +struct SNAME CMC_(PFX, _init)(size_t n_bits) +{ + return CMC_(PFX, _init_custom)(n_bits, NULL, NULL); +} + +struct SNAME CMC_(PFX, _init_custom)(size_t n_bits, struct CMC_ALLOC_NODE_NAME *alloc, + struct CMC_CALLBACKS_NAME *CMC_UNUSED(callbacks)) +{ + CMC_CALLBACKS_MAYBE_UNUSED(callbacks); + + struct SNAME _bitset_ = { 0 }; + + if (n_bits < 1) + return _bitset_; + + if (!alloc) + alloc = &cmc_alloc_node_default; + + size_t capacity = cmc_bidx_to_widx(n_bits - 1) + 1; + + _bitset_.buffer = alloc->calloc(capacity, sizeof(cmc_bitset_word)); + + if (!_bitset_.buffer) + return _bitset_; + + _bitset_.capacity = capacity; + _bitset_.flag = CMC_FLAG_OK; + _bitset_.alloc = alloc; + CMC_CALLBACKS_ASSIGN(&_bitset_, callbacks); + + return _bitset_; +} + +void CMC_(PFX, _free)(struct SNAME *_bitset_) +{ + free(_bitset_->buffer); + free(_bitset_); +} + +void CMC_(PFX, _release)(struct SNAME _bitset_) +{ + free(_bitset_.buffer); +} + +void CMC_(PFX, _customize)(struct SNAME *_bitset_, struct CMC_ALLOC_NODE_NAME *alloc, + struct CMC_CALLBACKS_NAME *callbacks) +{ + CMC_CALLBACKS_MAYBE_UNUSED(callbacks); + + if (!alloc) + _bitset_->alloc = &cmc_alloc_node_default; + else + _bitset_->alloc = alloc; + + CMC_CALLBACKS_ASSIGN(_bitset_, callbacks); + + _bitset_->flag = CMC_FLAG_OK; +} + +bool CMC_(PFX, _set)(struct SNAME *_bitset_, size_t bit_index) +{ + if (!CMC_(PFX, _impl_resize)(_bitset_, bit_index + 1, false)) + return false; + + /* How many bits in a word */ + const cmc_bitset_word bits = sizeof(cmc_bitset_word) * CHAR_BIT; + + size_t i = cmc_bidx_to_widx(bit_index); + + _bitset_->buffer[i] |= ((cmc_bitset_word)1) << (bit_index % bits); + + _bitset_->flag = CMC_FLAG_OK; + + CMC_CALLBACKS_CALL(_bitset_, create); + + return true; +} + +bool CMC_(PFX, _set_range)(struct SNAME *_bitset_, size_t from, size_t to) +{ + if (to < from) + { + _bitset_->flag = CMC_FLAG_INVALID; + return false; + } + + if (!CMC_(PFX, _impl_resize)(_bitset_, to + 1, false)) + return false; + + size_t start_index = cmc_bidx_to_widx(from); + size_t end_index = cmc_bidx_to_widx(to); + + /* How many bits in a word */ + const cmc_bitset_word bits = sizeof(cmc_bitset_word) * CHAR_BIT; + + /* 1111 ... 1111 */ + const cmc_bitset_word ones = ~((cmc_bitset_word)0); + + cmc_bitset_word shift_start = from % bits; + cmc_bitset_word shift_end = (cmc_bitset_word)(-(to + 1)) % bits; + + cmc_bitset_word start_mask = ones << shift_start; + cmc_bitset_word end_mask = ones >> shift_end; + + if (start_index == end_index) + { + _bitset_->buffer[end_index] |= (start_mask & end_mask); + } + else + { + _bitset_->buffer[start_index] |= start_mask; + + for (size_t i = start_index + 1; i < end_index; i++) + _bitset_->buffer[i] |= ~((cmc_bitset_word)0); + + _bitset_->buffer[end_index] |= end_mask; + } + + _bitset_->flag = CMC_FLAG_OK; + + CMC_CALLBACKS_CALL(_bitset_, create); + + return true; +} + +bool CMC_(PFX, _clear)(struct SNAME *_bitset_, size_t bit_index) +{ + if (!CMC_(PFX, _impl_resize)(_bitset_, bit_index + 1, false)) + return false; + + /* How many bits in a word */ + const cmc_bitset_word bits = sizeof(cmc_bitset_word) * CHAR_BIT; + + size_t i = cmc_bidx_to_widx(bit_index); + + _bitset_->buffer[i] &= ~(((cmc_bitset_word)1) << (bit_index % bits)); + + _bitset_->flag = CMC_FLAG_OK; + + CMC_CALLBACKS_CALL(_bitset_, delete); + + return true; +} + +bool CMC_(PFX, _clear_range)(struct SNAME *_bitset_, size_t from, size_t to) +{ + if (to < from) + { + _bitset_->flag = CMC_FLAG_INVALID; + return false; + } + + if (!CMC_(PFX, _impl_resize)(_bitset_, to + 1, false)) + return false; + + size_t start_index = cmc_bidx_to_widx(from); + size_t end_index = cmc_bidx_to_widx(to); + + /* How many bits in a word */ + const cmc_bitset_word bits = sizeof(cmc_bitset_word) * CHAR_BIT; + + /* 1111 ... 1111 */ + const cmc_bitset_word ones = ~((cmc_bitset_word)0); + + cmc_bitset_word shift_start = from % bits; + cmc_bitset_word shift_end = (cmc_bitset_word)(-(to + 1)) % bits; + + cmc_bitset_word start_mask = ones << shift_start; + cmc_bitset_word end_mask = ones >> shift_end; + + if (start_index == end_index) + { + _bitset_->buffer[end_index] &= ~(start_mask & end_mask); + } + else + { + _bitset_->buffer[start_index] &= ~start_mask; + + for (size_t i = start_index + 1; i < end_index; i++) + _bitset_->buffer[i] = 0; + + _bitset_->buffer[end_index] &= ~end_mask; + } + + _bitset_->flag = CMC_FLAG_OK; + + CMC_CALLBACKS_CALL(_bitset_, delete); + + return true; +} + +bool CMC_(PFX, _flip)(struct SNAME *_bitset_, size_t bit_index) +{ + if (!CMC_(PFX, _impl_resize)(_bitset_, bit_index + 1, false)) + return false; + + /* How many bits in a word */ + const cmc_bitset_word bits = sizeof(cmc_bitset_word) * CHAR_BIT; + + size_t i = cmc_bidx_to_widx(bit_index); + + _bitset_->buffer[i] ^= ((cmc_bitset_word)1) << (bit_index % bits); + + _bitset_->flag = CMC_FLAG_OK; + + CMC_CALLBACKS_CALL(_bitset_, update); + + return true; +} + +bool CMC_(PFX, _flip_range)(struct SNAME *_bitset_, size_t from, size_t to) +{ + if (to < from) + { + _bitset_->flag = CMC_FLAG_INVALID; + return false; + } + + if (!CMC_(PFX, _impl_resize)(_bitset_, to + 1, false)) + return false; + + size_t start_index = cmc_bidx_to_widx(from); + size_t end_index = cmc_bidx_to_widx(to); + + /* How many bits in a word */ + const cmc_bitset_word bits = sizeof(cmc_bitset_word) * CHAR_BIT; + + /* 1111 ... 1111 */ + const cmc_bitset_word ones = ~((cmc_bitset_word)0); + + cmc_bitset_word shift_start = from % bits; + cmc_bitset_word shift_end = (cmc_bitset_word)(-(to + 1)) % bits; + + cmc_bitset_word start_mask = ones << shift_start; + cmc_bitset_word end_mask = ones >> shift_end; + + if (start_index == end_index) + { + _bitset_->buffer[end_index] ^= (start_mask & end_mask); + } + else + { + _bitset_->buffer[start_index] ^= start_mask; + + for (size_t i = start_index + 1; i < end_index; i++) + _bitset_->buffer[i] ^= ones; + + _bitset_->buffer[end_index] ^= end_mask; + } + + _bitset_->flag = CMC_FLAG_OK; + + CMC_CALLBACKS_CALL(_bitset_, update); + + return true; +} + +bool CMC_(PFX, _put)(struct SNAME *_bitset_, size_t bit_index, bool state) +{ + if (state) + return CMC_(PFX, _set)(_bitset_, bit_index); + else + return CMC_(PFX, _clear)(_bitset_, bit_index); +} + +bool CMC_(PFX, _put_range)(struct SNAME *_bitset_, size_t from, size_t to, bool state) +{ + if (state) + return CMC_(PFX, _set_range)(_bitset_, from, to); + else + return CMC_(PFX, _clear_range)(_bitset_, from, to); +} + +bool CMC_(PFX, _set_all)(struct SNAME *_bitset_) +{ + for (size_t i = 0; i < _bitset_->capacity; i++) + _bitset_->buffer[i] = ~((cmc_bitset_word)0); + + _bitset_->flag = CMC_FLAG_OK; + + CMC_CALLBACKS_CALL(_bitset_, create); + + return true; +} + +bool CMC_(PFX, _clear_all)(struct SNAME *_bitset_) +{ + for (size_t i = 0; i < _bitset_->capacity; i++) + _bitset_->buffer[i] = 0; + + _bitset_->flag = CMC_FLAG_OK; + + CMC_CALLBACKS_CALL(_bitset_, delete); + + return true; +} + +bool CMC_(PFX, _flip_all)(struct SNAME *_bitset_) +{ + for (size_t i = 0; i < _bitset_->capacity; i++) + _bitset_->buffer[i] ^= ~((cmc_bitset_word)0); + + _bitset_->flag = CMC_FLAG_OK; + + CMC_CALLBACKS_CALL(_bitset_, create); + + return true; +} + +bool CMC_(PFX, _get)(struct SNAME *_bitset_, size_t bit_index) +{ + /* How many bits in a word */ + const cmc_bitset_word bits = sizeof(cmc_bitset_word) * CHAR_BIT; + + cmc_bitset_word w = _bitset_->buffer[cmc_bidx_to_widx(bit_index)]; + + return w & ((cmc_bitset_word)1 << (bit_index % bits)); +} + +bool CMC_(PFX, _resize)(struct SNAME *_bitset_, size_t n_bits) +{ + return CMC_(PFX, _impl_resize)(_bitset_, n_bits, true); +} + +/* When do_resize is false, then we just want to assure that the bitset */ +/* can accommodate n_bits */ +bool CMC_(PFX, _impl_resize)(struct SNAME *_bitset_, size_t n_bits, bool do_resize) +{ + if (n_bits == 0) + { + _bitset_->flag = CMC_FLAG_INVALID; + return false; + } + + /* -1 because n_bits is 1-based and we need to pass a 0-based index */ + /* +1 to have a 1-based result */ + size_t words = cmc_bidx_to_widx(n_bits - 1) + 1; + + /* Be sure we are not always shrinking when we just want to make */ + /* sure that we have enough size for n_bits */ + if (!do_resize && words <= _bitset_->capacity) + return true; + + cmc_bitset_word *new_buffer = realloc(_bitset_->buffer, words * sizeof(cmc_bitset_word)); + + if (!new_buffer) + { + _bitset_->flag = CMC_FLAG_ALLOC; + return false; + } + + _bitset_->buffer = new_buffer; + + /* Make new bits be all zeroes */ + if (_bitset_->capacity < words) + memset(_bitset_->buffer + _bitset_->capacity, 0, (words - _bitset_->capacity) * sizeof(cmc_bitset_word)); + + _bitset_->capacity = words; + + CMC_CALLBACKS_CALL(_bitset_, resize); + + _bitset_->flag = CMC_FLAG_OK; + + return true; +} diff --git a/src/cmc/cmc/bitset/ext/code.h b/src/cmc/cmc/bitset/ext/code.h new file mode 100644 index 0000000..024f8fa --- /dev/null +++ b/src/cmc/cmc/bitset/ext/code.h @@ -0,0 +1,57 @@ +/** + * Copyright (c) 2019 Leonardo Vencovsky + * + * This file is part of the C Macro Collections Libray. + * + * 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. + */ + +/** + * INIT + * + * The part 'INIT' gives a new way of initializing a collection. The collection + * struct is not heap allocated, only its internal structure (nodes, buffers). + */ +#ifdef CMC_EXT_BITSET_INIT + +#endif /* CMC_EXT_BITSET_INIT */ + +/** + * ITER + * + * Bitset bi-directional iterator. + */ +#ifdef CMC_EXT_BITSET_ITER + +/* Iterator Functions */ +/* Iterator Initialization */ +/* Iterator State */ +/* Iterator Movement */ +/* Iterator Access */ + +#endif /* CMC_EXT_BITSET_ITER */ + +/** + * STR + * + * Print helper functions. + */ +#ifdef CMC_EXT_BITSET_STR + +#endif /* CMC_EXT_BITSET_STR */ diff --git a/src/cmc/cmc/bitset/ext/header.h b/src/cmc/cmc/bitset/ext/header.h new file mode 100644 index 0000000..024f8fa --- /dev/null +++ b/src/cmc/cmc/bitset/ext/header.h @@ -0,0 +1,57 @@ +/** + * Copyright (c) 2019 Leonardo Vencovsky + * + * This file is part of the C Macro Collections Libray. + * + * 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. + */ + +/** + * INIT + * + * The part 'INIT' gives a new way of initializing a collection. The collection + * struct is not heap allocated, only its internal structure (nodes, buffers). + */ +#ifdef CMC_EXT_BITSET_INIT + +#endif /* CMC_EXT_BITSET_INIT */ + +/** + * ITER + * + * Bitset bi-directional iterator. + */ +#ifdef CMC_EXT_BITSET_ITER + +/* Iterator Functions */ +/* Iterator Initialization */ +/* Iterator State */ +/* Iterator Movement */ +/* Iterator Access */ + +#endif /* CMC_EXT_BITSET_ITER */ + +/** + * STR + * + * Print helper functions. + */ +#ifdef CMC_EXT_BITSET_STR + +#endif /* CMC_EXT_BITSET_STR */ diff --git a/src/cmc/cmc/bitset/ext/struct.h b/src/cmc/cmc/bitset/ext/struct.h new file mode 100644 index 0000000..12b3db3 --- /dev/null +++ b/src/cmc/cmc/bitset/ext/struct.h @@ -0,0 +1,45 @@ +/** + * Copyright (c) 2019 Leonardo Vencovsky + * + * This file is part of the C Macro Collections Libray. + * + * 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. + */ + +/** + * ITER + * + * Bitset bi-directional iterator. + */ +#ifdef CMC_EXT_BITSET_ITER + +/* BitSet Iterator */ +struct CMC_DEF_ITER(SNAME) +{ + /* Target bitset */ + struct SNAME *target; + /* Cursor's position (index) */ + size_t cursor; + /* If the iterator has reached the start of the iteration */ + bool start; + /* If the iterator has reached the end of the iteration */ + bool end; +}; + +#endif /* CMC_EXT_BITSET_ITER */ diff --git a/src/cmc/cmc/bitset/header.h b/src/cmc/cmc/bitset/header.h new file mode 100644 index 0000000..9d3ab53 --- /dev/null +++ b/src/cmc/cmc/bitset/header.h @@ -0,0 +1,52 @@ +/** + * Copyright (c) 2019 Leonardo Vencovsky + * + * This file is part of the C Macro Collections Libray. + * + * 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. + */ + +/* Collection Allocation and Deallocation */ +struct SNAME *CMC_(PFX, _new)(size_t n_bits); +struct SNAME *CMC_(PFX, _new_custom)(size_t n_bits, struct CMC_ALLOC_NODE_NAME *alloc, + struct CMC_CALLBACKS_NAME *callbacks); +struct SNAME CMC_(PFX, _init)(size_t n_bits); +struct SNAME CMC_(PFX, _init_custom)(size_t n_bits, struct CMC_ALLOC_NODE_NAME *alloc, + struct CMC_CALLBACKS_NAME *callbacks); +void CMC_(PFX, _free)(struct SNAME *_bitset_); +void CMC_(PFX, _release)(struct SNAME _bitset_); +void CMC_(PFX, _customize)(struct SNAME *_bitset_, struct CMC_ALLOC_NODE_NAME *alloc, + struct CMC_CALLBACKS_NAME *callbacks); +/* Collection Input and Output */ +bool CMC_(PFX, _set)(struct SNAME *_bitset_, size_t bit_index); +bool CMC_(PFX, _set_range)(struct SNAME *_bitset_, size_t from, size_t to); +bool CMC_(PFX, _clear)(struct SNAME *_bitset_, size_t bit_index); +bool CMC_(PFX, _clear_range)(struct SNAME *_bitset_, size_t from, size_t to); +bool CMC_(PFX, _flip)(struct SNAME *_bitset_, size_t bit_index); +bool CMC_(PFX, _flip_range)(struct SNAME *_bitset_, size_t from, size_t to); +bool CMC_(PFX, _put)(struct SNAME *_bitset_, size_t bit_index, bool state); +bool CMC_(PFX, _put_range)(struct SNAME *_bitset_, size_t from, size_t to, bool state); +bool CMC_(PFX, _set_all)(struct SNAME *_bitset_); +bool CMC_(PFX, _clear_all)(struct SNAME *_bitset_); +bool CMC_(PFX, _flip_all)(struct SNAME *_bitset_); +/* Element Access */ +bool CMC_(PFX, _get)(struct SNAME *_bitset_, size_t bit_index); +/* Collection State */ +/* Collection Utility */ +bool CMC_(PFX, _resize)(struct SNAME *_bitset_, size_t n_bits); diff --git a/src/cmc/cmc/bitset/struct.h b/src/cmc/cmc/bitset/struct.h new file mode 100644 index 0000000..f5e7d98 --- /dev/null +++ b/src/cmc/cmc/bitset/struct.h @@ -0,0 +1,42 @@ +/** + * Copyright (c) 2019 Leonardo Vencovsky + * + * This file is part of the C Macro Collections Libray. + * + * 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. + */ + +/* BitSet Structure */ +struct SNAME +{ + /* Dynamic Array of Bits */ + cmc_bitset_word *buffer; + /* Current array capacity */ + size_t capacity; + /* Currently used bits */ + /* This should always be true: */ + /* capacity - count < sizeof(cmc_bitset_word) * CHAR_BIT */ + size_t count; + /* Flags indicating errors or success */ + int flag; + /* Custom allocation functions */ + struct CMC_ALLOC_NODE_NAME *alloc; + /* Custom callback functions */ + CMC_CALLBACKS_DECL; +}; diff --git a/src/cmc/cmc/heap/code.h b/src/cmc/cmc/heap/code.h new file mode 100644 index 0000000..aea0b31 --- /dev/null +++ b/src/cmc/cmc/heap/code.h @@ -0,0 +1,362 @@ +/** + * Copyright (c) 2019 Leonardo Vencovsky + * + * This file is part of the C Macro Collections Libray. + * + * 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. + */ + +/* Implementation Detail Functions */ +static void CMC_(PFX, _impl_float_up)(struct SNAME *_heap_, size_t index); +static void CMC_(PFX, _impl_float_down)(struct SNAME *_heap_, size_t index); + +struct SNAME *CMC_(PFX, _new)(size_t capacity, enum cmc_heap_order HO, struct CMC_DEF_FVAL(SNAME) * f_val) +{ + return CMC_(PFX, _new_custom)(capacity, HO, f_val, NULL, NULL); +} + +struct SNAME *CMC_(PFX, _new_custom)(size_t capacity, enum cmc_heap_order HO, struct CMC_DEF_FVAL(SNAME) * f_val, + struct CMC_ALLOC_NODE_NAME *alloc, struct CMC_CALLBACKS_NAME *callbacks) +{ + CMC_CALLBACKS_MAYBE_UNUSED(callbacks); + + if (capacity < 1) + return NULL; + + if (HO != CMC_MIN_HEAP && HO != CMC_MAX_HEAP) + return NULL; + + if (!f_val) + return NULL; + + if (!alloc) + alloc = &cmc_alloc_node_default; + + struct SNAME *_heap_ = alloc->malloc(sizeof(struct SNAME)); + + if (!_heap_) + return NULL; + + _heap_->buffer = alloc->calloc(capacity, sizeof(V)); + + if (!_heap_->buffer) + { + alloc->free(_heap_); + return NULL; + } + + _heap_->capacity = capacity; + _heap_->count = 0; + _heap_->HO = HO; + _heap_->flag = CMC_FLAG_OK; + _heap_->f_val = f_val; + _heap_->alloc = alloc; + CMC_CALLBACKS_ASSIGN(_heap_, callbacks); + + return _heap_; +} + +void CMC_(PFX, _clear)(struct SNAME *_heap_) +{ + if (_heap_->f_val->free) + { + for (size_t i = 0; i < _heap_->count; i++) + { + _heap_->f_val->free(_heap_->buffer[i]); + } + } + + memset(_heap_->buffer, 0, sizeof(V) * _heap_->capacity); + + _heap_->count = 0; + _heap_->flag = CMC_FLAG_OK; +} + +void CMC_(PFX, _free)(struct SNAME *_heap_) +{ + if (_heap_->f_val->free) + { + for (size_t i = 0; i < _heap_->count; i++) + { + _heap_->f_val->free(_heap_->buffer[i]); + } + } + + _heap_->alloc->free(_heap_->buffer); + _heap_->alloc->free(_heap_); +} + +void CMC_(PFX, _customize)(struct SNAME *_heap_, struct CMC_ALLOC_NODE_NAME *alloc, + struct CMC_CALLBACKS_NAME *callbacks) +{ + CMC_CALLBACKS_MAYBE_UNUSED(callbacks); + + if (!alloc) + _heap_->alloc = &cmc_alloc_node_default; + else + _heap_->alloc = alloc; + + CMC_CALLBACKS_ASSIGN(_heap_, callbacks); + + _heap_->flag = CMC_FLAG_OK; +} + +bool CMC_(PFX, _insert)(struct SNAME *_heap_, V value) +{ + if (CMC_(PFX, _full)(_heap_)) + { + if (!CMC_(PFX, _resize)(_heap_, _heap_->count * 2)) + return false; + } + + _heap_->buffer[_heap_->count++] = value; + + if (_heap_->count > 1) + { + CMC_(PFX, _impl_float_up)(_heap_, _heap_->count - 1); + } + + _heap_->flag = CMC_FLAG_OK; + + CMC_CALLBACKS_CALL(_heap_, create); + + return true; +} + +bool CMC_(PFX, _remove)(struct SNAME *_heap_) +{ + if (CMC_(PFX, _empty)(_heap_)) + { + _heap_->flag = CMC_FLAG_EMPTY; + return false; + } + + _heap_->buffer[0] = _heap_->buffer[_heap_->count - 1]; + _heap_->buffer[_heap_->count - 1] = (V){ 0 }; + + _heap_->count--; + + CMC_(PFX, _impl_float_down)(_heap_, 0); + + _heap_->flag = CMC_FLAG_OK; + + CMC_CALLBACKS_CALL(_heap_, delete); + + return true; +} + +V CMC_(PFX, _peek)(struct SNAME *_heap_) +{ + if (CMC_(PFX, _empty)(_heap_)) + { + _heap_->flag = CMC_FLAG_EMPTY; + return (V){ 0 }; + } + + _heap_->flag = CMC_FLAG_OK; + + CMC_CALLBACKS_CALL(_heap_, read); + + return _heap_->buffer[0]; +} + +bool CMC_(PFX, _contains)(struct SNAME *_heap_, V value) +{ + _heap_->flag = CMC_FLAG_OK; + + bool result = false; + + for (size_t i = 0; i < _heap_->count; i++) + { + if (_heap_->f_val->cmp(_heap_->buffer[i], value) == 0) + { + result = true; + break; + } + } + + CMC_CALLBACKS_CALL(_heap_, read); + + return result; +} + +bool CMC_(PFX, _empty)(struct SNAME *_heap_) +{ + return _heap_->count == 0; +} + +bool CMC_(PFX, _full)(struct SNAME *_heap_) +{ + return _heap_->count >= _heap_->capacity; +} + +size_t CMC_(PFX, _count)(struct SNAME *_heap_) +{ + return _heap_->count; +} + +size_t CMC_(PFX, _capacity)(struct SNAME *_heap_) +{ + return _heap_->capacity; +} + +int CMC_(PFX, _flag)(struct SNAME *_heap_) +{ + return _heap_->flag; +} + +bool CMC_(PFX, _resize)(struct SNAME *_heap_, size_t capacity) +{ + _heap_->flag = CMC_FLAG_OK; + + if (_heap_->capacity == capacity) + goto success; + + if (capacity < _heap_->count) + { + _heap_->flag = CMC_FLAG_INVALID; + return false; + } + + V *new_buffer = _heap_->alloc->realloc(_heap_->buffer, sizeof(V) * capacity); + + if (!new_buffer) + { + _heap_->flag = CMC_FLAG_ALLOC; + return false; + } + + /* TODO zero out new slots */ + + _heap_->buffer = new_buffer; + _heap_->capacity = capacity; + +success: + + CMC_CALLBACKS_CALL(_heap_, resize); + + return true; +} + +struct SNAME *CMC_(PFX, _copy_of)(struct SNAME *_heap_) +{ + struct SNAME *result = CMC_(PFX, _new_custom)(_heap_->capacity, _heap_->HO, _heap_->f_val, _heap_->alloc, NULL); + + if (!result) + { + _heap_->flag = CMC_FLAG_ERROR; + return NULL; + } + + CMC_CALLBACKS_ASSIGN(result, _heap_->callbacks); + + if (_heap_->f_val->cpy) + { + for (size_t i = 0; i < _heap_->count; i++) + result->buffer[i] = _heap_->f_val->cpy(_heap_->buffer[i]); + } + else + memcpy(result->buffer, _heap_->buffer, sizeof(V) * _heap_->count); + + result->count = _heap_->count; + + _heap_->flag = CMC_FLAG_OK; + + return result; +} + +bool CMC_(PFX, _equals)(struct SNAME *_heap1_, struct SNAME *_heap2_) +{ + _heap1_->flag = CMC_FLAG_OK; + _heap2_->flag = CMC_FLAG_OK; + + if (_heap1_->count != _heap2_->count) + return false; + + for (size_t i = 0; i < _heap1_->count; i++) + { + if (_heap1_->f_val->cmp(_heap1_->buffer[i], _heap2_->buffer[i]) != 0) + return false; + } + + return true; +} + +static void CMC_(PFX, _impl_float_up)(struct SNAME *_heap_, size_t index) +{ + /* Current index */ + size_t C = index; + V child = _heap_->buffer[C]; + V parent = _heap_->buffer[(index - 1) / 2]; + + int mod = _heap_->HO; + + while (C > 0 && _heap_->f_val->cmp(child, parent) * mod > 0) + { + /* Swap between C (current element) and its parent */ + V tmp = _heap_->buffer[C]; + _heap_->buffer[C] = _heap_->buffer[(C - 1) / 2]; + _heap_->buffer[(C - 1) / 2] = tmp; + + /* Go to parent */ + C = (C - 1) / 2; + + /* Prevent the two lines below from accessing a negative index */ + if (C == 0) + break; + + child = _heap_->buffer[C]; + parent = _heap_->buffer[(C - 1) / 2]; + } +} + +static void CMC_(PFX, _impl_float_down)(struct SNAME *_heap_, size_t index) +{ + int mod = _heap_->HO; + + while (index < _heap_->count) + { + size_t L = 2 * index + 1; + size_t R = 2 * index + 2; + size_t C = index; + + /* Determine if we swap with the left or right element */ + if (L < _heap_->count && _heap_->f_val->cmp(_heap_->buffer[L], _heap_->buffer[C]) * mod > 0) + { + C = L; + } + + if (R < _heap_->count && _heap_->f_val->cmp(_heap_->buffer[R], _heap_->buffer[C]) * mod > 0) + { + C = R; + } + + /* Swap only if either left or right was picked, otherwise done */ + if (C != index) + { + V tmp = _heap_->buffer[index]; + _heap_->buffer[index] = _heap_->buffer[C]; + _heap_->buffer[C] = tmp; + + index = C; + } + else + break; + } +} diff --git a/src/cmc/cmc/heap/ext/code.h b/src/cmc/cmc/heap/ext/code.h new file mode 100644 index 0000000..5235aaf --- /dev/null +++ b/src/cmc/cmc/heap/ext/code.h @@ -0,0 +1,265 @@ +/** + * Copyright (c) 2019 Leonardo Vencovsky + * + * This file is part of the C Macro Collections Libray. + * + * 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. + */ + +/** + * INIT + * + * The part 'INIT' gives a new way of initializing a collection. The collection + * struct is not heap allocated, only its internal structure (nodes, buffers). + */ +#ifdef CMC_EXT_HEAP_INIT + +#endif /* CMC_EXT_HEAP_INIT */ + +/** + * ITER + * + * Heap bi-directional iterator. + */ +#ifdef CMC_EXT_HEAP_ITER + +struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_start)(struct SNAME *target) +{ + struct CMC_DEF_ITER(SNAME) iter; + + iter.target = target; + iter.cursor = 0; + iter.start = true; + iter.end = CMC_(PFX, _empty)(target); + + return iter; +} + +struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_end)(struct SNAME *target) +{ + struct CMC_DEF_ITER(SNAME) iter; + + iter.target = target; + iter.cursor = 0; + iter.start = CMC_(PFX, _empty)(target); + iter.end = true; + + if (!CMC_(PFX, _empty)(target)) + iter.cursor = target->count - 1; + + return iter; +} + +bool CMC_(PFX, _iter_at_start)(struct CMC_DEF_ITER(SNAME) * iter) +{ + return CMC_(PFX, _empty)(iter->target) || iter->start; +} + +bool CMC_(PFX, _iter_at_end)(struct CMC_DEF_ITER(SNAME) * iter) +{ + return CMC_(PFX, _empty)(iter->target) || iter->end; +} + +bool CMC_(PFX, _iter_to_start)(struct CMC_DEF_ITER(SNAME) * iter) +{ + if (!CMC_(PFX, _empty)(iter->target)) + { + iter->cursor = 0; + iter->start = true; + iter->end = CMC_(PFX, _empty)(iter->target); + + return true; + } + + return false; +} + +bool CMC_(PFX, _iter_to_end)(struct CMC_DEF_ITER(SNAME) * iter) +{ + if (!CMC_(PFX, _empty)(iter->target)) + { + iter->cursor = iter->target->count - 1; + iter->start = CMC_(PFX, _empty)(iter->target); + iter->end = true; + + return true; + } + + return false; +} + +bool CMC_(PFX, _iter_next)(struct CMC_DEF_ITER(SNAME) * iter) +{ + if (iter->end) + return false; + + if (iter->cursor + 1 == iter->target->count) + { + iter->end = true; + return false; + } + + iter->start = CMC_(PFX, _empty)(iter->target); + + iter->cursor++; + + return true; +} + +bool CMC_(PFX, _iter_prev)(struct CMC_DEF_ITER(SNAME) * iter) +{ + if (iter->start) + return false; + + if (iter->cursor == 0) + { + iter->start = true; + return false; + } + + iter->end = CMC_(PFX, _empty)(iter->target); + + iter->cursor--; + + return true; +} + +/* Returns true only if the iterator moved */ +bool CMC_(PFX, _iter_advance)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps) +{ + if (iter->end) + return false; + + if (iter->cursor + 1 == iter->target->count) + { + iter->end = true; + return false; + } + + if (steps == 0 || iter->cursor + steps >= iter->target->count) + return false; + + if (iter->end) + return false; + + iter->start = CMC_(PFX, _empty)(iter->target); + + iter->cursor += steps; + + return true; +} + +/* Returns true only if the iterator moved */ +bool CMC_(PFX, _iter_rewind)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps) +{ + if (iter->start) + return false; + + if (iter->cursor == 0) + { + iter->start = true; + return false; + } + + if (steps == 0 || iter->cursor < steps) + return false; + + iter->end = CMC_(PFX, _empty)(iter->target); + + iter->cursor -= steps; + + return true; +} + +/* Returns true only if the iterator was able to be positioned at the */ +/* given index */ +bool CMC_(PFX, _iter_go_to)(struct CMC_DEF_ITER(SNAME) * iter, size_t index) +{ + if (index >= iter->target->count) + return false; + + if (iter->cursor > index) + return CMC_(PFX, _iter_rewind)(iter, iter->cursor - index); + else if (iter->cursor < index) + return CMC_(PFX, _iter_advance)(iter, index - iter->cursor); + + return true; +} + +V CMC_(PFX, _iter_value)(struct CMC_DEF_ITER(SNAME) * iter) +{ + if (CMC_(PFX, _empty)(iter->target)) + return (V){ 0 }; + + return iter->target->buffer[iter->cursor]; +} + +size_t CMC_(PFX, _iter_index)(struct CMC_DEF_ITER(SNAME) * iter) +{ + return iter->cursor; +} + +#endif /* CMC_EXT_HEAP_ITER */ + +/** + * STR + * + * Print helper functions. + */ +#ifdef CMC_EXT_HEAP_STR + +bool CMC_(PFX, _to_string)(struct SNAME *_heap_, FILE *fptr) +{ + struct SNAME *h_ = _heap_; + const char *t = h_->HO == 1 ? "MaxHeap" : "MinHeap"; + + return 0 <= fprintf(fptr, + "struct %s<%s> " + "at %p { " + "buffer:%p, " + "capacity:%" PRIuMAX ", " + "count:%" PRIuMAX ", " + "type:%s, " + "flag:%d, " + "f_val:%p, " + "alloc:%p, " + "callbacks: %p}", + CMC_TO_STRING(SNAME), CMC_TO_STRING(V), h_, h_->buffer, h_->capacity, h_->count, t, h_->flag, + h_->f_val, h_->alloc, CMC_CALLBACKS_GET(h_)); +} + +bool CMC_(PFX, _print)(struct SNAME *_heap_, FILE *fptr, const char *start, const char *separator, const char *end) +{ + fprintf(fptr, "%s", start); + + for (size_t i = 0; i < _heap_->count; i++) + { + if (!_heap_->f_val->str(fptr, _heap_->buffer[i])) + return false; + + if (i + 1 < _heap_->count) + fprintf(fptr, "%s", separator); + } + + fprintf(fptr, "%s", end); + + return true; +} + +#endif /* CMC_EXT_HEAP_STR */ diff --git a/src/cmc/cmc/heap/ext/header.h b/src/cmc/cmc/heap/ext/header.h new file mode 100644 index 0000000..5c69ee7 --- /dev/null +++ b/src/cmc/cmc/heap/ext/header.h @@ -0,0 +1,72 @@ +/** + * Copyright (c) 2019 Leonardo Vencovsky + * + * This file is part of the C Macro Collections Libray. + * + * 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. + */ + +/** + * INIT + * + * The part 'INIT' gives a new way of initializing a collection. The collection + * struct is not heap allocated, only its internal structure (nodes, buffers). + */ +#ifdef CMC_EXT_HEAP_INIT + +#endif /* CMC_EXT_HEAP_INIT */ + +/** + * ITER + * + * Heap bi-directional iterator. + */ +#ifdef CMC_EXT_HEAP_ITER + +/* Iterator Initialization */ +struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_start)(struct SNAME *target); +struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_end)(struct SNAME *target); +/* Iterator State */ +bool CMC_(PFX, _iter_at_start)(struct CMC_DEF_ITER(SNAME) * iter); +bool CMC_(PFX, _iter_at_end)(struct CMC_DEF_ITER(SNAME) * iter); +/* Iterator Movement */ +bool CMC_(PFX, _iter_to_start)(struct CMC_DEF_ITER(SNAME) * iter); +bool CMC_(PFX, _iter_to_end)(struct CMC_DEF_ITER(SNAME) * iter); +bool CMC_(PFX, _iter_next)(struct CMC_DEF_ITER(SNAME) * iter); +bool CMC_(PFX, _iter_prev)(struct CMC_DEF_ITER(SNAME) * iter); +bool CMC_(PFX, _iter_advance)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps); +bool CMC_(PFX, _iter_rewind)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps); +bool CMC_(PFX, _iter_go_to)(struct CMC_DEF_ITER(SNAME) * iter, size_t index); +/* Iterator Access */ +V CMC_(PFX, _iter_value)(struct CMC_DEF_ITER(SNAME) * iter); +size_t CMC_(PFX, _iter_index)(struct CMC_DEF_ITER(SNAME) * iter); + +#endif /* CMC_EXT_HEAP_ITER */ + +/** + * STR + * + * Print helper functions. + */ +#ifdef CMC_EXT_HEAP_STR + +bool CMC_(PFX, _to_string)(struct SNAME *_heap_, FILE *fptr); +bool CMC_(PFX, _print)(struct SNAME *_heap_, FILE *fptr, const char *start, const char *separator, const char *end); + +#endif /* CMC_EXT_HEAP_STR */ diff --git a/src/cmc/cmc/heap/ext/struct.h b/src/cmc/cmc/heap/ext/struct.h new file mode 100644 index 0000000..8433eba --- /dev/null +++ b/src/cmc/cmc/heap/ext/struct.h @@ -0,0 +1,45 @@ +/** + * Copyright (c) 2019 Leonardo Vencovsky + * + * This file is part of the C Macro Collections Libray. + * + * 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. + */ + +/** + * ITER + * + * Heap bi-directional iterator. + */ +#ifdef CMC_EXT_HEAP_ITER + +/* Heap Iterator */ +struct CMC_DEF_ITER(SNAME) +{ + /* Target heap */ + struct SNAME *target; + /* Cursor's position (index) */ + size_t cursor; + /* If the iterator has reached the start of the iteration */ + bool start; + /* If the iterator has reached the end of the iteration */ + bool end; +}; + +#endif /* CMC_EXT_HEAP_ITER */ diff --git a/src/cmc/cmc/heap/header.h b/src/cmc/cmc/heap/header.h new file mode 100644 index 0000000..29ef3a8 --- /dev/null +++ b/src/cmc/cmc/heap/header.h @@ -0,0 +1,66 @@ +/** + * Copyright (c) 2019 Leonardo Vencovsky + * + * This file is part of the C Macro Collections Libray. + * + * 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. + */ + +/* Value struct function table */ +struct CMC_DEF_FVAL(SNAME) +{ + /* Comparator function */ + CMC_DEF_FTAB_CMP(V); + /* Copy function */ + CMC_DEF_FTAB_CPY(V); + /* To string function */ + CMC_DEF_FTAB_STR(V); + /* Free from memory function */ + CMC_DEF_FTAB_FREE(V); + /* Hash function */ + CMC_DEF_FTAB_HASH(V); + /* Priority function */ + CMC_DEF_FTAB_PRI(V); +}; + +/* Collection Allocation and Deallocation */ +struct SNAME *CMC_(PFX, _new)(size_t capacity, enum cmc_heap_order HO, struct CMC_DEF_FVAL(SNAME) * f_val); +struct SNAME *CMC_(PFX, _new_custom)(size_t capacity, enum cmc_heap_order HO, struct CMC_DEF_FVAL(SNAME) * f_val, + struct CMC_ALLOC_NODE_NAME *alloc, struct CMC_CALLBACKS_NAME *callbacks); +void CMC_(PFX, _clear)(struct SNAME *_heap_); +void CMC_(PFX, _free)(struct SNAME *_heap_); +/* Customization of Allocation and Callbacks */ +void CMC_(PFX, _customize)(struct SNAME *_heap_, struct CMC_ALLOC_NODE_NAME *alloc, + struct CMC_CALLBACKS_NAME *callbacks); +/* Collection Input and Output */ +bool CMC_(PFX, _insert)(struct SNAME *_heap_, V value); +bool CMC_(PFX, _remove)(struct SNAME *_heap_); +/* Element Access */ +V CMC_(PFX, _peek)(struct SNAME *_heap_); +/* Collection State */ +bool CMC_(PFX, _contains)(struct SNAME *_heap_, V value); +bool CMC_(PFX, _empty)(struct SNAME *_heap_); +bool CMC_(PFX, _full)(struct SNAME *_heap_); +size_t CMC_(PFX, _count)(struct SNAME *_heap_); +size_t CMC_(PFX, _capacity)(struct SNAME *_heap_); +int CMC_(PFX, _flag)(struct SNAME *_heap_); +/* Collection Utility */ +bool CMC_(PFX, _resize)(struct SNAME *_heap_, size_t capacity); +struct SNAME *CMC_(PFX, _copy_of)(struct SNAME *_heap_); +bool CMC_(PFX, _equals)(struct SNAME *_heap1_, struct SNAME *_heap2_); diff --git a/src/cmc/cmc/heap/struct.h b/src/cmc/cmc/heap/struct.h new file mode 100644 index 0000000..3dc51ea --- /dev/null +++ b/src/cmc/cmc/heap/struct.h @@ -0,0 +1,43 @@ +/** + * Copyright (c) 2019 Leonardo Vencovsky + * + * This file is part of the C Macro Collections Libray. + * + * 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. + */ + +struct SNAME +{ + /* Dynamic array of elements */ + V *buffer; + /* Current array capacity */ + size_t capacity; + /* Current amount of elements in the heap */ + size_t count; + /* Heap order (MaxHeap or MinHeap) */ + enum cmc_heap_order HO; + /* Flags indicating errors or success */ + int flag; + /* Value function table */ + struct CMC_DEF_FVAL(SNAME) * f_val; + /* Custom allocation functions */ + struct CMC_ALLOC_NODE_NAME *alloc; + /* Custom callback functions */ + CMC_CALLBACKS_DECL; +}; diff --git a/src/cmc/cmc/intervalheap/code.h b/src/cmc/cmc/intervalheap/code.h new file mode 100644 index 0000000..4e48ae5 --- /dev/null +++ b/src/cmc/cmc/intervalheap/code.h @@ -0,0 +1,761 @@ +/** + * Copyright (c) 2019 Leonardo Vencovsky + * + * This file is part of the C Macro Collections Libray. + * + * 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. + */ + +/* Implementation Detail Functions */ +static void CMC_(PFX, _impl_float_up_max)(struct SNAME *_heap_); +static void CMC_(PFX, _impl_float_up_min)(struct SNAME *_heap_); +static void CMC_(PFX, _impl_float_down_max)(struct SNAME *_heap_); +static void CMC_(PFX, _impl_float_down_min)(struct SNAME *_heap_); + +struct SNAME *CMC_(PFX, _new)(size_t capacity, struct CMC_DEF_FVAL(SNAME) * f_val) +{ + return CMC_(PFX, _new_custom)(capacity, f_val, NULL, NULL); +} + +struct SNAME *CMC_(PFX, _new_custom)(size_t capacity, struct CMC_DEF_FVAL(SNAME) * f_val, + struct CMC_ALLOC_NODE_NAME *alloc, struct CMC_CALLBACKS_NAME *callbacks) +{ + CMC_CALLBACKS_MAYBE_UNUSED(callbacks); + + if (capacity == 0 || capacity == UINTMAX_MAX) + return NULL; + + if (!f_val) + return NULL; + + if (!alloc) + alloc = &cmc_alloc_node_default; + + struct SNAME *_heap_ = alloc->malloc(sizeof(struct SNAME)); + + if (!_heap_) + return NULL; + + capacity = (capacity + capacity % 2) / 2; + + _heap_->buffer = alloc->calloc(capacity, sizeof(V[2])); + + if (!_heap_->buffer) + { + alloc->free(_heap_); + return NULL; + } + + _heap_->capacity = capacity; + _heap_->size = 0; + _heap_->count = 0; + _heap_->flag = CMC_FLAG_OK; + _heap_->f_val = f_val; + _heap_->alloc = alloc; + CMC_CALLBACKS_ASSIGN(_heap_, callbacks); + + return _heap_; +} + +void CMC_(PFX, _clear)(struct SNAME *_heap_) +{ + if (_heap_->f_val->free) + { + for (size_t i = 0; i < _heap_->count; i++) + { + _heap_->f_val->free(_heap_->buffer[i / 2][i % 2]); + } + } + + memset(_heap_->buffer, 0, sizeof(V[2]) * _heap_->capacity); + + _heap_->size = 0; + _heap_->count = 0; + _heap_->flag = CMC_FLAG_OK; +} + +void CMC_(PFX, _free)(struct SNAME *_heap_) +{ + if (_heap_->f_val->free) + { + for (size_t i = 0; i < _heap_->count; i++) + { + _heap_->f_val->free(_heap_->buffer[i / 2][i % 2]); + } + } + + _heap_->alloc->free(_heap_->buffer); + + _heap_->alloc->free(_heap_); +} + +void CMC_(PFX, _customize)(struct SNAME *_heap_, struct CMC_ALLOC_NODE_NAME *alloc, + struct CMC_CALLBACKS_NAME *callbacks) +{ + CMC_CALLBACKS_MAYBE_UNUSED(callbacks); + + if (!alloc) + _heap_->alloc = &cmc_alloc_node_default; + else + _heap_->alloc = alloc; + + CMC_CALLBACKS_ASSIGN(_heap_, callbacks); + + _heap_->flag = CMC_FLAG_OK; +} + +bool CMC_(PFX, _insert)(struct SNAME *_heap_, V value) +{ + if (CMC_(PFX, _full)(_heap_)) + { + if (!CMC_(PFX, _resize)(_heap_, _heap_->capacity * 4)) + return false; + } + + if (_heap_->count % 2 == 0) + { + /* Occupying a new node */ + _heap_->buffer[_heap_->size][0] = value; + _heap_->buffer[_heap_->size][1] = (V){ 0 }; + + _heap_->size++; + } + else + { + V(*node)[2] = &(_heap_->buffer[_heap_->size - 1]); + + /* Decide if the new element goes into the MinHeap or MaxHeap */ + if (_heap_->f_val->cmp((*node)[0], value) > 0) + { + /* Swap current value and add new element to the MinHeap */ + (*node)[1] = (*node)[0]; + (*node)[0] = value; + } + else + { + /* No need to swap and add the new element to the MaxHeap */ + (*node)[1] = value; + } + } + + _heap_->count++; + _heap_->flag = CMC_FLAG_OK; + + if (_heap_->count > 2) + { + /* Determine wheather to do a MaxHeap insert or a MinHeap */ + /* insert. For any integer this index calculation results in */ + /* an even number representing the parent of the last value */ + V(*parent)[2] = &(_heap_->buffer[(_heap_->size - 2) / 2]); + + if (_heap_->f_val->cmp((*parent)[0], value) > 0) + CMC_(PFX, _impl_float_up_min)(_heap_); + else if (_heap_->f_val->cmp((*parent)[1], value) < 0) + CMC_(PFX, _impl_float_up_max)(_heap_); + /* else no float up required */ + } + + CMC_CALLBACKS_CALL(_heap_, create); + + return true; +} + +bool CMC_(PFX, _remove_max)(struct SNAME *_heap_) +{ + if (CMC_(PFX, _empty)(_heap_)) + { + _heap_->flag = CMC_FLAG_EMPTY; + return false; + } + + if (_heap_->count == 1) + { + _heap_->buffer[0][0] = (V){ 0 }; + + _heap_->count--; + _heap_->size--; + + goto success; + } + + /* Swap the result with the last element in the MaxHeap and float */ + /* it down */ + V(*last_node)[2] = &(_heap_->buffer[_heap_->size - 1]); + + if (_heap_->count % 2 == 1) + { + /* Grab from MinHeap and discard last node */ + _heap_->buffer[0][1] = (*last_node)[0]; + + (*last_node)[0] = (V){ 0 }; + + _heap_->size--; + } + else + { + _heap_->buffer[0][1] = (*last_node)[1]; + + (*last_node)[1] = (V){ 0 }; + } + + _heap_->count--; + + /* FLoat Down on the MaxHeap */ + CMC_(PFX, _impl_float_down_max)(_heap_); + +success: + + _heap_->flag = CMC_FLAG_OK; + + CMC_CALLBACKS_CALL(_heap_, delete); + + return true; +} + +bool CMC_(PFX, _remove_min)(struct SNAME *_heap_) +{ + if (CMC_(PFX, _empty)(_heap_)) + { + _heap_->flag = CMC_FLAG_EMPTY; + return false; + } + + if (_heap_->count == 1) + { + _heap_->buffer[0][0] = (V){ 0 }; + + _heap_->count--; + _heap_->size--; + + goto success; + } + + /* Swap the result with the last element in the MinHeap and float */ + /* it down */ + V(*last_node)[2] = &(_heap_->buffer[_heap_->size - 1]); + + _heap_->buffer[0][0] = (*last_node)[0]; + + if (_heap_->count % 2 == 1) + { + /* Discard last node */ + (*last_node)[0] = (V){ 0 }; + + _heap_->size--; + } + else + { + /* Place the MaxHeap value in the MinHeap value spot */ + (*last_node)[0] = (*last_node)[1]; + (*last_node)[1] = (V){ 0 }; + } + + _heap_->count--; + + /* FLoat Down on the MinHeap */ + CMC_(PFX, _impl_float_down_min)(_heap_); + +success: + + _heap_->flag = CMC_FLAG_OK; + + CMC_CALLBACKS_CALL(_heap_, delete); + + return true; +} + +bool CMC_(PFX, _update_max)(struct SNAME *_heap_, V value) +{ + if (CMC_(PFX, _empty)(_heap_)) + { + _heap_->flag = CMC_FLAG_EMPTY; + return false; + } + + if (_heap_->count == 1) + { + _heap_->buffer[0][0] = value; + } + else if (_heap_->f_val->cmp(value, _heap_->buffer[0][0]) < 0) + { + /* Corner case: we are updating the Max value but it is less */ + /* than the Min value */ + _heap_->buffer[0][1] = _heap_->buffer[0][0]; + _heap_->buffer[0][0] = value; + + CMC_(PFX, _impl_float_down_max)(_heap_); + } + else + { + /* Update Max element and float it down */ + _heap_->buffer[0][1] = value; + + CMC_(PFX, _impl_float_down_max)(_heap_); + } + + _heap_->flag = CMC_FLAG_OK; + + CMC_CALLBACKS_CALL(_heap_, update); + + return true; +} + +bool CMC_(PFX, _update_min)(struct SNAME *_heap_, V value) +{ + if (CMC_(PFX, _empty)(_heap_)) + { + _heap_->flag = CMC_FLAG_EMPTY; + return false; + } + + if (_heap_->count == 1) + { + _heap_->buffer[0][0] = value; + } + else if (_heap_->f_val->cmp(value, _heap_->buffer[0][1]) > 0) + { + /* Corner case: we are updating the Min value but it is greater */ + /* than the Max value. */ + _heap_->buffer[0][0] = _heap_->buffer[0][1]; + _heap_->buffer[0][1] = value; + + CMC_(PFX, _impl_float_down_min)(_heap_); + } + else + { + /* Update Min element and float it down */ + _heap_->buffer[0][0] = value; + + CMC_(PFX, _impl_float_down_min)(_heap_); + } + + _heap_->flag = CMC_FLAG_OK; + + CMC_CALLBACKS_CALL(_heap_, update); + + return true; +} + +V CMC_(PFX, _max)(struct SNAME *_heap_) +{ + if (CMC_(PFX, _empty)(_heap_)) + { + _heap_->flag = CMC_FLAG_EMPTY; + return (V){ 0 }; + } + + _heap_->flag = CMC_FLAG_OK; + + CMC_CALLBACKS_CALL(_heap_, read); + + /* If there is only one element, then the maximum element is the */ + /* same as the one in the MinHeap */ + if (_heap_->count == 1) + return _heap_->buffer[0][0]; + + return _heap_->buffer[0][1]; +} + +V CMC_(PFX, _min)(struct SNAME *_heap_) +{ + if (CMC_(PFX, _empty)(_heap_)) + { + _heap_->flag = CMC_FLAG_EMPTY; + return (V){ 0 }; + } + + _heap_->flag = CMC_FLAG_OK; + + CMC_CALLBACKS_CALL(_heap_, read); + + return _heap_->buffer[0][0]; +} + +bool CMC_(PFX, _contains)(struct SNAME *_heap_, V value) +{ + _heap_->flag = CMC_FLAG_OK; + + bool result = false; + + for (size_t i = 0; i < _heap_->count; i++) + { + if (_heap_->f_val->cmp(_heap_->buffer[i / 2][i % 2], value) == 0) + { + result = true; + break; + } + } + + CMC_CALLBACKS_CALL(_heap_, read); + + return result; +} + +bool CMC_(PFX, _empty)(struct SNAME *_heap_) +{ + return _heap_->count == 0; +} + +bool CMC_(PFX, _full)(struct SNAME *_heap_) +{ + /* The heap is full if all nodes are completely filled */ + return _heap_->size >= _heap_->capacity && _heap_->count % 2 == 0; +} + +size_t CMC_(PFX, _count)(struct SNAME *_heap_) +{ + return _heap_->count; +} + +size_t CMC_(PFX, _capacity)(struct SNAME *_heap_) +{ + return _heap_->capacity; +} + +int CMC_(PFX, _flag)(struct SNAME *_heap_) +{ + return _heap_->flag; +} + +bool CMC_(PFX, _resize)(struct SNAME *_heap_, size_t capacity) +{ + if (_heap_->capacity == capacity) + goto success; + + if (capacity < _heap_->count) + { + _heap_->flag = CMC_FLAG_INVALID; + return false; + } + + /* Prevent overflow */ + if (capacity == UINTMAX_MAX) + { + _heap_->flag = CMC_FLAG_ERROR; + return false; + } + + capacity += capacity % 2; + + V(*new_buffer)[2] = _heap_->alloc->realloc(_heap_->buffer, sizeof(V[2]) * capacity); + + if (!new_buffer) + { + _heap_->flag = CMC_FLAG_ALLOC; + return false; + } + + if (capacity > _heap_->capacity) + { + memset(new_buffer + _heap_->capacity, 0, sizeof(V[2]) * (capacity - _heap_->capacity)); + } + + _heap_->buffer = new_buffer; + _heap_->capacity = capacity; + +success: + + _heap_->flag = CMC_FLAG_OK; + + CMC_CALLBACKS_CALL(_heap_, resize); + + return true; +} + +struct SNAME *CMC_(PFX, _copy_of)(struct SNAME *_heap_) +{ + struct SNAME *result = _heap_->alloc->malloc(sizeof(struct SNAME)); + + if (!result) + { + _heap_->flag = CMC_FLAG_ALLOC; + return NULL; + } + + memcpy(result, _heap_, sizeof(struct SNAME)); + + result->buffer = _heap_->alloc->malloc(sizeof(V[2]) * _heap_->capacity); + + if (!result->buffer) + { + _heap_->alloc->free(result); + _heap_->flag = CMC_FLAG_ALLOC; + return NULL; + } + + if (_heap_->f_val->cpy) + { + for (size_t i = 0; i < _heap_->count; i++) + result->buffer[i / 2][i % 2] = _heap_->f_val->cpy(_heap_->buffer[i / 2][i % 2]); + } + else + memcpy(result->buffer, _heap_->buffer, sizeof(V[2]) * _heap_->capacity); + + result->capacity = _heap_->capacity; + result->size = _heap_->size; + result->count = _heap_->count; + result->flag = CMC_FLAG_OK; + result->f_val = _heap_->f_val; + result->alloc = _heap_->alloc; + CMC_CALLBACKS_ASSIGN(result, _heap_->callbacks); + + _heap_->flag = CMC_FLAG_OK; + + return result; +} + +bool CMC_(PFX, _equals)(struct SNAME *_heap1_, struct SNAME *_heap2_) +{ + _heap1_->flag = CMC_FLAG_OK; + _heap2_->flag = CMC_FLAG_OK; + + if (_heap1_->count != _heap2_->count) + return false; + + for (size_t i = 0; i < _heap1_->count; i++) + { + V value1 = _heap1_->buffer[i / 2][i % 2]; + V value2 = _heap2_->buffer[i / 2][i % 2]; + + if (_heap1_->f_val->cmp(value1, value2) != 0) + return false; + } + + return true; +} + +static void CMC_(PFX, _impl_float_up_max)(struct SNAME *_heap_) +{ + size_t index = _heap_->size - 1; + + V(*curr_node)[2] = &(_heap_->buffer[index]); + + /* FLoat Up on the MaxHeap */ + while (index > 0) + { + /* Parent index */ + size_t P_index = (index - 1) / 2; + + V(*parent)[2] = &(_heap_->buffer[P_index]); + + if (index == _heap_->size - 1 && _heap_->count % 2 != 0) + { + /* In this case, the current node has no MaxHeap value so */ + /* we instead compare with the MinHeap value */ + if (_heap_->f_val->cmp((*curr_node)[0], (*parent)[1]) < 0) + break; + + /* Since the comparison above passed now we need to swap */ + /* the current node with the parent but it will have to be */ + /* done with the node's MinHeap value since the MaxHeap */ + /* value doesn't exist */ + V tmp = (*curr_node)[0]; + (*curr_node)[0] = (*parent)[1]; + (*parent)[1] = tmp; + } + else + { + /* Usual case, just compare both MaxHeap values */ + if (_heap_->f_val->cmp((*curr_node)[1], (*parent)[1]) < 0) + break; + + /* Swap with parent and repeat */ + V tmp = (*curr_node)[1]; + (*curr_node)[1] = (*parent)[1]; + (*parent)[1] = tmp; + } + + /* Update indexe and node */ + index = P_index; + curr_node = parent; + } +} + +static void CMC_(PFX, _impl_float_up_min)(struct SNAME *_heap_) +{ + size_t index = _heap_->size - 1; + + V(*curr_node)[2] = &(_heap_->buffer[index]); + + /* FLoat Up on the MinHeap */ + while (index > 0) + { + /* Parent index */ + size_t P_index = (index - 1) / 2; + + V(*parent)[2] = &(_heap_->buffer[P_index]); + + if (_heap_->f_val->cmp((*curr_node)[0], (*parent)[0]) >= 0) + break; + + /* Swap with parent and repeat */ + V tmp = (*curr_node)[0]; + (*curr_node)[0] = (*parent)[0]; + (*parent)[0] = tmp; + + /* Update indexe and node */ + index = P_index; + curr_node = parent; + } +} + +static void CMC_(PFX, _impl_float_down_max)(struct SNAME *_heap_) +{ + /* Floats Down from the MaxHeap */ + size_t index = 0; + + V(*curr_node)[2] = &(_heap_->buffer[index]); + + while (true) + { + /* If there are no children it is done */ + if (2 * index + 1 >= _heap_->size) + break; + + /* Child index to be compared with current value */ + size_t child; + size_t L_index = index * 2 + 1; + size_t R_index = index * 2 + 2; + + /* If there are two children, pick the smallest one */ + if (R_index < _heap_->size) + { + V(*L)[2] = &(_heap_->buffer[L_index]); + V(*R)[2] = &(_heap_->buffer[R_index]); + + /* If the right child is the last node and there is no */ + /* MaxHeap value */ + /* then do the comparison with the MinHeap value */ + if (R_index == _heap_->size - 1 && _heap_->count % 2 != 0) + child = _heap_->f_val->cmp((*L)[1], (*R)[0]) > 0 ? L_index : R_index; + else + child = _heap_->f_val->cmp((*L)[1], (*R)[1]) > 0 ? L_index : R_index; + } + /* Pick the only one available */ + else + child = L_index; + + V(*child_node)[2] = &(_heap_->buffer[child]); + + /* Again, check if the child node is the last one and has no */ + /* MaxHeap value */ + if (child == _heap_->size - 1 && _heap_->count % 2 != 0) + { + /* Odd case, compare with MinHeap value */ + /* If current value is not less than the child node's */ + /* value it is done */ + if (_heap_->f_val->cmp((*curr_node)[1], (*child_node)[0]) >= 0) + break; + + /* Otherwise swap and continue */ + V tmp = (*child_node)[0]; + (*child_node)[0] = (*curr_node)[1]; + (*curr_node)[1] = tmp; + } + else + { + /* If current value is not less than the child node's */ + /* value it is done */ + if (_heap_->f_val->cmp((*curr_node)[1], (*child_node)[1]) >= 0) + break; + + /* Otherwise swap and continue */ + V tmp = (*child_node)[1]; + (*child_node)[1] = (*curr_node)[1]; + (*curr_node)[1] = tmp; + + /* Check if the MinHeap and MaxHeap values need to be */ + /* swapped */ + if (_heap_->f_val->cmp((*child_node)[0], (*child_node)[1]) > 0) + { + /* Swap because the MinHeap value is greater than the */ + /* MaxHeap value */ + tmp = (*child_node)[0]; + (*child_node)[0] = (*child_node)[1]; + (*child_node)[1] = tmp; + } + } + + /* Update index and node */ + index = child; + curr_node = child_node; + } +} + +static void CMC_(PFX, _impl_float_down_min)(struct SNAME *_heap_) +{ + /* Floats Down from the MinHeap */ + size_t index = 0; + + V(*curr_node)[2] = &(_heap_->buffer[index]); + + while (true) + { + /* If there are no children it is done */ + if (2 * index + 1 >= _heap_->size) + break; + + /* Child index to be compared with current value */ + size_t child; + size_t L_index = index * 2 + 1; + size_t R_index = index * 2 + 2; + + /* If there are two children, pick the smallest one */ + if (R_index < _heap_->size) + { + V(*L)[2] = &(_heap_->buffer[L_index]); + V(*R)[2] = &(_heap_->buffer[R_index]); + + child = _heap_->f_val->cmp((*L)[0], (*R)[0]) < 0 ? L_index : R_index; + } + /* Pick the only one available */ + else + child = L_index; + + V(*child_node)[2] = &(_heap_->buffer[child]); + + /* If current value is smaller than the child node's value, it */ + /* is done */ + if (_heap_->f_val->cmp((*curr_node)[0], (*child_node)[0]) < 0) + break; + + /* Otherwise swap and continue */ + V tmp = (*child_node)[0]; + (*child_node)[0] = (*curr_node)[0]; + (*curr_node)[0] = tmp; + + /* If the child node is the last node check if the MinHeap and */ + /* MaxHeap values need to be swapped */ + if (child != _heap_->size - 1 || _heap_->count % 2 == 0) + { + if (_heap_->f_val->cmp((*child_node)[0], (*child_node)[1]) > 0) + { + /* Swap because the MinHeap value is greater than the */ + /* MaxHeap value */ + tmp = (*child_node)[0]; + (*child_node)[0] = (*child_node)[1]; + (*child_node)[1] = tmp; + } + } + + /* Update index and node */ + index = child; + curr_node = child_node; + } +} diff --git a/src/cmc/cmc/intervalheap/ext/code.h b/src/cmc/cmc/intervalheap/ext/code.h new file mode 100644 index 0000000..e513abe --- /dev/null +++ b/src/cmc/cmc/intervalheap/ext/code.h @@ -0,0 +1,266 @@ +/** + * Copyright (c) 2019 Leonardo Vencovsky + * + * This file is part of the C Macro Collections Libray. + * + * 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. + */ + +/** + * INIT + * + * The part 'INIT' gives a new way of initializing a collection. The collection + * struct is not heap allocated, only its internal structure (nodes, buffers). + */ +#ifdef CMC_EXT_INTERVALHEAP_INIT + +#endif /* CMC_EXT_INTERVALHEAP_INIT */ + +/** + * ITER + * + * Intervalheap bi-directional iterator. + * + * TODO allow creation of iterators exclusively for min or max heap + */ +#ifdef CMC_EXT_INTERVALHEAP_ITER + +struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_start)(struct SNAME *target) +{ + struct CMC_DEF_ITER(SNAME) iter; + + iter.target = target; + iter.cursor = 0; + iter.start = true; + iter.end = CMC_(PFX, _empty)(target); + + return iter; +} + +struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_end)(struct SNAME *target) +{ + struct CMC_DEF_ITER(SNAME) iter; + + iter.target = target; + iter.cursor = 0; + iter.start = CMC_(PFX, _empty)(target); + iter.end = true; + + if (!CMC_(PFX, _empty)(target)) + iter.cursor = target->count - 1; + + return iter; +} + +bool CMC_(PFX, _iter_at_start)(struct CMC_DEF_ITER(SNAME) * iter) +{ + return CMC_(PFX, _empty)(iter->target) || iter->start; +} + +bool CMC_(PFX, _iter_at_end)(struct CMC_DEF_ITER(SNAME) * iter) +{ + return CMC_(PFX, _empty)(iter->target) || iter->end; +} + +bool CMC_(PFX, _iter_to_start)(struct CMC_DEF_ITER(SNAME) * iter) +{ + if (!CMC_(PFX, _empty)(iter->target)) + { + iter->cursor = 0; + iter->start = true; + iter->end = CMC_(PFX, _empty)(iter->target); + + return true; + } + + return false; +} + +bool CMC_(PFX, _iter_to_end)(struct CMC_DEF_ITER(SNAME) * iter) +{ + if (!CMC_(PFX, _empty)(iter->target)) + { + iter->cursor = iter->target->count - 1; + iter->start = CMC_(PFX, _empty)(iter->target); + iter->end = true; + + return true; + } + + return false; +} + +bool CMC_(PFX, _iter_next)(struct CMC_DEF_ITER(SNAME) * iter) +{ + if (iter->end) + return false; + + if (iter->cursor + 1 == iter->target->count) + { + iter->end = true; + return false; + } + + iter->start = CMC_(PFX, _empty)(iter->target); + + iter->cursor++; + + return true; +} + +bool CMC_(PFX, _iter_prev)(struct CMC_DEF_ITER(SNAME) * iter) +{ + if (iter->start) + return false; + + if (iter->cursor == 0) + { + iter->start = true; + return false; + } + + iter->end = CMC_(PFX, _empty)(iter->target); + + iter->cursor--; + + return true; +} + +/* Returns true only if the iterator moved */ +bool CMC_(PFX, _iter_advance)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps) +{ + if (iter->end) + return false; + + if (iter->cursor + 1 == iter->target->count) + { + iter->end = true; + return false; + } + + if (steps == 0 || iter->cursor + steps >= iter->target->count) + return false; + + if (iter->end) + return false; + + iter->start = CMC_(PFX, _empty)(iter->target); + + iter->cursor += steps; + + return true; +} + +/* Returns true only if the iterator moved */ +bool CMC_(PFX, _iter_rewind)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps) +{ + if (iter->start) + return false; + + if (iter->cursor == 0) + { + iter->start = true; + return false; + } + + if (steps == 0 || iter->cursor < steps) + return false; + + iter->end = CMC_(PFX, _empty)(iter->target); + + iter->cursor -= steps; + + return true; +} + +/* Returns true only if the iterator was able to be positioned at the */ +/* given index */ +bool CMC_(PFX, _iter_go_to)(struct CMC_DEF_ITER(SNAME) * iter, size_t index) +{ + if (index >= iter->target->count) + return false; + + if (iter->cursor > index) + return CMC_(PFX, _iter_rewind)(iter, iter->cursor - index); + else if (iter->cursor < index) + return CMC_(PFX, _iter_advance)(iter, index - iter->cursor); + + return true; +} + +V CMC_(PFX, _iter_value)(struct CMC_DEF_ITER(SNAME) * iter) +{ + if (CMC_(PFX, _empty)(iter->target)) + return (V){ 0 }; + + return iter->target->buffer[iter->cursor / 2][iter->cursor % 2]; +} + +size_t CMC_(PFX, _iter_index)(struct CMC_DEF_ITER(SNAME) * iter) +{ + return iter->cursor; +} + +#endif /* CMC_EXT_INTERVALHEAP_ITER */ + +/** + * STR + * + * Print helper functions. + */ +#ifdef CMC_EXT_INTERVALHEAP_STR + +bool CMC_(PFX, _to_string)(struct SNAME *_heap_, FILE *fptr) +{ + struct SNAME *h_ = _heap_; + + return 0 <= fprintf(fptr, + "struct %s<%s> " + "at %p { " + "buffer:%p, " + "capacity:%" PRIuMAX ", " + "size:%" PRIuMAX ", " + "count:%" PRIuMAX ", " + "flag:%d, " + "f_val:%p, " + "alloc:%p, " + "callbacks:%p }", + CMC_TO_STRING(SNAME), CMC_TO_STRING(V), h_, h_->buffer, h_->capacity, h_->size, h_->count, + h_->flag, h_->f_val, h_->alloc, CMC_CALLBACKS_GET(h_)); +} + +bool CMC_(PFX, _print)(struct SNAME *_heap_, FILE *fptr, const char *start, const char *separator, const char *end) +{ + fprintf(fptr, "%s", start); + + for (size_t i = 0; i < _heap_->count; i++) + { + if (!_heap_->f_val->str(fptr, _heap_->buffer[i / 2][i % 2])) + return false; + + if (i + 1 < _heap_->count) + fprintf(fptr, "%s", separator); + } + + fprintf(fptr, "%s", end); + + return true; +} + +#endif /* CMC_EXT_INTERVALHEAP_STR */ diff --git a/src/cmc/cmc/intervalheap/ext/header.h b/src/cmc/cmc/intervalheap/ext/header.h new file mode 100644 index 0000000..ae998e3 --- /dev/null +++ b/src/cmc/cmc/intervalheap/ext/header.h @@ -0,0 +1,88 @@ +/** + * Copyright (c) 2019 Leonardo Vencovsky + * + * This file is part of the C Macro Collections Libray. + * + * 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. + */ + +/** + * INIT + * + * The part 'INIT' gives a new way of initializing a collection. The collection + * struct is not heap allocated, only its internal structure (nodes, buffers). + */ +#ifdef CMC_EXT_INTERVALHEAP_INIT + +#endif /* CMC_EXT_INTERVALHEAP_INIT */ + +/** + * ITER + * + * List bi-directional iterator. + */ +#ifdef CMC_EXT_INTERVALHEAP_ITER + +/* IntervalHeap Iterator */ +struct CMC_DEF_ITER(SNAME) +{ + /* Target IntervalHeap */ + struct SNAME *target; + + /* Cursor's position (index) */ + size_t cursor; + + /* If the iterator has reached the start of the iteration */ + bool start; + + /* If the iterator has reached the end of the iteration */ + bool end; +}; + +/* Iterator Initialization */ +struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_start)(struct SNAME *target); +struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_end)(struct SNAME *target); +/* Iterator State */ +bool CMC_(PFX, _iter_at_start)(struct CMC_DEF_ITER(SNAME) * iter); +bool CMC_(PFX, _iter_at_end)(struct CMC_DEF_ITER(SNAME) * iter); +/* Iterator Movement */ +bool CMC_(PFX, _iter_to_start)(struct CMC_DEF_ITER(SNAME) * iter); +bool CMC_(PFX, _iter_to_end)(struct CMC_DEF_ITER(SNAME) * iter); +bool CMC_(PFX, _iter_next)(struct CMC_DEF_ITER(SNAME) * iter); +bool CMC_(PFX, _iter_prev)(struct CMC_DEF_ITER(SNAME) * iter); +bool CMC_(PFX, _iter_advance)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps); +bool CMC_(PFX, _iter_rewind)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps); +bool CMC_(PFX, _iter_go_to)(struct CMC_DEF_ITER(SNAME) * iter, size_t index); +/* Iterator Access */ +V CMC_(PFX, _iter_value)(struct CMC_DEF_ITER(SNAME) * iter); +size_t CMC_(PFX, _iter_index)(struct CMC_DEF_ITER(SNAME) * iter); + +#endif /* CMC_EXT_INTERVALHEAP_ITER */ + +/** + * STR + * + * Print helper functions. + */ +#ifdef CMC_EXT_INTERVALHEAP_STR + +bool CMC_(PFX, _to_string)(struct SNAME *_heap_, FILE *fptr); +bool CMC_(PFX, _print)(struct SNAME *_heap_, FILE *fptr, const char *start, const char *separator, const char *end); + +#endif /* CMC_EXT_INTERVALHEAP_STR */ diff --git a/src/cmc/cmc/intervalheap/ext/struct.h b/src/cmc/cmc/intervalheap/ext/struct.h new file mode 100644 index 0000000..59c5376 --- /dev/null +++ b/src/cmc/cmc/intervalheap/ext/struct.h @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019 Leonardo Vencovsky + * + * This file is part of the C Macro Collections Libray. + * + * 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. + */ diff --git a/src/cmc/cmc/intervalheap/header.h b/src/cmc/cmc/intervalheap/header.h new file mode 100644 index 0000000..7d69a93 --- /dev/null +++ b/src/cmc/cmc/intervalheap/header.h @@ -0,0 +1,72 @@ +/** + * Copyright (c) 2019 Leonardo Vencovsky + * + * This file is part of the C Macro Collections Libray. + * + * 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. + */ + +/* Value struct function table */ +struct CMC_DEF_FVAL(SNAME) +{ + /* Comparator function */ + CMC_DEF_FTAB_CMP(V); + /* Copy function */ + CMC_DEF_FTAB_CPY(V); + /* To string function */ + CMC_DEF_FTAB_STR(V); + /* Free from memory function */ + CMC_DEF_FTAB_FREE(V); + /* Hash function */ + CMC_DEF_FTAB_HASH(V); + /* Priority function */ + CMC_DEF_FTAB_PRI(V); +}; + +/* Collection Functions */ +/* Collection Allocation and Deallocation */ +struct SNAME *CMC_(PFX, _new)(size_t capacity, struct CMC_DEF_FVAL(SNAME) * f_val); +struct SNAME *CMC_(PFX, _new_custom)(size_t capacity, struct CMC_DEF_FVAL(SNAME) * f_val, + struct CMC_ALLOC_NODE_NAME *alloc, struct CMC_CALLBACKS_NAME *callbacks); +void CMC_(PFX, _clear)(struct SNAME *_heap_); +void CMC_(PFX, _free)(struct SNAME *_heap_); +/* Customization of Allocation and Callbacks */ +void CMC_(PFX, _customize)(struct SNAME *_heap_, struct CMC_ALLOC_NODE_NAME *alloc, + struct CMC_CALLBACKS_NAME *callbacks); +/* Collection Input and Output */ +bool CMC_(PFX, _insert)(struct SNAME *_heap_, V value); +bool CMC_(PFX, _remove_max)(struct SNAME *_heap_); +bool CMC_(PFX, _remove_min)(struct SNAME *_heap_); +/* Collection Update */ +bool CMC_(PFX, _update_max)(struct SNAME *_heap_, V value); +bool CMC_(PFX, _update_min)(struct SNAME *_heap_, V value); +/* Element Access */ +V CMC_(PFX, _max)(struct SNAME *_heap_); +V CMC_(PFX, _min)(struct SNAME *_heap_); +/* Collection State */ +bool CMC_(PFX, _contains)(struct SNAME *_heap_, V value); +bool CMC_(PFX, _empty)(struct SNAME *_heap_); +bool CMC_(PFX, _full)(struct SNAME *_heap_); +size_t CMC_(PFX, _count)(struct SNAME *_heap_); +size_t CMC_(PFX, _capacity)(struct SNAME *_heap_); +int CMC_(PFX, _flag)(struct SNAME *_heap_); +/* Collection Utility */ +bool CMC_(PFX, _resize)(struct SNAME *_heap_, size_t capacity); +struct SNAME *CMC_(PFX, _copy_of)(struct SNAME *_heap_); +bool CMC_(PFX, _equals)(struct SNAME *_heap1_, struct SNAME *_heap2_); diff --git a/src/cmc/cmc/intervalheap/struct.h b/src/cmc/cmc/intervalheap/struct.h new file mode 100644 index 0000000..4c6ea42 --- /dev/null +++ b/src/cmc/cmc/intervalheap/struct.h @@ -0,0 +1,44 @@ +/** + * Copyright (c) 2019 Leonardo Vencovsky + * + * This file is part of the C Macro Collections Libray. + * + * 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. + */ + +struct SNAME +{ + /* Dynamic array of elements */ + /* buffer[n][0] is MinHeap and buffer[n][1] is MaxHeap */ + V (*buffer)[2]; + /* Current array capacity */ + size_t capacity; + /* Current amount of pairs of values in the array */ + size_t size; + /* Current amount of elements in the heap */ + size_t count; + /* Flags indicating errors or success */ + int flag; + /* Value function table */ + struct CMC_DEF_FVAL(SNAME) * f_val; + /* Custom allocation functions */ + struct CMC_ALLOC_NODE_NAME *alloc; + /* Custom callback functions */ + CMC_CALLBACKS_DECL; +}; diff --git a/src/cmc/cor/alloc.h b/src/cmc/cor/alloc.h index 3c715e1..809dd40 100644 --- a/src/cmc/cor/alloc.h +++ b/src/cmc/cor/alloc.h @@ -35,6 +35,8 @@ #ifndef CMC_COR_ALLOC_H #define CMC_COR_ALLOC_H +#ifndef CMC_NO_ALLOC + #ifdef CMC_CAMEL_CASE #define CMC_ALLOC_NODE_NAME CMCAllocNode #else @@ -58,4 +60,6 @@ static struct CMC_ALLOC_NODE_NAME void (*free)(void *); } CMC_UNUSED cmc_alloc_node_default = { malloc, calloc, realloc, free }; +#endif /* CMC_NO_ALLOC */ + #endif /* CMC_COR_ALLOC_H */ diff --git a/src/cmc/cor/bitset.h b/src/cmc/cor/bitset.h index d4b3fb5..bd03bba 100644 --- a/src/cmc/cor/bitset.h +++ b/src/cmc/cor/bitset.h @@ -39,7 +39,7 @@ #ifndef CMC_COR_BITSET_H #define CMC_COR_BITSET_H -#include +#include "core.h" /* Defines the underlaying data type for the bitset array */ /* Possible values: uint64_t, uint32_t, uint16_t, uint8_t, size_t */ diff --git a/src/cmc/cor/core.h b/src/cmc/cor/core.h index bdd4002..5308da5 100644 --- a/src/cmc/cor/core.h +++ b/src/cmc/cor/core.h @@ -45,13 +45,18 @@ #ifndef CMC_COR_CORE_H #define CMC_COR_CORE_H +#ifndef CMC_NO_IMPORTS + #include #include #include +#include #include #include #include +#endif /* CMC_NO_IMPORTS */ + #if defined(__GNUC__) || defined(__clang__) #define CMC_UNUSED __attribute__((__unused__)) #else diff --git a/src/cmc/heap.h b/src/cmc/heap.h new file mode 100644 index 0000000..b82886f --- /dev/null +++ b/src/cmc/heap.h @@ -0,0 +1,88 @@ +/** + * Copyright (c) 2019 Leonardo Vencovsky + * + * This file is part of the C Macro Collections Libray. + * + * 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. + */ + +/** + * heap.h + * + * Creation Date: 25/03/2019 + * + * Authors: + * Leonardo Vencovsky (https://github.com/LeoVen) + * + */ + +/** + * Heap + * + * The Heap is a specialized tree-based data structure which is essentially a + * complete tree that satisfies the heap property: + * - MaxHeap: + * - The root node is the greatest element of the unique set of keys. + * - A node key is always greater than or equal to its children keys. + * - Minheap: + * - The root node is the smallest element of the unique set of keys. + * - A node Key is always greater than or equal to its children keys. + * + * The heap is mostly used to implement priority queues. Sometimes it can also + * be used to sort elements. There are three main functions: + * - insert : Adds an element to the heap + * - remove_(min/max): Removes the min/max element from the heap + * - min/max : Accesses the min/max element from the heap + */ + +#include "cor/core.h" +#include "cor/heap.h" + +/** + * Used values + * V - heap value data type + * SNAME - struct name and prefix of other related structs + * PFX - functions prefix + */ + +/* Structs definition */ +#include "cmc/heap/struct.h" + +/* Function declaration */ +#include "cmc/heap/header.h" + +/* Function implementation */ +#include "cmc/heap/code.h" + +/** + * Extensions + * + * INIT - Initializes the struct on the stack + * ITER - heap iterator + * STR - Print helper functions + */ +#define CMC_EXT_HEAP_PARTS ITER, SETF, STR +/**/ +#include "cmc/heap/ext/struct.h" +/**/ +#include "cmc/heap/ext/header.h" +/**/ +#include "cmc/heap/ext/code.h" + +#include "cor/undef.h" diff --git a/src/cmc/intervalheap.h b/src/cmc/intervalheap.h new file mode 100644 index 0000000..72adb71 --- /dev/null +++ b/src/cmc/intervalheap.h @@ -0,0 +1,80 @@ +/** + * Copyright (c) 2019 Leonardo Vencovsky + * + * This file is part of the C Macro Collections Libray. + * + * 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. + */ + +/** + * intervalheap.h + * + * Creation Date: 06/07/2019 + * + * Authors: + * Leonardo Vencovsky (https://github.com/LeoVen) + * + */ + +/** + * Interval Heap + * + * An interval heap is a specialized heap with: + * + * - O(1) - Find Min + * - O(1) - Find Max + * - O(log n) - Insert + * - O(log n) - Remove Min + * - O(log n) - Remove Max + */ + +#include "cor/core.h" + +/** + * Used values + * V - intervalheap value data type + * SNAME - struct name and prefix of other related structs + * PFX - functions prefix + */ + +/* Structs definition */ +#include "cmc/intervalheap/struct.h" + +/* Function declaration */ +#include "cmc/intervalheap/header.h" + +/* Function implementation */ +#include "cmc/intervalheap/code.h" + +/** + * Extensions + * + * INIT - Initializes the struct on the stack + * ITER - intervalheap iterator + * STR - Print helper functions + */ +#define CMC_EXT_HEAP_PARTS ITER, SETF, STR +/**/ +#include "cmc/intervalheap/ext/struct.h" +/**/ +#include "cmc/intervalheap/ext/header.h" +/**/ +#include "cmc/intervalheap/ext/code.h" + +#include "cor/undef.h" diff --git a/tests/Makefile b/tests/Makefile index 4baee3d..f7ec904 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -1,5 +1,5 @@ CC=gcc -CFLAGS=-Wall -Wextra -Werror -fprofile-arcs -ftest-coverage -g -O0 +CFLAGS=-Wall -Wextra -Werror -fprofile-arcs -ftest-coverage -ftime-report -g -O0 INCLUDE=-I ../src main: diff --git a/tests/main.c b/tests/main.c index 70bae83..0760c3d 100644 --- a/tests/main.c +++ b/tests/main.c @@ -1,18 +1,18 @@ #include #include -// #include "unt_bitset.h" +#include "unt_bitset.h" #include "unt_deque.h" #include "unt_hashbidimap.h" #include "unt_hashmap.h" #include "unt_hashmultimap.h" #include "unt_hashmultiset.h" #include "unt_hashset.h" -// #include "unt_heap.h" -// #include "unt_intervalheap.h" +#include "unt_heap.h" +#include "unt_intervalheap.h" // #include "unt_linkedlist.h" #include "unt_list.h" -// #include "unt_queue.h" +#include "unt_queue.h" // #include "unt_sortedlist.h" #include "unt_stack.h" // #include "unt_treemap.h" @@ -52,8 +52,8 @@ int main(void) cmc_timer_start(timer); uintmax_t tests = 0, units = 0; - // cmc_run(CMCBitSet, units, tests); - // cmc_run(CMCBitSetIter, units, tests); + cmc_run(CMCBitSet, units, tests); + cmc_run(CMCBitSetIter, units, tests); cmc_run(CMCDeque, units, tests); cmc_run(CMCDequeIter, units, tests); cmc_run(CMCHashBidiMap, units, tests); @@ -66,16 +66,16 @@ int main(void) cmc_run(CMCHashMultiSetIter, units, tests); cmc_run(CMCHashSet, units, tests); cmc_run(CMCHashSetIter, units, tests); - // cmc_run(CMCHeap, units, tests); - // cmc_run(CMCHeapIter, units, tests); - // cmc_run(CMCIntervalHeap, units, tests); - // cmc_run(CMCIntervalHeapIter, units, tests); + cmc_run(CMCHeap, units, tests); + cmc_run(CMCHeapIter, units, tests); + cmc_run(CMCIntervalHeap, units, tests); + cmc_run(CMCIntervalHeapIter, units, tests); // cmc_run(CMCLinkedList, units, tests); // cmc_run(CMCLinkedListIter, units, tests); cmc_run(CMCList, units, tests); cmc_run(CMCListIter, units, tests); - // cmc_run(CMCQueue, units, tests); - // cmc_run(CMCQueueIter, units, tests); + cmc_run(CMCQueue, units, tests); + cmc_run(CMCQueueIter, units, tests); // cmc_run(CMCSortedList, units, tests); // cmc_run(CMCSortedListIter, units, tests); cmc_run(CMCStack, units, tests); diff --git a/tests/unt_bitset.h b/tests/unt_bitset.h new file mode 100644 index 0000000..b163ebd --- /dev/null +++ b/tests/unt_bitset.h @@ -0,0 +1,454 @@ +#ifndef CMC_TESTS_UNT_BITSET_H +#define CMC_TESTS_UNT_BITSET_H + +#include "utl.h" + +#define PFX bs +#define SNAME bitset +#define CMC_EXT_BITSET_INIT +#define CMC_EXT_BITSET_ITER +#define CMC_EXT_BITSET_STR +#include "cmc/bitset.h" + +struct cmc_alloc_node *bs_alloc_node = + &(struct cmc_alloc_node){ .malloc = malloc, .calloc = calloc, .realloc = realloc, .free = free }; + +CMC_CREATE_UNIT(CMCBitSet, true, { + const size_t word_bits = sizeof(cmc_bitset_word) * CHAR_BIT; + + printf("%s", cmc_test_color(5)); + printf(" BitSet<" CMC_TO_STRING(CMC_BITSET_WORD_TYPE) ">\n"); + printf("%s", cmc_test_color(0)); + + CMC_CREATE_TEST(PFX##_new(), { + struct bitset *bs = bs_new(64); + + cmc_assert_not_equals(ptr, NULL, bs); + cmc_assert_not_equals(ptr, NULL, bs->buffer); + cmc_assert_equals(size_t, cmc_bidx_to_widx(63) + 1, bs->capacity); + cmc_assert_equals(ptr, cmc_alloc_node_default.malloc, bs->alloc->malloc); + cmc_assert_equals(ptr, cmc_alloc_node_default.calloc, bs->alloc->calloc); + cmc_assert_equals(ptr, cmc_alloc_node_default.realloc, bs->alloc->realloc); + cmc_assert_equals(ptr, cmc_alloc_node_default.free, bs->alloc->free); + cmc_assert_equals(ptr, NULL, bs->callbacks); + + bs_free(bs); + + bs = bs_new(129); + + cmc_assert_equals(size_t, cmc_bidx_to_widx(128) + 1, bs->capacity); + + bs_free(bs); + + bs = bs_new(0); + + cmc_assert_equals(ptr, NULL, bs); + }); + + CMC_CREATE_TEST(PFX##_new_custom(), { + struct bitset *bs = bs_new_custom(64, bs_alloc_node, callbacks); + + cmc_assert_not_equals(ptr, NULL, bs); + cmc_assert_not_equals(ptr, NULL, bs->buffer); + cmc_assert_equals(size_t, cmc_bidx_to_widx(63) + 1, bs->capacity); + cmc_assert_equals(ptr, bs_alloc_node, bs->alloc); + cmc_assert_equals(ptr, callbacks, bs->callbacks); + + bs_free(bs); + + bs = bs_new_custom(129, NULL, NULL); + + cmc_assert_equals(size_t, cmc_bidx_to_widx(128) + 1, bs->capacity); + bs_free(bs); + + bs = bs_new_custom(0, bs_alloc_node, callbacks); + + cmc_assert_equals(ptr, NULL, bs); + }); + + CMC_CREATE_TEST(PFX##_init(), { + struct bitset bs = bs_init(64); + + cmc_assert_not_equals(ptr, NULL, bs.buffer); + cmc_assert_equals(size_t, cmc_bidx_to_widx(63) + 1, bs.capacity); + cmc_assert_equals(ptr, cmc_alloc_node_default.malloc, bs.alloc->malloc); + cmc_assert_equals(ptr, cmc_alloc_node_default.calloc, bs.alloc->calloc); + cmc_assert_equals(ptr, cmc_alloc_node_default.realloc, bs.alloc->realloc); + cmc_assert_equals(ptr, cmc_alloc_node_default.free, bs.alloc->free); + cmc_assert_equals(ptr, NULL, bs.callbacks); + + bs_release(bs); + + bs = bs_init(129); + + cmc_assert_equals(size_t, cmc_bidx_to_widx(128) + 1, bs.capacity); + + bs_release(bs); + + bs = bs_init(0); + + cmc_assert_equals(ptr, NULL, bs.buffer); + }); + + CMC_CREATE_TEST(PFX##_init_custom(), { + struct bitset bs = bs_init_custom(64, bs_alloc_node, callbacks); + + cmc_assert_not_equals(ptr, NULL, bs.buffer); + cmc_assert_equals(size_t, cmc_bidx_to_widx(63) + 1, bs.capacity); + cmc_assert_equals(ptr, bs_alloc_node, bs.alloc); + cmc_assert_equals(ptr, callbacks, bs.callbacks); + + bs_release(bs); + + bs = bs_init_custom(129, NULL, NULL); + + cmc_assert_equals(size_t, cmc_bidx_to_widx(128) + 1, bs.capacity); + + bs_release(bs); + + bs = bs_init_custom(0, bs_alloc_node, callbacks); + + cmc_assert_equals(ptr, NULL, bs.buffer); + }); + + CMC_CREATE_TEST(PFX##_customize(), { + struct bitset *bs = bs_new(word_bits); + + cmc_assert_not_equals(ptr, NULL, bs); + + bs->flag = CMC_FLAG_ERROR; + bs_customize(bs, bs_alloc_node, callbacks); + + cmc_assert_equals(ptr, bs_alloc_node, bs->alloc); + cmc_assert_equals(ptr, callbacks, bs->callbacks); + cmc_assert_equals(int32_t, CMC_FLAG_OK, bs->flag); + + bs->flag = CMC_FLAG_ERROR; + bs_customize(bs, NULL, NULL); + + cmc_assert_equals(ptr, cmc_alloc_node_default.malloc, bs->alloc->malloc); + cmc_assert_equals(ptr, cmc_alloc_node_default.calloc, bs->alloc->calloc); + cmc_assert_equals(ptr, cmc_alloc_node_default.realloc, bs->alloc->realloc); + cmc_assert_equals(ptr, cmc_alloc_node_default.free, bs->alloc->free); + cmc_assert_equals(ptr, NULL, bs->callbacks); + cmc_assert_equals(int32_t, CMC_FLAG_OK, bs->flag); + + bs_free(bs); + }); + + CMC_CREATE_TEST(PFX##_set(), { + struct bitset *bs = bs_new(word_bits); + + cmc_assert_not_equals(ptr, NULL, bs); + cmc_assert_equals(CMC_BITSET_WORD_TYPE, 0, bs->buffer[0]); + + bs->flag = CMC_FLAG_ERROR; + cmc_assert(bs_set(bs, 0)); + cmc_assert_equals(CMC_BITSET_WORD_TYPE, 1, bs->buffer[0]); + cmc_assert_equals(int32_t, CMC_FLAG_OK, bs->flag); + + bs->buffer[0] = 0; + + cmc_assert(bs_set(bs, word_bits - 1)); + cmc_assert_equals(CMC_BITSET_WORD_TYPE, ((cmc_bitset_word)1 << (word_bits - 1)), bs->buffer[0]); + + cmc_assert(bs_set(bs, word_bits * 8 - 1)); + cmc_assert_equals(CMC_BITSET_WORD_TYPE, ((cmc_bitset_word)1 << (word_bits - 1)), + bs->buffer[cmc_bidx_to_widx(word_bits * 8 - 1)]); + + cmc_assert(bs_set(bs, word_bits * 18 - 2)); + cmc_assert_equals(CMC_BITSET_WORD_TYPE, ((cmc_bitset_word)1 << (word_bits - 2)), + bs->buffer[cmc_bidx_to_widx(word_bits * 18 - 2)]); + + bs_free(bs); + }); + + CMC_CREATE_TEST(PFX##_set_range(), { + struct bitset *bs = bs_new(word_bits); + + cmc_assert_not_equals(ptr, NULL, bs); + cmc_assert_equals(CMC_BITSET_WORD_TYPE, 0, bs->buffer[0]); + + bs->flag = CMC_FLAG_ERROR; + cmc_assert(bs_set_range(bs, 0, 0)); + cmc_assert_equals(uint8_t, 1, bs->buffer[0]); + cmc_assert_equals(int32_t, CMC_FLAG_OK, bs->flag); + + cmc_assert(!bs_set_range(bs, 1, 0)); + cmc_assert_equals(int32_t, CMC_FLAG_INVALID, bs->flag); + + bs->buffer[0] = 0; + + cmc_assert(bs_set_range(bs, 4, 7)); /* 1111 0000 */ + cmc_assert_equals(uint8_t, 240, bs->buffer[0]); + + cmc_assert(bs_set_range(bs, 2, 2)); /* 1111 0100 */ + cmc_assert_equals(uint8_t, 244, bs->buffer[0]); + + cmc_assert(bs_set_range(bs, word_bits * 6 - 2, word_bits * 6 - 2)); + cmc_assert_equals(CMC_BITSET_WORD_TYPE, ((cmc_bitset_word)1 << (word_bits - 2)), + bs->buffer[cmc_bidx_to_widx(word_bits * 6 - 2)]); + + // Make sure we have at least word_bits * 40 slots + bs_set(bs, word_bits * 40); + + cmc_assert(bs_set_range(bs, word_bits * 20, word_bits * 21 - 1)); + cmc_assert_equals(CMC_BITSET_WORD_TYPE, (~(cmc_bitset_word)0), bs->buffer[cmc_bidx_to_widx(word_bits * 20)]); + + cmc_assert_equals(CMC_BITSET_WORD_TYPE, 0, bs->buffer[cmc_bidx_to_widx(word_bits * 20 - 1)]); + cmc_assert_equals(CMC_BITSET_WORD_TYPE, 0, bs->buffer[cmc_bidx_to_widx(word_bits * 21 + 1)]); + + cmc_assert(bs_set_range(bs, 0, word_bits * 100 - 1)); + cmc_assert_equals(size_t, 100, bs->capacity); + + for (size_t i = 0; i < bs->capacity; i++) + cmc_assert_equals(CMC_BITSET_WORD_TYPE, ~((cmc_bitset_word)0), bs->buffer[i]); + + bs_free(bs); + }); + + CMC_CREATE_TEST(PFX##_clear(), { + struct bitset *bs = bs_new(word_bits * 10 - 1); + + cmc_assert_not_equals(ptr, NULL, bs); + cmc_assert_equals(CMC_BITSET_WORD_TYPE, 0, bs->buffer[0]); + + bs->buffer[0] = 1; // 0001 + cmc_assert(bs_clear(bs, 0)); + cmc_assert_equals(CMC_BITSET_WORD_TYPE, 0, bs->buffer[0]); + + bs->buffer[0] = 10; // 1010 + cmc_assert(bs_clear(bs, 1)); + cmc_assert(bs_clear(bs, 3)); + cmc_assert_equals(CMC_BITSET_WORD_TYPE, 0, bs->buffer[0]); + + cmc_assert(bs_clear(bs, word_bits * 100 - 1)); + cmc_assert_equals(size_t, 100, bs->capacity); + + bs_free(bs); + }); + + CMC_CREATE_TEST(PFX##_clear_range(), { + struct bitset *bs = bs_new(word_bits * 10 - 1); + + cmc_assert_not_equals(ptr, NULL, bs); + cmc_assert_equals(CMC_BITSET_WORD_TYPE, 0, bs->buffer[0]); + + cmc_assert(!bs_clear_range(bs, 1, 0)); + cmc_assert_equals(int32_t, CMC_FLAG_INVALID, bs->flag); + + cmc_assert(bs_clear_range(bs, 0, word_bits * 100 - 1)); + cmc_assert_equals(size_t, 100, bs->capacity); + + cmc_assert(bs_set_range(bs, word_bits * 20, word_bits * 21 - 1)); + cmc_assert(bs_clear_range(bs, word_bits * 20, word_bits * 21 - 1)); + + cmc_assert_equals(uint32_t, 0, bs->buffer[cmc_bidx_to_widx(word_bits * 20)]); + + for (size_t i = 0; i < bs->capacity; i++) + bs->buffer[i] = ~((cmc_bitset_word)0); + + cmc_assert(bs_set_range(bs, 0, word_bits * 100 - 1)); + cmc_assert(bs_clear_range(bs, 0, word_bits * 100 - 1)); + + cmc_assert_equals(size_t, 100, bs->capacity); + + for (size_t i = 0; i < bs->capacity; i++) + cmc_assert_equals(size_t, 0, bs->buffer[0]); + + cmc_assert(bs_clear_range(bs, 0, word_bits * 200 - 1)); + cmc_assert_equals(size_t, 200, bs->capacity); + + bs_free(bs); + }); + + CMC_CREATE_TEST(PFX##_flip(), { + struct bitset *bs = bs_new(word_bits * 10 - 1); + + cmc_assert_not_equals(ptr, NULL, bs); + cmc_assert_equals(CMC_BITSET_WORD_TYPE, 0, bs->buffer[0]); + + cmc_assert(bs_flip(bs, 0)); + cmc_assert_equals(CMC_BITSET_WORD_TYPE, 1, bs->buffer[0]); + + cmc_assert(bs_flip(bs, 0)); + cmc_assert_equals(CMC_BITSET_WORD_TYPE, 0, bs->buffer[0]); + + cmc_assert(bs_set_range(bs, 0, 2)); // 0111 + cmc_assert_equals(CMC_BITSET_WORD_TYPE, 7, bs->buffer[0]); + cmc_assert(bs_flip(bs, 1)); // 0101 + cmc_assert_equals(CMC_BITSET_WORD_TYPE, 5, bs->buffer[0]); + + cmc_assert(bs_flip(bs, word_bits * 100 - 1)); + cmc_assert_equals(size_t, 100, bs->capacity); + + bs_free(bs); + }); + + CMC_CREATE_TEST(PFX##_flip_range(), { + struct bitset *bs = bs_new(word_bits * 10 - 1); + + cmc_assert_not_equals(ptr, NULL, bs); + cmc_assert_equals(CMC_BITSET_WORD_TYPE, 0, bs->buffer[0]); + + cmc_assert(bs_flip_range(bs, 0, 0)); + cmc_assert_equals(CMC_BITSET_WORD_TYPE, 1, bs->buffer[0]); + + cmc_assert(bs_flip_range(bs, 0, 0)); + cmc_assert_equals(CMC_BITSET_WORD_TYPE, 0, bs->buffer[0]); + + cmc_assert(bs_flip_range(bs, 1, 4)); // 0001 1110 + cmc_assert_equals(CMC_BITSET_WORD_TYPE, 30, bs->buffer[0]); + + cmc_assert(bs_flip_range(bs, 2, 3)); // 0001 0010 + cmc_assert_equals(CMC_BITSET_WORD_TYPE, 18, bs->buffer[0]); + + cmc_assert(bs_flip_range(bs, 0, 2)); // 0001 0101 + cmc_assert_equals(CMC_BITSET_WORD_TYPE, 21, bs->buffer[0]); + + bs->buffer[0] = 0; + + cmc_assert(bs_flip_range(bs, 0, word_bits * 100 - 1)); + cmc_assert_equals(size_t, 100, bs->capacity); + + for (size_t i = 0; i < bs->capacity; i++) + cmc_assert_equals(CMC_BITSET_WORD_TYPE, ~((cmc_bitset_word)0), bs->buffer[i]); + + bs_free(bs); + }); + + CMC_CREATE_TEST(PFX##_put(), { + struct bitset *bs = bs_new(word_bits * 10 - 1); + + cmc_assert_not_equals(ptr, NULL, bs); + cmc_assert_equals(CMC_BITSET_WORD_TYPE, 0, bs->buffer[0]); + + cmc_assert(bs_put(bs, 1, true)); // 0010 + cmc_assert_equals(CMC_BITSET_WORD_TYPE, 2, bs->buffer[0]); + cmc_assert(bs_put(bs, 0, false)); // 0010 + cmc_assert_equals(CMC_BITSET_WORD_TYPE, 2, bs->buffer[0]); + cmc_assert(bs_put(bs, 1, false)); // 0000 + cmc_assert_equals(CMC_BITSET_WORD_TYPE, 0, bs->buffer[0]); + cmc_assert(bs_put(bs, 3, true)); // 1000 + cmc_assert_equals(CMC_BITSET_WORD_TYPE, 8, bs->buffer[0]); + cmc_assert(bs_put(bs, 0, true)); // 1001 + cmc_assert_equals(CMC_BITSET_WORD_TYPE, 9, bs->buffer[0]); + cmc_assert(bs_put(bs, 3, false)); // 0001 + cmc_assert_equals(CMC_BITSET_WORD_TYPE, 1, bs->buffer[0]); + + cmc_assert(bs_put(bs, word_bits * 100 - 1, true)); + cmc_assert_equals(size_t, 100, bs->capacity); + + bs_free(bs); + }); + + CMC_CREATE_TEST(PFX##_put_range(), { + struct bitset *bs = bs_new(word_bits * 10 - 1); + + cmc_assert_not_equals(ptr, NULL, bs); + cmc_assert_equals(CMC_BITSET_WORD_TYPE, 0, bs->buffer[0]); + + cmc_assert(bs_put_range(bs, 1, 2, true)); // 0110 + cmc_assert_equals(CMC_BITSET_WORD_TYPE, 6, bs->buffer[0]); + cmc_assert(bs_put_range(bs, 0, 1, false)); // 0100 + cmc_assert_equals(CMC_BITSET_WORD_TYPE, 4, bs->buffer[0]); + cmc_assert(bs_put_range(bs, 1, 3, true)); // 1110 + cmc_assert_equals(CMC_BITSET_WORD_TYPE, 14, bs->buffer[0]); + cmc_assert(bs_put_range(bs, 2, 3, false)); // 0010 + cmc_assert_equals(CMC_BITSET_WORD_TYPE, 2, bs->buffer[0]); + + cmc_assert(bs_put_range(bs, 0, word_bits * 100 - 1, true)); + cmc_assert_equals(size_t, 100, bs->capacity); + + for (size_t i = 0; i < bs->capacity; i++) + cmc_assert_equals(CMC_BITSET_WORD_TYPE, ~((cmc_bitset_word)0), bs->buffer[i]); + + cmc_assert(bs_put_range(bs, 0, word_bits * 100 - 1, false)); + for (size_t i = 0; i < bs->capacity; i++) + cmc_assert_equals(CMC_BITSET_WORD_TYPE, 0, bs->buffer[i]); + + bs_free(bs); + }); + + CMC_CREATE_TEST(PFX##_set_all(), { + struct bitset *bs = bs_new(word_bits * 10 - 1); + + cmc_assert_not_equals(ptr, NULL, bs); + + cmc_assert(bs_set_all(bs)); + + for (size_t i = 0; i < bs->capacity; i++) + cmc_assert_equals(CMC_BITSET_WORD_TYPE, ~((cmc_bitset_word)0), bs->buffer[i]); + + bs_free(bs); + }); + + CMC_CREATE_TEST(PFX##_clear_all(), { + struct bitset *bs = bs_new(word_bits * 10 - 1); + + cmc_assert_not_equals(ptr, NULL, bs); + + cmc_assert(bs_set_all(bs)); + cmc_assert(bs_clear_all(bs)); + + for (size_t i = 0; i < bs->capacity; i++) + cmc_assert_equals(CMC_BITSET_WORD_TYPE, 0, bs->buffer[i]); + + bs_free(bs); + }); + + CMC_CREATE_TEST(PFX##_flip_all(), { + struct bitset *bs = bs_new(word_bits * 10 - 1); + + cmc_assert_not_equals(ptr, NULL, bs); + + cmc_assert(bs_flip_all(bs)); + for (size_t i = 0; i < bs->capacity; i++) + cmc_assert_equals(CMC_BITSET_WORD_TYPE, ~((cmc_bitset_word)0), bs->buffer[i]); + + cmc_assert(bs_flip_all(bs)); + for (size_t i = 0; i < bs->capacity; i++) + cmc_assert_equals(CMC_BITSET_WORD_TYPE, 0, bs->buffer[i]); + + bs_free(bs); + }); + + CMC_CREATE_TEST(PFX##_get(), { + struct bitset *bs = bs_new(64); + + cmc_assert_not_equals(ptr, NULL, bs); + + cmc_assert(bs_set(bs, 1)); + + cmc_assert(bs_get(bs, 1)); + + bs_free(bs); + }); + + CMC_CREATE_TEST(PFX##_resize(), { + struct bitset *bs = bs_new(64); + + // WIP + + bs_free(bs); + }); +}); + +CMC_CREATE_UNIT(CMCBitSetIter, true, { + // const size_t word_bytes = sizeof(cmc_bitset_word); + // const size_t word_bits = sizeof(cmc_bitset_word) * CHAR_BIT; + + printf("%s", cmc_test_color(5)); + printf(" BitSet<" CMC_TO_STRING(CMC_BITSET_WORD_TYPE) ">\n"); + printf("%s", cmc_test_color(0)); + + CMC_CREATE_TEST(PFX##_iter_start(), { + struct bitset *bs = bs_new(64); + + // WIP + + bs_free(bs); + }); +}); + +#endif /* CMC_TESTS_UNT_BITSET_H */ diff --git a/tests/unt_hashmultimap.h b/tests/unt_hashmultimap.h index 99a7886..4613d27 100644 --- a/tests/unt_hashmultimap.h +++ b/tests/unt_hashmultimap.h @@ -308,6 +308,7 @@ CMC_CREATE_UNIT(CMCHashMultiMap, true, { cmc_assert(hmm_equals(map, map2)); hmm_free(map); + hmm_free(map2); }); CMC_CREATE_TEST(PFX##_equals(), { @@ -1013,19 +1014,4 @@ CMC_CREATE_UNIT(CMCHashMultiMapIter, true, { }); }); -#ifdef CMC_TEST_MAIN -int main(void) -{ - int result = CMCHashMultiMap() + CMCHashMultiMapIter(); - - printf(" +---------------------------------------------------------------+"); - printf("\n"); - printf(" | CMCHashMultiMap Suit : %-41s |\n", result == 0 ? "PASSED" : "FAILED"); - printf(" +---------------------------------------------------------------+"); - printf("\n\n\n"); - - return result; -} -#endif - #endif /* CMC_TESTS_UNT_HASHMULTIMAP_H */ diff --git a/tests/unt_hashmultiset.h b/tests/unt_hashmultiset.h index 6bddbfd..a06cfe6 100644 --- a/tests/unt_hashmultiset.h +++ b/tests/unt_hashmultiset.h @@ -853,19 +853,4 @@ CMC_CREATE_UNIT(CMCHashMultiSetIter, true, { }); }); -#ifdef CMC_TEST_MAIN -int main(void) -{ - int result = CMCHashMultiSet() + CMCHashMultiSetIter(); - - printf(" +---------------------------------------------------------------+"); - printf("\n"); - printf(" | CMCHashMultiSet Suit : %-41s |\n", result == 0 ? "PASSED" : "FAILED"); - printf(" +---------------------------------------------------------------+"); - printf("\n\n\n"); - - return result; -} -#endif - #endif /* CMC_TESTS_UNT_HASHMULTISET_H */ diff --git a/tests/unt_hashset.h b/tests/unt_hashset.h index b381f97..119b66b 100644 --- a/tests/unt_hashset.h +++ b/tests/unt_hashset.h @@ -1033,19 +1033,4 @@ CMC_CREATE_UNIT(CMCHashSetIter, true, { }); }); -#ifdef CMC_TEST_MAIN -int main(void) -{ - int result = CMCHashSet() + CMCHashSetIter(); - - printf(" +---------------------------------------------------------------+"); - printf("\n"); - printf(" | CMCHashSet Suit : %-46s |\n", result == 0 ? "PASSED" : "FAILED"); - printf(" +---------------------------------------------------------------+"); - printf("\n\n\n"); - - return result; -} -#endif - #endif /* CMC_TESTS_UNT_HASHSET_H */ diff --git a/tests/unt_heap.h b/tests/unt_heap.h new file mode 100644 index 0000000..a2bebd7 --- /dev/null +++ b/tests/unt_heap.h @@ -0,0 +1,720 @@ +#ifndef CMC_TESTS_UNT_HEAP_H +#define CMC_TESTS_UNT_HEAP_H + +#include "utl.h" + +#define V size_t +#define PFX h +#define SNAME heap +#define CMC_EXT_HEAP_INIT +#define CMC_EXT_HEAP_ITER +#define CMC_EXT_HEAP_STR +#include "cmc/heap.h" + +struct heap_fval *h_fval = &(struct heap_fval){ + .cmp = cmc_size_cmp, .cpy = NULL, .str = cmc_size_str, .free = NULL, .hash = cmc_size_hash, .pri = cmc_size_cmp +}; + +CMC_CREATE_UNIT(CMCHeap, true, { + CMC_CREATE_TEST(new, { + struct heap *h = h_new(1000000, CMC_MAX_HEAP, h_fval); + + cmc_assert_not_equals(ptr, NULL, h); + cmc_assert_not_equals(ptr, NULL, h->buffer); + cmc_assert_equals(size_t, 1000000, h_capacity(h)); + cmc_assert_equals(size_t, 0, h_count(h)); + + h_free(h); + }); + + CMC_CREATE_TEST(new[edge_case capacity = 0], { + struct heap *h = h_new(0, CMC_MAX_HEAP, h_fval); + + cmc_assert_equals(ptr, NULL, h); + }); + + CMC_CREATE_TEST(new[edge_case capacity = UINT64_MAX], { + struct heap *h = h_new(UINT64_MAX, CMC_MAX_HEAP, h_fval); + + cmc_assert_equals(ptr, NULL, h); + }); + + CMC_CREATE_TEST(clear[count capacity], { + struct heap *h = h_new(100, CMC_MAX_HEAP, h_fval); + + cmc_assert_not_equals(ptr, NULL, h); + + for (size_t i = 0; i < 50; i++) + h_insert(h, i); + + cmc_assert_equals(size_t, 50, h_count(h)); + + h_clear(h); + + cmc_assert_equals(size_t, 0, h_count(h)); + cmc_assert_equals(size_t, 100, h_capacity(h)); + + h_free(h); + }); + + CMC_CREATE_TEST(buffer_growth[edge_case capacity = 1], { + struct heap *h = h_new(1, CMC_MAX_HEAP, h_fval); + + cmc_assert_not_equals(ptr, NULL, h); + + for (size_t i = 0; i < 50; i++) + cmc_assert(h_insert(h, i)); + + cmc_assert_equals(size_t, 50, h_count(h)); + + h_free(h); + }); + + CMC_CREATE_TEST(insert, { + struct heap *h = h_new(100, CMC_MAX_HEAP, h_fval); + + cmc_assert_not_equals(ptr, NULL, h); + + cmc_assert(h_insert(h, 10)); + + h_free(h); + }); + + CMC_CREATE_TEST(insert[item preservation], { + struct heap *h = h_new(50, CMC_MAX_HEAP, h_fval); + + cmc_assert_not_equals(ptr, NULL, h); + + for (size_t i = 0; i <= 100; i++) + cmc_assert(h_insert(h, i)); + + size_t sum = 0; + for (size_t i = 0; i < h_count(h); i++) + sum += h->buffer[i]; + + cmc_assert_equals(size_t, 5050, sum); + + h_free(h); + }); + + CMC_CREATE_TEST(remove, { + struct heap *h = h_new(50, CMC_MAX_HEAP, h_fval); + + cmc_assert_not_equals(ptr, NULL, h); + + for (size_t i = 0; i <= 100; i++) + cmc_assert(h_insert(h, i)); + + cmc_assert_equals(size_t, 100, h_peek(h)); + cmc_assert(h_remove(h)); + cmc_assert_equals(size_t, 99, h_peek(h)); + + h_free(h); + }); + + CMC_CREATE_TEST(remove[count = 0], { + struct heap *h = h_new(100, CMC_MAX_HEAP, h_fval); + + cmc_assert_not_equals(ptr, NULL, h); + + cmc_assert(!h_remove(h)); + + h_free(h); + }); + + CMC_CREATE_TEST(remove[sorted], { + struct heap *h = h_new(100, CMC_MIN_HEAP, h_fval); + + cmc_assert_not_equals(ptr, NULL, h); + + for (size_t i = 1; i <= 100; i++) + cmc_assert(h_insert(h, i)); + + size_t i = 0; + size_t arr[100]; + while (!h_empty(h)) + { + arr[i++] = h_peek(h); + cmc_assert(h_remove(h)); + } + + cmc_assert_array_sorted_any(size_t, arr, cmc_size_cmp, 0, 99); + + h_free(h); + }); + + CMC_CREATE_TEST(peek, { + struct heap *h = h_new(100, CMC_MAX_HEAP, h_fval); + + cmc_assert_not_equals(ptr, NULL, h); + + for (size_t i = 1; i <= 100; i++) + cmc_assert(h_insert(h, i)); + + cmc_assert_equals(size_t, 100, h_peek(h)); + + h_free(h); + }); + + CMC_CREATE_TEST(peek[count = 0], { + struct heap *h = h_new(100, CMC_MAX_HEAP, h_fval); + + cmc_assert_not_equals(ptr, NULL, h); + + cmc_assert_equals(size_t, (size_t){ 0 }, h_peek(h)); + + h_free(h); + }); + + CMC_CREATE_TEST(flags, { + struct heap *h = h_new(100, CMC_MAX_HEAP, h_fval); + + cmc_assert_not_equals(ptr, NULL, h); + cmc_assert_equals(int32_t, CMC_FLAG_OK, h_flag(h)); + + h->flag = CMC_FLAG_ERROR; + + // insert + cmc_assert(h_insert(h, 10)); + cmc_assert_equals(int32_t, CMC_FLAG_OK, h_flag(h)); + + h->flag = CMC_FLAG_ERROR; + + // remove + cmc_assert(h_remove(h)); + cmc_assert_equals(int32_t, CMC_FLAG_OK, h_flag(h)); + + cmc_assert(!h_remove(h)); + cmc_assert_equals(int32_t, CMC_FLAG_EMPTY, h_flag(h)); + + // peek + cmc_assert(h_insert(h, 10)); + h_peek(h); + cmc_assert_equals(int32_t, CMC_FLAG_OK, h_flag(h)); + cmc_assert(h_remove(h)); + h_peek(h); + cmc_assert_equals(int32_t, CMC_FLAG_EMPTY, h_flag(h)); + + // clear + h_clear(h); + cmc_assert_equals(int32_t, CMC_FLAG_OK, h_flag(h)); + + h->flag = CMC_FLAG_ERROR; + + // contains + h_contains(h, 10); + cmc_assert_equals(int32_t, CMC_FLAG_OK, h_flag(h)); + + h->flag = CMC_FLAG_ERROR; + + // copy of + struct heap *h2 = h_copy_of(h); + cmc_assert_equals(int32_t, CMC_FLAG_OK, h_flag(h)); + cmc_assert_equals(int32_t, CMC_FLAG_OK, h_flag(h2)); + + h->flag = CMC_FLAG_ERROR; + h2->flag = CMC_FLAG_ERROR; + + // equals + cmc_assert(h_equals(h, h2)); + cmc_assert_equals(int32_t, CMC_FLAG_OK, h_flag(h)); + cmc_assert_equals(int32_t, CMC_FLAG_OK, h_flag(h2)); + + h_free(h); + h_free(h2); + }); + + CMC_CREATE_TEST(callbacks, { + struct heap *h = h_new_custom(100, CMC_MAX_HEAP, h_fval, NULL, callbacks); + + cmc_assert_not_equals(ptr, NULL, h); + + total_create = 0; + total_read = 0; + total_update = 0; + total_delete = 0; + total_resize = 0; + + cmc_assert(h_insert(h, 10)); + cmc_assert_equals(int32_t, 1, total_create); + + cmc_assert(h_remove(h)); + cmc_assert_equals(int32_t, 1, total_delete); + + cmc_assert(h_insert(h, 10)); + cmc_assert_equals(int32_t, 2, total_create); + + cmc_assert_equals(size_t, 10, h_peek(h)); + cmc_assert_equals(int32_t, 1, total_read); + + cmc_assert(h_contains(h, 10)); + cmc_assert_equals(int32_t, 2, total_read); + + cmc_assert(h_resize(h, 1000)); + cmc_assert_equals(int32_t, 1, total_resize); + + cmc_assert(h_resize(h, 100)); + cmc_assert_equals(int32_t, 2, total_resize); + + cmc_assert_equals(int32_t, 2, total_create); + cmc_assert_equals(int32_t, 2, total_read); + cmc_assert_equals(int32_t, 0, total_update); + cmc_assert_equals(int32_t, 1, total_delete); + cmc_assert_equals(int32_t, 2, total_resize); + + h_customize(h, NULL, NULL); + + cmc_assert_equals(ptr, NULL, h->callbacks); + + h_clear(h); + cmc_assert(h_insert(h, 10)); + cmc_assert(h_remove(h)); + cmc_assert(h_insert(h, 10)); + cmc_assert_equals(size_t, 10, h_peek(h)); + cmc_assert(h_contains(h, 10)); + cmc_assert(h_resize(h, 1000)); + cmc_assert(h_resize(h, 100)); + + cmc_assert_equals(int32_t, 2, total_create); + cmc_assert_equals(int32_t, 2, total_read); + cmc_assert_equals(int32_t, 0, total_update); + cmc_assert_equals(int32_t, 1, total_delete); + cmc_assert_equals(int32_t, 2, total_resize); + + cmc_assert_equals(ptr, NULL, h->callbacks); + + h_free(h); + + total_create = 0; + total_read = 0; + total_update = 0; + total_delete = 0; + total_resize = 0; + }); +}); + +CMC_CREATE_UNIT(CMCHeapIter, true, { + CMC_CREATE_TEST(PFX##_iter_start(), { + struct heap *h = h_new(100, CMC_MAX_HEAP, h_fval); + + cmc_assert_not_equals(ptr, NULL, h); + + struct heap_iter it = h_iter_start(h); + + cmc_assert_equals(ptr, h, it.target); + cmc_assert_equals(size_t, 0, it.cursor); + cmc_assert_equals(bool, true, it.start); + cmc_assert_equals(bool, true, it.end); + + cmc_assert(h_iter_at_start(&it)); + cmc_assert(h_iter_at_end(&it)); + + cmc_assert(h_insert(h, 1)); + cmc_assert(h_insert(h, 2)); + + it = h_iter_start(h); + + cmc_assert_equals(size_t, 0, it.cursor); + cmc_assert_equals(bool, false, it.end); + + h_free(h); + }); + + CMC_CREATE_TEST(PFX##_iter_end(), { + struct heap *h = h_new(100, CMC_MAX_HEAP, h_fval); + + cmc_assert_not_equals(ptr, NULL, h); + + struct heap_iter it = h_iter_end(h); + + cmc_assert_equals(ptr, h, it.target); + cmc_assert_equals(size_t, 0, it.cursor); + cmc_assert_equals(bool, true, it.start); + cmc_assert_equals(bool, true, it.end); + + cmc_assert(h_iter_at_start(&it)); + cmc_assert(h_iter_at_end(&it)); + + cmc_assert(h_insert(h, 1)); + cmc_assert(h_insert(h, 2)); + cmc_assert(h_insert(h, 3)); + + it = h_iter_end(h); + + cmc_assert_equals(size_t, h->count - 1, it.cursor); + cmc_assert_equals(bool, false, it.start); + + h_free(h); + }); + + CMC_CREATE_TEST(PFX##_iter_at_start(), { + struct heap *h = h_new(100, CMC_MAX_HEAP, h_fval); + + cmc_assert_not_equals(ptr, NULL, h); + + struct heap_iter it = h_iter_start(h); + + // Empty checks + cmc_assert(h_iter_at_start(&it)); + it = h_iter_end(h); + cmc_assert(h_iter_at_start(&it)); + + // Non-empty check + cmc_assert(h_insert(h, 1)); + it = h_iter_end(h); + cmc_assert(!h_iter_at_start(&it)); + it = h_iter_start(h); + cmc_assert(h_iter_at_start(&it)); + + h_free(h); + }); + + CMC_CREATE_TEST(PFX##_iter_at_end(), { + struct heap *h = h_new(100, CMC_MAX_HEAP, h_fval); + + cmc_assert_not_equals(ptr, NULL, h); + + struct heap_iter it = h_iter_start(h); + + // Empty check + cmc_assert(h_iter_at_end(&it)); + it = h_iter_end(h); + cmc_assert(h_iter_at_end(&it)); + + // Non-empty check + cmc_assert(h_insert(h, 1)); + it = h_iter_end(h); + cmc_assert(h_iter_at_end(&it)); + it = h_iter_start(h); + cmc_assert(!h_iter_at_end(&it)); + + h_free(h); + }); + + CMC_CREATE_TEST(PFX##_iter_to_start(), { + struct heap *h = h_new(100, CMC_MAX_HEAP, h_fval); + + cmc_assert_not_equals(ptr, NULL, h); + + struct heap_iter it = h_iter_start(h); + + cmc_assert(!h_iter_to_start(&it)); + + for (size_t i = 1; i <= 100; i++) + { + if (i % 2 == 0) + h_insert(h, i); + else + h_insert(h, i); + } + + cmc_assert_equals(size_t, 100, h->count); + + it = h_iter_end(h); + cmc_assert(!h_iter_at_start(&it)); + cmc_assert(h_iter_at_end(&it)); + cmc_assert_equals(size_t, 99, it.cursor); + + cmc_assert(h_iter_to_start(&it)); + cmc_assert(h_iter_at_start(&it)); + cmc_assert(!h_iter_at_end(&it)); + cmc_assert_equals(size_t, 0, it.cursor); + + h_free(h); + }); + + CMC_CREATE_TEST(PFX##_iter_to_end(), { + struct heap *h = h_new(100, CMC_MAX_HEAP, h_fval); + + cmc_assert_not_equals(ptr, NULL, h); + + struct heap_iter it = h_iter_end(h); + + cmc_assert(!h_iter_to_end(&it)); + + for (size_t i = 1; i <= 100; i++) + { + if (i % 2 == 0) + h_insert(h, i); + else + h_insert(h, i); + } + + it = h_iter_start(h); + cmc_assert(h_iter_at_start(&it)); + cmc_assert(!h_iter_at_end(&it)); + + cmc_assert(h_iter_to_end(&it)); + cmc_assert(!h_iter_at_start(&it)); + cmc_assert(h_iter_at_end(&it)); + + h_free(h); + }); + + CMC_CREATE_TEST(PFX##_iter_next(), { + struct heap *h = h_new(100, CMC_MAX_HEAP, h_fval); + + cmc_assert_not_equals(ptr, NULL, h); + + struct heap_iter it = h_iter_start(h); + + cmc_assert(!h_iter_next(&it)); + + for (size_t i = 1; i <= 1000; i++) + { + if (i % 2 == 0) + h_insert(h, i); + else + h_insert(h, i); + } + + size_t sum = 0; + for (it = h_iter_start(h); !h_iter_at_end(&it); h_iter_next(&it)) + { + sum += h_iter_value(&it); + } + + cmc_assert_equals(size_t, 500500, sum); + + sum = 0; + + h_iter_to_start(&it); + do + { + sum += h_iter_value(&it); + } while (h_iter_next(&it)); + + cmc_assert_equals(size_t, 500500, sum); + + h_free(h); + }); + + CMC_CREATE_TEST(PFX##_iter_prev(), { + struct heap *h = h_new(100, CMC_MAX_HEAP, h_fval); + + cmc_assert_not_equals(ptr, NULL, h); + + struct heap_iter it = h_iter_end(h); + + cmc_assert(!h_iter_prev(&it)); + + for (size_t i = 1; i <= 1000; i++) + { + if (i % 2 == 0) + h_insert(h, i); + else + h_insert(h, i); + } + + size_t sum = 0; + for (it = h_iter_end(h); !h_iter_at_start(&it); h_iter_prev(&it)) + { + sum += h_iter_value(&it); + } + + cmc_assert_equals(size_t, 500500, sum); + + sum = 0; + + h_iter_to_end(&it); + do + { + sum += h_iter_value(&it); + } while (h_iter_prev(&it)); + + cmc_assert_equals(size_t, 500500, sum); + + h_free(h); + }); + + CMC_CREATE_TEST(PFX##_iter_advance(), { + struct heap *h = h_new(100, CMC_MAX_HEAP, h_fval); + + cmc_assert_not_equals(ptr, NULL, h); + + struct heap_iter it = h_iter_start(h); + + cmc_assert(!h_iter_advance(&it, 1)); + + for (size_t i = 1; i <= 1000; i++) + h_insert(h, i); + + it = h_iter_start(h); + + cmc_assert(!h_iter_advance(&it, 0)); + cmc_assert(!h_iter_advance(&it, h->count)); + + size_t sum = 0; + for (it = h_iter_start(h);;) + { + sum += h_iter_value(&it); + + if (!h_iter_advance(&it, 2)) + break; + + cmc_assert_equals(size_t, 0, h_iter_index(&it) % 2); + } + + cmc_assert(h_iter_to_start(&it)); + cmc_assert(h_iter_next(&it)); + + cmc_assert_equals(size_t, 1, h_iter_index(&it)); + + for (;;) + { + sum += h_iter_value(&it); + + if (!h_iter_advance(&it, 2)) + break; + + cmc_assert_equals(size_t, 1, h_iter_index(&it) % 2); + } + + cmc_assert_equals(size_t, 500500, sum); + + h_iter_to_start(&it); + cmc_assert(h_iter_advance(&it, h->count - 1)); + + h_free(h); + }); + + CMC_CREATE_TEST(PFX##_iter_rewind(), { + struct heap *h = h_new(100, CMC_MAX_HEAP, h_fval); + + cmc_assert_not_equals(ptr, NULL, h); + + struct heap_iter it = h_iter_end(h); + + cmc_assert(!h_iter_rewind(&it, 1)); + + for (size_t i = 0; i <= 1000; i++) + h_insert(h, i); + + it = h_iter_end(h); + + cmc_assert(!h_iter_rewind(&it, 0)); + cmc_assert(!h_iter_rewind(&it, h->count)); + + size_t sum = 0; + for (it = h_iter_end(h);;) + { + sum += h_iter_value(&it); + + if (!h_iter_rewind(&it, 2)) + break; + + cmc_assert_equals(size_t, 0, h_iter_index(&it) % 2); + } + + cmc_assert(h_iter_to_end(&it)); + cmc_assert(h_iter_prev(&it)); + + cmc_assert_equals(size_t, h->count - 2, h_iter_index(&it)); + + for (;;) + { + sum += h_iter_value(&it); + + if (!h_iter_rewind(&it, 2)) + break; + + cmc_assert_equals(size_t, 1, h_iter_index(&it) % 2); + } + + cmc_assert_equals(size_t, 500500, sum); + + h_iter_to_end(&it); + cmc_assert(h_iter_rewind(&it, h->count - 1)); + + h_free(h); + }); + + CMC_CREATE_TEST(PFX##_iter_go_to(), { + struct heap *h = h_new(100, CMC_MAX_HEAP, h_fval); + + cmc_assert_not_equals(ptr, NULL, h); + + struct heap_iter it = h_iter_end(h); + cmc_assert(!h_iter_go_to(&it, 0)); + + it = h_iter_start(h); + cmc_assert(!h_iter_go_to(&it, 0)); + + for (size_t i = 0; i <= 1000; i++) + h_insert(h, i); + + cmc_assert_equals(size_t, 1001, h->count); + + it = h_iter_start(h); + + size_t sum = 0; + for (size_t i = 0; i < 1001; i++) + { + h_iter_go_to(&it, i); + + sum += h_iter_value(&it); + } + + cmc_assert_equals(size_t, 500500, sum); + + sum = 0; + for (size_t i = 1001; i > 0; i--) + { + cmc_assert(h_iter_go_to(&it, i - 1)); + + sum += h_iter_value(&it); + } + + cmc_assert_equals(size_t, 500500, sum); + + h_free(h); + }); + + CMC_CREATE_TEST(PFX##_iter_value(), { + struct heap *h = h_new(100, CMC_MAX_HEAP, h_fval); + + cmc_assert_not_equals(ptr, NULL, h); + + struct heap_iter it = h_iter_end(h); + + cmc_assert_equals(size_t, (size_t){ 0 }, h_iter_value(&it)); + + cmc_assert(h_insert(h, 1)); + cmc_assert(h_insert(h, 3)); + cmc_assert(h_insert(h, 2)); + + it = h_iter_start(h); + + cmc_assert_equals(size_t, 3, h_iter_value(&it)); + + h_free(h); + }); + + CMC_CREATE_TEST(PFX##_iter_index(), { + struct heap *h = h_new(100, CMC_MAX_HEAP, h_fval); + + cmc_assert_not_equals(ptr, NULL, h); + + for (size_t i = 0; i <= 1000; i++) + h_insert(h, i); + + struct heap_iter it = h_iter_start(h); + + for (size_t i = 0; i < 1001; i++) + { + cmc_assert_equals(size_t, i, h_iter_index(&it)); + h_iter_next(&it); + } + + it = h_iter_end(h); + for (size_t i = 1001; i > 0; i--) + { + cmc_assert_equals(size_t, i - 1, h_iter_index(&it)); + h_iter_prev(&it); + } + + h_free(h); + }); +}); + +#endif /* CMC_TESTS_UNT_HEAP_H */ diff --git a/tests/unt_intervalheap.h b/tests/unt_intervalheap.h new file mode 100644 index 0000000..0621d3e --- /dev/null +++ b/tests/unt_intervalheap.h @@ -0,0 +1,1045 @@ +#ifndef CMC_TESTS_UNT_INTERVALHEAP_H +#define CMC_TESTS_UNT_INTERVALHEAP_H + +#include "utl.h" + +#define V size_t +#define PFX ih +#define SNAME intervalheap +#define CMC_EXT_INTERVALHEAP_INIT +#define CMC_EXT_INTERVALHEAP_ITER +#define CMC_EXT_INTERVALHEAP_STR +#include "cmc/intervalheap.h" + +struct intervalheap_fval *ih_fval = &(struct intervalheap_fval){ + .cmp = cmc_size_cmp, .cpy = NULL, .str = cmc_size_str, .free = NULL, .hash = cmc_size_hash, .pri = cmc_size_cmp +}; + +struct intervalheap_fval *ih_fval_counter = &(struct intervalheap_fval){ + .cmp = v_c_cmp, .cpy = v_c_cpy, .str = v_c_str, .free = v_c_free, .hash = v_c_hash, .pri = v_c_pri +}; + +struct cmc_alloc_node *ih_alloc_node = + &(struct cmc_alloc_node){ .malloc = malloc, .calloc = calloc, .realloc = realloc, .free = free }; + +CMC_CREATE_UNIT(CMCIntervalHeap, true, { + CMC_CREATE_TEST(PFX##_new(), { + struct intervalheap *ih = ih_new(1000000, ih_fval); + + cmc_assert_not_equals(ptr, NULL, ih); + cmc_assert_not_equals(ptr, NULL, ih->buffer); + cmc_assert_equals(size_t, 500000, ih_capacity(ih)); + cmc_assert_equals(size_t, 0, ih_count(ih)); + + ih_free(ih); + + ih = ih_new(0, ih_fval); + + cmc_assert_equals(ptr, NULL, ih); + + ih = ih_new(UINT64_MAX, ih_fval); + + cmc_assert_equals(ptr, NULL, ih); + + ih = ih_new(1, ih_fval); + + cmc_assert_not_equals(ptr, NULL, ih); + cmc_assert_equals(size_t, 1, ih_capacity(ih)); + + ih_free(ih); + + ih = ih_new(2, ih_fval); + + cmc_assert_not_equals(ptr, NULL, ih); + cmc_assert_equals(size_t, 1, ih_capacity(ih)); + + ih_free(ih); + + ih = ih_new(3, ih_fval); + + cmc_assert_not_equals(ptr, NULL, ih); + cmc_assert_equals(size_t, 2, ih_capacity(ih)); + + ih_free(ih); + + ih = ih_new(4, ih_fval); + cmc_assert_not_equals(ptr, NULL, ih); + cmc_assert_equals(size_t, 2, ih_capacity(ih)); + + ih_free(ih); + }); + + CMC_CREATE_TEST(PFX##_new_custom(), { + struct intervalheap *ih = ih_new_custom(1000000, ih_fval, ih_alloc_node, callbacks); + + cmc_assert_not_equals(ptr, NULL, ih); + cmc_assert_not_equals(ptr, NULL, ih->buffer); + cmc_assert_equals(size_t, 500000, ih_capacity(ih)); + cmc_assert_equals(size_t, 0, ih_count(ih)); + cmc_assert_equals(ptr, ih_alloc_node, ih->alloc); + cmc_assert_equals(ptr, callbacks, ih->callbacks); + + ih_free(ih); + + ih = ih_new_custom(0, ih_fval, NULL, NULL); + + cmc_assert_equals(ptr, NULL, ih); + + ih = ih_new_custom(UINT64_MAX, ih_fval, NULL, NULL); + + cmc_assert_equals(ptr, NULL, ih); + + ih = ih_new_custom(1, ih_fval, NULL, NULL); + + cmc_assert_not_equals(ptr, NULL, ih); + cmc_assert_equals(size_t, 1, ih_capacity(ih)); + cmc_assert_equals(ptr, cmc_alloc_node_default.malloc, ih->alloc->malloc); + cmc_assert_equals(ptr, cmc_alloc_node_default.calloc, ih->alloc->calloc); + cmc_assert_equals(ptr, cmc_alloc_node_default.realloc, ih->alloc->realloc); + cmc_assert_equals(ptr, cmc_alloc_node_default.free, ih->alloc->free); + cmc_assert_equals(ptr, NULL, ih->callbacks); + + ih_free(ih); + + ih = ih_new_custom(2, ih_fval, NULL, NULL); + + cmc_assert_not_equals(ptr, NULL, ih); + cmc_assert_equals(size_t, 1, ih_capacity(ih)); + + ih_free(ih); + + ih = ih_new_custom(3, ih_fval, NULL, NULL); + + cmc_assert_not_equals(ptr, NULL, ih); + cmc_assert_equals(size_t, 2, ih_capacity(ih)); + + ih_free(ih); + + ih = ih_new_custom(4, ih_fval, NULL, NULL); + + cmc_assert_not_equals(ptr, NULL, ih); + cmc_assert_equals(size_t, 2, ih_capacity(ih)); + + ih_free(ih); + }); + + CMC_CREATE_TEST(PFX##_clear(), { + v_total_free = 0; + struct intervalheap *ih = ih_new(100, ih_fval); + + cmc_assert_not_equals(ptr, NULL, ih); + + for (size_t i = 0; i < 50; i++) + ih_insert(ih, i); + + cmc_assert_equals(size_t, 50, ih_count(ih)); + + ih_clear(ih); + + cmc_assert_equals(size_t, 0, ih_count(ih)); + cmc_assert_equals(size_t, 50, ih_capacity(ih)); + + ih_free(ih); + + ih = ih_new(100, ih_fval_counter); + + ih_insert(ih, 10); + ih_clear(ih); + + cmc_assert_equals(int32_t, 1, v_total_free); + + for (size_t i = 0; i < 10000; i++) + ih_insert(ih, i); + + cmc_assert_equals(size_t, 10000, ih_count(ih)); + + ih_clear(ih); + + cmc_assert_equals(int32_t, 10001, v_total_free); + + size_t sum = 0; + for (size_t i = 0; i < ih->capacity; i++) + sum += ih->buffer[i / 2][i % 2]; + + cmc_assert_equals(size_t, 0, sum); + + ih_free(ih); + + cmc_assert_equals(int32_t, 10001, v_total_free); + + v_total_free = 0; + }); + + CMC_CREATE_TEST(PFX##_free(), { + v_total_free = 0; + struct intervalheap *ih = ih_new(100, ih_fval_counter); + + cmc_assert_not_equals(ptr, NULL, ih); + + ih_insert(ih, 10); + ih_free(ih); + + cmc_assert_equals(int32_t, 1, v_total_free); + + ih = ih_new(100, ih_fval_counter); + + for (size_t i = 0; i < 10000; i++) + ih_insert(ih, i); + + ih_free(ih); + + cmc_assert_equals(int32_t, 10001, v_total_free); + + v_total_free = 0; + }); + + CMC_CREATE_TEST(PFX##_customize(), { + struct intervalheap *ih = ih_new(100, ih_fval); + + ih->flag = CMC_FLAG_ERROR; + ih_customize(ih, ih_alloc_node, callbacks); + + cmc_assert_equals(ptr, ih_alloc_node, ih->alloc); + cmc_assert_equals(ptr, callbacks, ih->callbacks); + cmc_assert_equals(int32_t, CMC_FLAG_OK, ih->flag); + + ih->flag = CMC_FLAG_ERROR; + ih_customize(ih, NULL, NULL); + + cmc_assert_equals(ptr, cmc_alloc_node_default.malloc, ih->alloc->malloc); + cmc_assert_equals(ptr, cmc_alloc_node_default.calloc, ih->alloc->calloc); + cmc_assert_equals(ptr, cmc_alloc_node_default.realloc, ih->alloc->realloc); + cmc_assert_equals(ptr, cmc_alloc_node_default.free, ih->alloc->free); + cmc_assert_equals(ptr, NULL, ih->callbacks); + cmc_assert_equals(int32_t, CMC_FLAG_OK, ih->flag); + + ih_free(ih); + }); + + CMC_CREATE_TEST(PFX##_insert(), { + total_create = 0; + struct intervalheap *ih = ih_new(100, ih_fval); + + cmc_assert_not_equals(ptr, NULL, ih); + + for (size_t i = 0; i < 100; i++) + ih_insert(ih, 10); + + cmc_assert_equals(size_t, 100, ih_count(ih)); + + ih_clear(ih); + + cmc_assert(ih_insert(ih, 1)); + cmc_assert(ih_insert(ih, 0)); + + cmc_assert_equals(size_t, 2, ih_count(ih)); + + ih_free(ih); + + // callbacks + ih = ih_new_custom(100, ih_fval, NULL, callbacks); + + for (size_t i = 0; i < 10000; i++) + ih_insert(ih, i); + + cmc_assert_equals(size_t, 10000, ih_count(ih)); + cmc_assert_equals(int32_t, 10000, total_create); + + ih_free(ih); + + // max + ih = ih_new(1, ih_fval); + + cmc_assert(ih_insert(ih, 0)); + cmc_assert(ih_insert(ih, 1)); + cmc_assert(ih_insert(ih, 2)); + + cmc_assert_equals(size_t, 2, ih_max(ih)); + + ih_free(ih); + + // min + ih = ih_new(1, ih_fval); + + cmc_assert(ih_insert(ih, 0)); + cmc_assert(ih_insert(ih, 1)); + cmc_assert(ih_insert(ih, 2)); + + cmc_assert_equals(size_t, 0, ih_min(ih)); + + ih_free(ih); + + // remove_max, remove_min + ih = ih_new(100, ih_fval); + + cmc_assert_not_equals(ptr, NULL, ih); + + cmc_assert(ih_insert(ih, 2)); + cmc_assert_equals(size_t, 2, ih->buffer[0][0]); + + cmc_assert(ih_insert(ih, 1)); + cmc_assert_equals(size_t, 1, ih->buffer[0][0]); + cmc_assert_equals(size_t, 2, ih->buffer[0][1]); + + cmc_assert(ih_remove_min(ih)); + cmc_assert_equals(size_t, 2, ih->buffer[0][0]); + + cmc_assert(ih_insert(ih, 1)); + cmc_assert_equals(size_t, 1, ih->buffer[0][0]); + cmc_assert_equals(size_t, 2, ih->buffer[0][1]); + + cmc_assert(ih_remove_max(ih)); + cmc_assert_equals(size_t, 1, ih->buffer[0][0]); + + ih_free(ih); + total_create = 0; + }); + + CMC_CREATE_TEST(PFX##_remove_max(), { + total_delete = 0; + struct intervalheap *ih = ih_new_custom(100, ih_fval, NULL, callbacks); + + // count == 0 + cmc_assert(!ih_remove_max(ih)); + + cmc_assert_equals(int32_t, CMC_FLAG_EMPTY, ih->flag); + + // count == 1 + cmc_assert(ih_insert(ih, 10)); + ih->flag = CMC_FLAG_ERROR; + cmc_assert(ih_remove_max(ih)); + + cmc_assert_equals(int32_t, 1, total_delete); + cmc_assert_equals(int32_t, CMC_FLAG_OK, ih->flag); + + for (size_t i = 1; i <= 1000; i++) + ih_insert(ih, i); + + for (size_t i = 1000; i > 0; i--) + { + cmc_assert_equals(size_t, i, ih_max(ih)); + cmc_assert(ih_remove_max(ih)); + } + + cmc_assert_equals(size_t, 0, ih_count(ih)); + + for (size_t i = 1; i <= 1000; i++) + { + ih_insert(ih, i % 50); + } + + cmc_assert_equals(size_t, 1000, ih_count(ih)); + + for (int i = 49; i >= 0; i--) + { + for (size_t j = 0; j < 20; j++) + { + cmc_assert_equals(size_t, (size_t)i, ih_max(ih)); + cmc_assert(ih_remove_max(ih)); + } + } + + ih_free(ih); + total_delete = 0; + }); + + CMC_CREATE_TEST(PFX##_remove_min(), { + total_delete = 0; + struct intervalheap *ih = ih_new_custom(100, ih_fval, NULL, callbacks); + + // count == 0 + cmc_assert(!ih_remove_min(ih)); + + cmc_assert_equals(int32_t, CMC_FLAG_EMPTY, ih->flag); + + // count == 1 + cmc_assert(ih_insert(ih, 10)); + ih->flag = CMC_FLAG_ERROR; + cmc_assert(ih_remove_min(ih)); + + cmc_assert_equals(int32_t, 1, total_delete); + cmc_assert_equals(int32_t, CMC_FLAG_OK, ih->flag); + + for (size_t i = 1000; i >= 1; i--) + ih_insert(ih, i); + + for (size_t i = 1; i <= 1000; i++) + { + cmc_assert_equals(size_t, i, ih_min(ih)); + cmc_assert(ih_remove_min(ih)); + } + + cmc_assert_equals(size_t, 0, ih_count(ih)); + + for (size_t i = 1000; i >= 1; i--) + { + ih_insert(ih, i % 50); + } + + cmc_assert_equals(size_t, 1000, ih_count(ih)); + + for (int i = 0; i <= 49; i++) + { + for (size_t j = 0; j < 20; j++) + { + cmc_assert_equals(size_t, (size_t)i, ih_min(ih)); + cmc_assert(ih_remove_min(ih)); + } + } + + ih_free(ih); + total_delete = 0; + }); + + CMC_CREATE_TEST(PFX##_remove_max() + PFX##_remove_min(), { + struct intervalheap *ih = ih_new(100, ih_fval); + + for (size_t i = 1; i <= 10000; i++) + { + ih_insert(ih, i % 50); + } + + cmc_assert_equals(size_t, 10000, ih_count(ih)); + + // i = min + // j = max + for (size_t i = 0, j = 49; i < j; i++, j--) + { + for (size_t k = 0; k < 200; k++) + { + cmc_assert_equals(size_t, i, ih_min(ih)); + cmc_assert_equals(size_t, j, ih_max(ih)); + cmc_assert(ih_remove_min(ih)); + cmc_assert(ih_remove_max(ih)); + } + } + + cmc_assert_equals(size_t, 0, ih_count(ih)); + + ih_free(ih); + }); + + CMC_CREATE_TEST(buffer_growth[capacity = 1], { + struct intervalheap *ih = ih_new(1, ih_fval); + + cmc_assert_not_equals(ptr, NULL, ih); + + for (size_t i = 0; i < 50; i++) + cmc_assert(ih_insert(ih, i)); + + cmc_assert_equals(size_t, 50, ih_count(ih)); + cmc_assert_greater(size_t, 50, ih_capacity(ih) * 2); + + ih_free(ih); + }); + + CMC_CREATE_TEST(flags, { + struct intervalheap *ih = ih_new(100, ih_fval); + + cmc_assert_not_equals(ptr, NULL, ih); + cmc_assert_equals(int32_t, CMC_FLAG_OK, ih_flag(ih)); + + ih->flag = CMC_FLAG_ERROR; + + // clear + ih_clear(ih); + cmc_assert_equals(int32_t, CMC_FLAG_OK, ih_flag(ih)); + + // customize + ih->flag = CMC_FLAG_ERROR; + ih_customize(ih, NULL, NULL); + cmc_assert_equals(int32_t, CMC_FLAG_OK, ih_flag(ih)); + + // insert + ih->flag = CMC_FLAG_ERROR; + cmc_assert(ih_insert(ih, 10)); + cmc_assert_equals(int32_t, CMC_FLAG_OK, ih_flag(ih)); + + // remove_max + cmc_assert(ih_remove_max(ih)); + cmc_assert_equals(int32_t, CMC_FLAG_OK, ih_flag(ih)); + cmc_assert(!ih_remove_max(ih)); + cmc_assert_equals(int32_t, CMC_FLAG_EMPTY, ih_flag(ih)); + + // remove min + cmc_assert(ih_insert(ih, 10)); + cmc_assert(ih_remove_min(ih)); + cmc_assert_equals(int32_t, CMC_FLAG_OK, ih_flag(ih)); + cmc_assert(!ih_remove_min(ih)); + cmc_assert_equals(int32_t, CMC_FLAG_EMPTY, ih_flag(ih)); + + // update_max + cmc_assert(!ih_update_max(ih, 20)); + cmc_assert_equals(int32_t, CMC_FLAG_EMPTY, ih_flag(ih)); + cmc_assert(ih_insert(ih, 10)); + ih->flag = CMC_FLAG_ERROR; + cmc_assert(ih_update_max(ih, 20)); + cmc_assert_equals(int32_t, CMC_FLAG_OK, ih_flag(ih)); + + // update_min + ih->flag = CMC_FLAG_ERROR; + cmc_assert(ih_update_min(ih, 20)); + cmc_assert_equals(int32_t, CMC_FLAG_OK, ih_flag(ih)); + cmc_assert(ih_remove_min(ih)); + ih->flag = CMC_FLAG_ERROR; + cmc_assert(!ih_update_max(ih, 20)); + cmc_assert_equals(int32_t, CMC_FLAG_EMPTY, ih_flag(ih)); + + // max min + ih->flag = CMC_FLAG_ERROR; + cmc_assert_equals(size_t, (size_t){ 0 }, ih_max(ih)); + cmc_assert_equals(int32_t, CMC_FLAG_EMPTY, ih_flag(ih)); + + ih->flag = CMC_FLAG_ERROR; + cmc_assert_equals(size_t, (size_t){ 0 }, ih_min(ih)); + cmc_assert_equals(int32_t, CMC_FLAG_EMPTY, ih_flag(ih)); + + cmc_assert(ih_insert(ih, 10)); + ih->flag = CMC_FLAG_ERROR; + cmc_assert_equals(size_t, 10, ih_max(ih)); + cmc_assert_equals(int32_t, CMC_FLAG_OK, ih_flag(ih)); + + ih->flag = CMC_FLAG_ERROR; + cmc_assert_equals(size_t, 10, ih_min(ih)); + cmc_assert_equals(int32_t, CMC_FLAG_OK, ih_flag(ih)); + + // contains + ih->flag = CMC_FLAG_ERROR; + cmc_assert(ih_contains(ih, 10)); + cmc_assert_equals(int32_t, CMC_FLAG_OK, ih_flag(ih)); + + // copy_of + ih->flag = CMC_FLAG_ERROR; + struct intervalheap *ih2 = ih_copy_of(ih); + cmc_assert_equals(int32_t, CMC_FLAG_OK, ih_flag(ih)); + cmc_assert_equals(int32_t, CMC_FLAG_OK, ih_flag(ih2)); + + // equals + ih->flag = CMC_FLAG_ERROR; + ih2->flag = CMC_FLAG_ERROR; + cmc_assert(ih_equals(ih, ih2)); + cmc_assert_equals(int32_t, CMC_FLAG_OK, ih_flag(ih)); + cmc_assert_equals(int32_t, CMC_FLAG_OK, ih_flag(ih2)); + + ih_free(ih); + ih_free(ih2); + }); + + CMC_CREATE_TEST(callbacks, { + struct intervalheap *ih = ih_new_custom(100, ih_fval, NULL, callbacks); + + cmc_assert_not_equals(ptr, NULL, ih); + + total_create = 0; + total_read = 0; + total_update = 0; + total_delete = 0; + total_resize = 0; + + cmc_assert(ih_insert(ih, 10)); + cmc_assert_equals(int32_t, 1, total_create); + + cmc_assert(ih_remove_max(ih)); + cmc_assert_equals(int32_t, 1, total_delete); + + cmc_assert(ih_insert(ih, 10)); + cmc_assert_equals(int32_t, 2, total_create); + + cmc_assert(ih_remove_min(ih)); + cmc_assert_equals(int32_t, 2, total_delete); + + cmc_assert(ih_insert(ih, 1)); + cmc_assert(ih_insert(ih, 2)); + cmc_assert_equals(int32_t, 4, total_create); + + cmc_assert(ih_update_max(ih, 1)); + cmc_assert_equals(int32_t, 1, total_update); + + cmc_assert(ih_update_min(ih, 2)); + cmc_assert_equals(int32_t, 2, total_update); + + cmc_assert_equals(size_t, 2, ih_max(ih)); + cmc_assert_equals(int32_t, 1, total_read); + + cmc_assert_equals(size_t, 1, ih_min(ih)); + cmc_assert_equals(int32_t, 2, total_read); + + cmc_assert(ih_contains(ih, 1)); + cmc_assert_equals(int32_t, 3, total_read); + + cmc_assert(ih_resize(ih, 1000)); + cmc_assert_equals(int32_t, 1, total_resize); + + cmc_assert(ih_resize(ih, 50)); + cmc_assert_equals(int32_t, 2, total_resize); + + cmc_assert_equals(int32_t, 4, total_create); + cmc_assert_equals(int32_t, 3, total_read); + cmc_assert_equals(int32_t, 2, total_update); + cmc_assert_equals(int32_t, 2, total_delete); + cmc_assert_equals(int32_t, 2, total_resize); + + ih_customize(ih, NULL, NULL); + + cmc_assert_equals(ptr, NULL, ih->callbacks); + + ih_clear(ih); + cmc_assert(ih_insert(ih, 10)); + cmc_assert(ih_remove_max(ih)); + cmc_assert(ih_insert(ih, 10)); + cmc_assert(ih_remove_min(ih)); + cmc_assert(ih_insert(ih, 1)); + cmc_assert(ih_insert(ih, 2)); + cmc_assert(ih_update_max(ih, 1)); + cmc_assert(ih_update_min(ih, 2)); + cmc_assert_equals(size_t, 2, ih_max(ih)); + cmc_assert_equals(size_t, 1, ih_min(ih)); + cmc_assert(ih_contains(ih, 1)); + cmc_assert(ih_resize(ih, 1000)); + cmc_assert(ih_resize(ih, 50)); + + cmc_assert_equals(int32_t, 4, total_create); + cmc_assert_equals(int32_t, 3, total_read); + cmc_assert_equals(int32_t, 2, total_update); + cmc_assert_equals(int32_t, 2, total_delete); + cmc_assert_equals(int32_t, 2, total_resize); + + cmc_assert_equals(ptr, NULL, ih->callbacks); + + ih_free(ih); + + total_create = 0; + total_read = 0; + total_update = 0; + total_delete = 0; + total_resize = 0; + }); +}); + +CMC_CREATE_UNIT(CMCIntervalHeapIter, true, { + CMC_CREATE_TEST(PFX##_iter_start(), { + struct intervalheap *ih = ih_new(100, ih_fval); + + cmc_assert_not_equals(ptr, NULL, ih); + + struct intervalheap_iter it = ih_iter_start(ih); + + cmc_assert_equals(ptr, ih, it.target); + cmc_assert_equals(size_t, 0, it.cursor); + cmc_assert_equals(bool, true, it.start); + cmc_assert_equals(bool, true, it.end); + + cmc_assert(ih_iter_at_start(&it)); + cmc_assert(ih_iter_at_end(&it)); + + cmc_assert(ih_insert(ih, 1)); + cmc_assert(ih_insert(ih, 2)); + + it = ih_iter_start(ih); + + cmc_assert_equals(size_t, 0, it.cursor); + cmc_assert_equals(bool, false, it.end); + + ih_free(ih); + }); + + CMC_CREATE_TEST(PFX##_iter_end(), { + struct intervalheap *ih = ih_new(100, ih_fval); + + cmc_assert_not_equals(ptr, NULL, ih); + + struct intervalheap_iter it = ih_iter_end(ih); + + cmc_assert_equals(ptr, ih, it.target); + cmc_assert_equals(size_t, 0, it.cursor); + cmc_assert_equals(bool, true, it.start); + cmc_assert_equals(bool, true, it.end); + + cmc_assert(ih_iter_at_start(&it)); + cmc_assert(ih_iter_at_end(&it)); + + cmc_assert(ih_insert(ih, 1)); + cmc_assert(ih_insert(ih, 2)); + cmc_assert(ih_insert(ih, 3)); + + it = ih_iter_end(ih); + + cmc_assert_equals(size_t, ih->count - 1, it.cursor); + cmc_assert_equals(bool, false, it.start); + + ih_free(ih); + }); + + CMC_CREATE_TEST(PFX##_iter_at_start(), { + struct intervalheap *ih = ih_new(100, ih_fval); + + cmc_assert_not_equals(ptr, NULL, ih); + + struct intervalheap_iter it = ih_iter_start(ih); + + // Empty checks + cmc_assert(ih_iter_at_start(&it)); + it = ih_iter_end(ih); + cmc_assert(ih_iter_at_start(&it)); + + // Non-empty check + cmc_assert(ih_insert(ih, 1)); + it = ih_iter_end(ih); + cmc_assert(!ih_iter_at_start(&it)); + it = ih_iter_start(ih); + cmc_assert(ih_iter_at_start(&it)); + + ih_free(ih); + }); + + CMC_CREATE_TEST(PFX##_iter_at_end(), { + struct intervalheap *ih = ih_new(100, ih_fval); + + cmc_assert_not_equals(ptr, NULL, ih); + + struct intervalheap_iter it = ih_iter_start(ih); + + // Empty check + cmc_assert(ih_iter_at_end(&it)); + it = ih_iter_end(ih); + cmc_assert(ih_iter_at_end(&it)); + + // Non-empty check + cmc_assert(ih_insert(ih, 1)); + it = ih_iter_end(ih); + cmc_assert(ih_iter_at_end(&it)); + it = ih_iter_start(ih); + cmc_assert(!ih_iter_at_end(&it)); + + ih_free(ih); + }); + + CMC_CREATE_TEST(PFX##_iter_to_start(), { + struct intervalheap *ih = ih_new(100, ih_fval); + + cmc_assert_not_equals(ptr, NULL, ih); + + struct intervalheap_iter it = ih_iter_start(ih); + + cmc_assert(!ih_iter_to_start(&it)); + + for (size_t i = 1; i <= 100; i++) + { + if (i % 2 == 0) + ih_insert(ih, i); + else + ih_insert(ih, i); + } + + cmc_assert_equals(size_t, 100, ih->count); + + it = ih_iter_end(ih); + cmc_assert(!ih_iter_at_start(&it)); + cmc_assert(ih_iter_at_end(&it)); + cmc_assert_equals(size_t, 99, it.cursor); + + cmc_assert(ih_iter_to_start(&it)); + cmc_assert(ih_iter_at_start(&it)); + cmc_assert(!ih_iter_at_end(&it)); + cmc_assert_equals(size_t, 0, it.cursor); + + ih_free(ih); + }); + + CMC_CREATE_TEST(PFX##_iter_to_end(), { + struct intervalheap *ih = ih_new(100, ih_fval); + + cmc_assert_not_equals(ptr, NULL, ih); + + struct intervalheap_iter it = ih_iter_end(ih); + + cmc_assert(!ih_iter_to_end(&it)); + + for (size_t i = 1; i <= 100; i++) + { + if (i % 2 == 0) + ih_insert(ih, i); + else + ih_insert(ih, i); + } + + it = ih_iter_start(ih); + cmc_assert(ih_iter_at_start(&it)); + cmc_assert(!ih_iter_at_end(&it)); + + cmc_assert(ih_iter_to_end(&it)); + cmc_assert(!ih_iter_at_start(&it)); + cmc_assert(ih_iter_at_end(&it)); + + ih_free(ih); + }); + + CMC_CREATE_TEST(PFX##_iter_next(), { + struct intervalheap *ih = ih_new(100, ih_fval); + + cmc_assert_not_equals(ptr, NULL, ih); + + struct intervalheap_iter it = ih_iter_start(ih); + + cmc_assert(!ih_iter_next(&it)); + + for (size_t i = 1; i <= 1000; i++) + { + if (i % 2 == 0) + ih_insert(ih, i); + else + ih_insert(ih, i); + } + + size_t sum = 0; + for (it = ih_iter_start(ih); !ih_iter_at_end(&it); ih_iter_next(&it)) + { + sum += ih_iter_value(&it); + } + + cmc_assert_equals(size_t, 500500, sum); + + sum = 0; + + ih_iter_to_start(&it); + do + { + sum += ih_iter_value(&it); + } while (ih_iter_next(&it)); + + cmc_assert_equals(size_t, 500500, sum); + + ih_free(ih); + }); + + CMC_CREATE_TEST(PFX##_iter_prev(), { + struct intervalheap *ih = ih_new(100, ih_fval); + + cmc_assert_not_equals(ptr, NULL, ih); + + struct intervalheap_iter it = ih_iter_end(ih); + + cmc_assert(!ih_iter_prev(&it)); + + for (size_t i = 1; i <= 1000; i++) + { + if (i % 2 == 0) + ih_insert(ih, i); + else + ih_insert(ih, i); + } + + size_t sum = 0; + for (it = ih_iter_end(ih); !ih_iter_at_start(&it); ih_iter_prev(&it)) + { + sum += ih_iter_value(&it); + } + + cmc_assert_equals(size_t, 500500, sum); + + sum = 0; + + ih_iter_to_end(&it); + do + { + sum += ih_iter_value(&it); + } while (ih_iter_prev(&it)); + + cmc_assert_equals(size_t, 500500, sum); + + ih_free(ih); + }); + + CMC_CREATE_TEST(PFX##_iter_advance(), { + struct intervalheap *ih = ih_new(100, ih_fval); + + cmc_assert_not_equals(ptr, NULL, ih); + + struct intervalheap_iter it = ih_iter_start(ih); + + cmc_assert(!ih_iter_advance(&it, 1)); + + for (size_t i = 1; i <= 1000; i++) + ih_insert(ih, i); + + it = ih_iter_start(ih); + + cmc_assert(!ih_iter_advance(&it, 0)); + cmc_assert(!ih_iter_advance(&it, ih->count)); + + size_t sum = 0; + for (it = ih_iter_start(ih);;) + { + sum += ih_iter_value(&it); + + if (!ih_iter_advance(&it, 2)) + break; + + cmc_assert_equals(size_t, 0, ih_iter_index(&it) % 2); + } + + cmc_assert(ih_iter_to_start(&it)); + cmc_assert(ih_iter_next(&it)); + + cmc_assert_equals(size_t, 1, ih_iter_index(&it)); + + for (;;) + { + sum += ih_iter_value(&it); + + if (!ih_iter_advance(&it, 2)) + break; + + cmc_assert_equals(size_t, 1, ih_iter_index(&it) % 2); + } + + cmc_assert_equals(size_t, 500500, sum); + + ih_iter_to_start(&it); + cmc_assert(ih_iter_advance(&it, ih->count - 1)); + + ih_free(ih); + }); + + CMC_CREATE_TEST(PFX##_iter_rewind(), { + struct intervalheap *ih = ih_new(100, ih_fval); + + cmc_assert_not_equals(ptr, NULL, ih); + + struct intervalheap_iter it = ih_iter_end(ih); + + cmc_assert(!ih_iter_rewind(&it, 1)); + + for (size_t i = 0; i <= 1000; i++) + ih_insert(ih, i); + + it = ih_iter_end(ih); + + cmc_assert(!ih_iter_rewind(&it, 0)); + cmc_assert(!ih_iter_rewind(&it, ih->count)); + + size_t sum = 0; + for (it = ih_iter_end(ih);;) + { + sum += ih_iter_value(&it); + + if (!ih_iter_rewind(&it, 2)) + break; + + cmc_assert_equals(size_t, 0, ih_iter_index(&it) % 2); + } + + cmc_assert(ih_iter_to_end(&it)); + cmc_assert(ih_iter_prev(&it)); + + cmc_assert_equals(size_t, ih->count - 2, ih_iter_index(&it)); + + for (;;) + { + sum += ih_iter_value(&it); + + if (!ih_iter_rewind(&it, 2)) + break; + + cmc_assert_equals(size_t, 1, ih_iter_index(&it) % 2); + } + + cmc_assert_equals(size_t, 500500, sum); + + ih_iter_to_end(&it); + cmc_assert(ih_iter_rewind(&it, ih->count - 1)); + + ih_free(ih); + }); + + CMC_CREATE_TEST(PFX##_iter_go_to(), { + struct intervalheap *ih = ih_new(100, ih_fval); + + cmc_assert_not_equals(ptr, NULL, ih); + + struct intervalheap_iter it = ih_iter_end(ih); + cmc_assert(!ih_iter_go_to(&it, 0)); + + it = ih_iter_start(ih); + cmc_assert(!ih_iter_go_to(&it, 0)); + + for (size_t i = 0; i <= 1000; i++) + ih_insert(ih, i); + + cmc_assert_equals(size_t, 1001, ih->count); + + it = ih_iter_start(ih); + + size_t sum = 0; + for (size_t i = 0; i < 1001; i++) + { + ih_iter_go_to(&it, i); + + sum += ih_iter_value(&it); + } + + cmc_assert_equals(size_t, 500500, sum); + + sum = 0; + for (size_t i = 1001; i > 0; i--) + { + cmc_assert(ih_iter_go_to(&it, i - 1)); + + sum += ih_iter_value(&it); + } + + cmc_assert_equals(size_t, 500500, sum); + + ih_free(ih); + }); + + CMC_CREATE_TEST(PFX##_iter_value(), { + struct intervalheap *ih = ih_new(100, ih_fval); + + cmc_assert_not_equals(ptr, NULL, ih); + + struct intervalheap_iter it = ih_iter_end(ih); + + cmc_assert_equals(size_t, (size_t){ 0 }, ih_iter_value(&it)); + + cmc_assert(ih_insert(ih, 1)); + cmc_assert(ih_insert(ih, 3)); + cmc_assert(ih_insert(ih, 2)); + + it = ih_iter_start(ih); + + cmc_assert_equals(size_t, 1, ih_iter_value(&it)); + cmc_assert(ih_iter_next(&it)); + cmc_assert_equals(size_t, 3, ih_iter_value(&it)); + + ih_free(ih); + }); + + CMC_CREATE_TEST(PFX##_iter_index(), { + struct intervalheap *ih = ih_new(100, ih_fval); + + cmc_assert_not_equals(ptr, NULL, ih); + + for (size_t i = 0; i <= 1000; i++) + ih_insert(ih, i); + + struct intervalheap_iter it = ih_iter_start(ih); + + for (size_t i = 0; i < 1001; i++) + { + cmc_assert_equals(size_t, i, ih_iter_index(&it)); + ih_iter_next(&it); + } + + it = ih_iter_end(ih); + for (size_t i = 1001; i > 0; i--) + { + cmc_assert_equals(size_t, i - 1, ih_iter_index(&it)); + ih_iter_prev(&it); + } + + ih_free(ih); + }); +}); + +#endif /* CMC_TESTS_UNT_INTERVALHEAP_H */ diff --git a/tests/unt_stack.h b/tests/unt_stack.h index 7a79ba4..617a2fa 100644 --- a/tests/unt_stack.h +++ b/tests/unt_stack.h @@ -837,19 +837,4 @@ CMC_CREATE_UNIT(CMCStackIter, true, { }); }); -#ifdef CMC_TEST_MAIN -int main(void) -{ - int result = CMCStack() + CMCStackIter(); - - printf(" +---------------------------------------------------------------+"); - printf("\n"); - printf(" | CMCStack Suit : %-48s |\n", result == 0 ? "PASSED" : "FAILED"); - printf(" +---------------------------------------------------------------+"); - printf("\n\n\n"); - - return result; -} -#endif - #endif /* CMC_TESTS_UNT_STACK_H */