Files
C-Macro-Collections/cmc/intervalheap/code.h
T

861 lines
20 KiB
C

/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* 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)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
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, CMC_ALLOC_TYPE alloc,
CMC_CALLBACK_TYPE callbacks)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
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_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
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_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
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_, CMC_ALLOC_TYPE alloc, CMC_CALLBACK_TYPE callbacks)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
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)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
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_);
return true;
}
bool CMC_(PFX, _remove_max)(struct SNAME *_heap_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
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_);
return true;
}
bool CMC_(PFX, _remove_min)(struct SNAME *_heap_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
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_);
return true;
}
bool CMC_(PFX, _update_max)(struct SNAME *_heap_, V value)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
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_);
return true;
}
bool CMC_(PFX, _update_min)(struct SNAME *_heap_, V value)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
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_);
return true;
}
V CMC_(PFX, _max)(struct SNAME *_heap_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(_heap_))
{
_heap_->flag = CMC_FLAG_EMPTY;
return (V){ 0 };
}
_heap_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_heap_);
/* 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_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(_heap_))
{
_heap_->flag = CMC_FLAG_EMPTY;
return (V){ 0 };
}
_heap_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_heap_);
return _heap_->buffer[0][0];
}
bool CMC_(PFX, _contains)(struct SNAME *_heap_, V value)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
_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_);
return result;
}
bool CMC_(PFX, _empty)(struct SNAME *_heap_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _heap_->count == 0;
}
bool CMC_(PFX, _full)(struct SNAME *_heap_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
/* 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_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _heap_->count;
}
size_t CMC_(PFX, _capacity)(struct SNAME *_heap_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _heap_->capacity;
}
int CMC_(PFX, _flag)(struct SNAME *_heap_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _heap_->flag;
}
bool CMC_(PFX, _resize)(struct SNAME *_heap_, size_t capacity)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
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_);
return true;
}
struct SNAME *CMC_(PFX, _copy_of)(struct SNAME *_heap_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
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_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
_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_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
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_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
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_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
/* 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_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
/* 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;
}
}