Blame complib/cl_heap.c

Packit 13e616
/*
Packit 13e616
 * Copyright (c) 2009-2015 ZIH, TU Dresden, Federal Republic of Germany. All rights reserved.
Packit 13e616
 *
Packit 13e616
 * This software is available to you under a choice of one of two
Packit 13e616
 * licenses.  You may choose to be licensed under the terms of the GNU
Packit 13e616
 * General Public License (GPL) Version 2, available from the file
Packit 13e616
 * COPYING in the main directory of this source tree, or the
Packit 13e616
 * OpenIB.org BSD license below:
Packit 13e616
 *
Packit 13e616
 *     Redistribution and use in source and binary forms, with or
Packit 13e616
 *     without modification, are permitted provided that the following
Packit 13e616
 *     conditions are met:
Packit 13e616
 *
Packit 13e616
 *      - Redistributions of source code must retain the above
Packit 13e616
 *        copyright notice, this list of conditions and the following
Packit 13e616
 *        disclaimer.
Packit 13e616
 *
Packit 13e616
 *      - Redistributions in binary form must reproduce the above
Packit 13e616
 *        copyright notice, this list of conditions and the following
Packit 13e616
 *        disclaimer in the documentation and/or other materials
Packit 13e616
 *        provided with the distribution.
Packit 13e616
 *
Packit 13e616
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
Packit 13e616
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
Packit 13e616
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
Packit 13e616
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
Packit 13e616
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
Packit 13e616
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
Packit 13e616
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
Packit 13e616
 * SOFTWARE.
Packit 13e616
 *
Packit 13e616
 */
Packit 13e616
Packit 13e616
/*
Packit 13e616
 * Abstract:
Packit 13e616
 *	This file contains a d-ary heap implementation.
Packit 13e616
 *	The default is a minimum heap, however the caller can overwrite
Packit 13e616
 *	the compare function for the keys of the heap.
Packit 13e616
 *
Packit 13e616
 */
Packit 13e616
Packit 13e616
#if HAVE_CONFIG_H
Packit 13e616
#include <config.h>
Packit 13e616
#endif				/* HAVE_CONFIG_H */
Packit 13e616
Packit 13e616
#include <stdlib.h>
Packit 13e616
#include <string.h>
Packit 13e616
#include <complib/cl_heap.h>
Packit 13e616
Packit 13e616
typedef struct _cl_heap_elem {
Packit 13e616
	uint64_t key;
Packit 13e616
	void *context;
Packit 13e616
} cl_heap_elem_t;
Packit 13e616
Packit 13e616
static int compare_keys(IN const void *p_key_1, IN const void *p_key_2)
Packit 13e616
{
Packit 13e616
	uint64_t key1, key2;
Packit 13e616
Packit 13e616
	CL_ASSERT(p_key_1);
Packit 13e616
	CL_ASSERT(p_key_2);
Packit 13e616
Packit 13e616
	key1 = *((uint64_t *) p_key_1);
Packit 13e616
	key2 = *((uint64_t *) p_key_2);
Packit 13e616
Packit 13e616
	return ((key1 < key2) ? -1 : ((key1 > key2) ? 1 : 0));
Packit 13e616
}
Packit 13e616
Packit 13e616
void cl_heap_construct(IN cl_heap_t * const p_heap)
Packit 13e616
{
Packit 13e616
	CL_ASSERT(p_heap);
Packit 13e616
Packit 13e616
	memset(p_heap, 0, sizeof(cl_heap_t));
Packit 13e616
Packit 13e616
	p_heap->state = CL_UNINITIALIZED;
Packit 13e616
}
Packit 13e616
Packit 13e616
cl_status_t cl_heap_init(IN cl_heap_t * const p_heap, IN const size_t max_size,
Packit 13e616
			 IN const uint8_t d,
Packit 13e616
			 IN cl_pfn_heap_apply_index_update_t pfn_index_update,
Packit 13e616
			 IN cl_pfn_heap_compare_keys_t pfn_compare OPTIONAL)
Packit 13e616
{
Packit 13e616
	CL_ASSERT(p_heap);
Packit 13e616
Packit 13e616
	if (!cl_is_state_valid(p_heap->state))
Packit 13e616
		cl_heap_construct(p_heap);
Packit 13e616
Packit 13e616
	if (max_size <= 0 || !d || !pfn_index_update)
Packit 13e616
		return (CL_INVALID_PARAMETER);
Packit 13e616
Packit 13e616
	if (cl_is_heap_inited(p_heap))
Packit 13e616
		cl_heap_destroy(p_heap);
Packit 13e616
Packit 13e616
	p_heap->branching_factor = d;
Packit 13e616
	p_heap->size = 0;
Packit 13e616
	p_heap->capacity = max_size;
Packit 13e616
	p_heap->pfn_index_update = pfn_index_update;
Packit 13e616
Packit 13e616
	if (pfn_compare)
Packit 13e616
		p_heap->pfn_compare = pfn_compare;
Packit 13e616
	else
Packit 13e616
		p_heap->pfn_compare = &compare_keys;
Packit 13e616
Packit 13e616
	p_heap->element_array =
Packit 13e616
	    (cl_heap_elem_t *) malloc(max_size * sizeof(cl_heap_elem_t));
Packit 13e616
	if (!p_heap->element_array)
Packit 13e616
		return (CL_INSUFFICIENT_MEMORY);
Packit 13e616
	memset(p_heap->element_array, 0, max_size * sizeof(cl_heap_elem_t));
Packit 13e616
Packit 13e616
	p_heap->state = CL_INITIALIZED;
Packit 13e616
Packit 13e616
	return (CL_SUCCESS);
Packit 13e616
}
Packit 13e616
Packit 13e616
void cl_heap_destroy(IN cl_heap_t * const p_heap)
Packit 13e616
{
Packit 13e616
	CL_ASSERT(p_heap);
Packit 13e616
	CL_ASSERT(cl_is_state_valid(p_heap->state));
Packit 13e616
Packit 13e616
	if (p_heap->element_array)
Packit 13e616
		free(p_heap->element_array);
Packit 13e616
Packit 13e616
	cl_heap_construct(p_heap);
Packit 13e616
}
Packit 13e616
Packit 13e616
cl_status_t cl_heap_resize(IN cl_heap_t * const p_heap,
Packit 13e616
			   IN const size_t new_size)
Packit 13e616
{
Packit 13e616
	cl_heap_elem_t *realloc_element_array = NULL;
Packit 13e616
Packit 13e616
	CL_ASSERT(p_heap);
Packit 13e616
	CL_ASSERT(cl_is_heap_inited(p_heap));
Packit 13e616
Packit 13e616
	if (new_size <= 0 || new_size < p_heap->size)
Packit 13e616
		return (CL_INVALID_PARAMETER);
Packit 13e616
Packit 13e616
	if (new_size == p_heap->capacity)
Packit 13e616
		return (CL_SUCCESS);
Packit 13e616
Packit 13e616
	realloc_element_array =
Packit 13e616
	    (cl_heap_elem_t *) realloc(p_heap->element_array,
Packit 13e616
				       new_size * sizeof(cl_heap_elem_t));
Packit 13e616
	if (!realloc_element_array)
Packit 13e616
		return (CL_INSUFFICIENT_MEMORY);
Packit 13e616
Packit 13e616
	p_heap->element_array = realloc_element_array;
Packit 13e616
	memset(p_heap->element_array + p_heap->size, 0,
Packit 13e616
	       (new_size - p_heap->size) * sizeof(cl_heap_elem_t));
Packit 13e616
Packit 13e616
	p_heap->capacity = new_size;
Packit 13e616
Packit 13e616
	return (CL_SUCCESS);
Packit 13e616
}
Packit 13e616
Packit 13e616
static void heap_down(IN cl_heap_t * const p_heap, IN const size_t index)
Packit 13e616
{
Packit 13e616
	int64_t first_child, swap_child, child, parent, d;
Packit 13e616
	cl_heap_elem_t tmp = p_heap->element_array[index];
Packit 13e616
	boolean_t swapped = FALSE;
Packit 13e616
Packit 13e616
	d = (int64_t) p_heap->branching_factor;
Packit 13e616
	parent = index;
Packit 13e616
Packit 13e616
	while (parent * d + 1 < p_heap->size) {
Packit 13e616
		swap_child = first_child = parent * d + 1;
Packit 13e616
		/* find the min (or max) child among the children */
Packit 13e616
		for (child = first_child + 1;
Packit 13e616
		     child < first_child + d && child < p_heap->size; child++)
Packit 13e616
			if (p_heap->
Packit 13e616
			    pfn_compare(&(p_heap->element_array[child].key),
Packit 13e616
					&(p_heap->element_array[swap_child].
Packit 13e616
					  key)) <= 0)
Packit 13e616
				swap_child = child;
Packit 13e616
Packit 13e616
		/* exchange parent and one child */
Packit 13e616
		if (p_heap->
Packit 13e616
		    pfn_compare(&(tmp.key),
Packit 13e616
				&(p_heap->element_array[swap_child].key)) > 0) {
Packit 13e616
			p_heap->element_array[parent] =
Packit 13e616
			    p_heap->element_array[swap_child];
Packit 13e616
			p_heap->pfn_index_update(p_heap->element_array[parent].
Packit 13e616
						 context, parent);
Packit 13e616
			parent = swap_child;
Packit 13e616
			swapped = TRUE;
Packit 13e616
		} else
Packit 13e616
			break;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/* move the original element down in the heap */
Packit 13e616
	if (swapped) {
Packit 13e616
		p_heap->element_array[parent] = tmp;
Packit 13e616
		p_heap->pfn_index_update(p_heap->element_array[parent].context,
Packit 13e616
					 parent);
Packit 13e616
	}
Packit 13e616
}
Packit 13e616
Packit 13e616
static void heap_up(IN cl_heap_t * const p_heap, IN const size_t index)
Packit 13e616
{
Packit 13e616
	int64_t parent, child, swap_child = 0, d;
Packit 13e616
	boolean_t swapped = FALSE;
Packit 13e616
Packit 13e616
	if (!index)
Packit 13e616
		return;
Packit 13e616
Packit 13e616
	cl_heap_elem_t tmp = p_heap->element_array[index];
Packit 13e616
Packit 13e616
	d = (int64_t) p_heap->branching_factor;
Packit 13e616
	parent = index;
Packit 13e616
	do {
Packit 13e616
		child = parent;
Packit 13e616
		parent = (child - 1) / d;
Packit 13e616
		if (p_heap->
Packit 13e616
		    pfn_compare(&(tmp.key),
Packit 13e616
				&(p_heap->element_array[parent].key)) < 0) {
Packit 13e616
			/* move the parent down and notify the user context about the change */
Packit 13e616
			p_heap->element_array[child] =
Packit 13e616
			    p_heap->element_array[parent];
Packit 13e616
			p_heap->pfn_index_update(p_heap->element_array[child].
Packit 13e616
						 context, child);
Packit 13e616
			swap_child = parent;
Packit 13e616
			swapped = TRUE;
Packit 13e616
		} else
Packit 13e616
			break;
Packit 13e616
	} while (parent > 0);
Packit 13e616
Packit 13e616
	/* write original heap element to the correct position */
Packit 13e616
	if (swapped) {
Packit 13e616
		p_heap->element_array[swap_child] = tmp;
Packit 13e616
		p_heap->pfn_index_update(p_heap->element_array[swap_child].
Packit 13e616
					 context, swap_child);
Packit 13e616
	}
Packit 13e616
}
Packit 13e616
Packit 13e616
cl_status_t cl_heap_modify_key(IN cl_heap_t * const p_heap,
Packit 13e616
			       IN const uint64_t key, IN const size_t index)
Packit 13e616
{
Packit 13e616
	uint64_t old_key;
Packit 13e616
	int compare_result;
Packit 13e616
Packit 13e616
	CL_ASSERT(p_heap);
Packit 13e616
	CL_ASSERT(cl_is_heap_inited(p_heap));
Packit 13e616
Packit 13e616
	if (index < 0 || index >= p_heap->size)
Packit 13e616
		return (CL_INVALID_PARAMETER);
Packit 13e616
Packit 13e616
	old_key = p_heap->element_array[index].key;
Packit 13e616
	p_heap->element_array[index].key = key;
Packit 13e616
Packit 13e616
	compare_result = p_heap->pfn_compare(&key, &old_key);
Packit 13e616
	if (compare_result < 0)
Packit 13e616
		heap_up(p_heap, index);
Packit 13e616
	else if (compare_result > 0)
Packit 13e616
		heap_down(p_heap, index);
Packit 13e616
Packit 13e616
	return (CL_SUCCESS);
Packit 13e616
}
Packit 13e616
Packit 13e616
cl_status_t cl_heap_insert(IN cl_heap_t * const p_heap, IN const uint64_t key,
Packit 13e616
			   IN const void *const context)
Packit 13e616
{
Packit 13e616
	CL_ASSERT(p_heap);
Packit 13e616
	CL_ASSERT(cl_is_heap_inited(p_heap));
Packit 13e616
Packit 13e616
	if (!context)
Packit 13e616
		return (CL_INVALID_PARAMETER);
Packit 13e616
Packit 13e616
	if (p_heap->size == p_heap->capacity)
Packit 13e616
		return (CL_INSUFFICIENT_RESOURCES);
Packit 13e616
Packit 13e616
	p_heap->element_array[p_heap->size].key = key;
Packit 13e616
	p_heap->element_array[p_heap->size].context = (void *) context;
Packit 13e616
	p_heap->pfn_index_update(context, p_heap->size);
Packit 13e616
Packit 13e616
	heap_up(p_heap, p_heap->size++);
Packit 13e616
Packit 13e616
	return (CL_SUCCESS);
Packit 13e616
}
Packit 13e616
Packit 13e616
void *cl_heap_delete(IN cl_heap_t * const p_heap, IN const size_t index)
Packit 13e616
{
Packit 13e616
	int64_t parent, d;
Packit 13e616
	int compare_result;
Packit 13e616
	cl_heap_elem_t tmp;
Packit 13e616
Packit 13e616
	CL_ASSERT(p_heap);
Packit 13e616
	CL_ASSERT(cl_is_heap_inited(p_heap));
Packit 13e616
Packit 13e616
	if (!p_heap->size)
Packit 13e616
		return NULL;
Packit 13e616
	if (index < 0 || index >= p_heap->size)
Packit 13e616
		return NULL;
Packit 13e616
	if (p_heap->size == 1)
Packit 13e616
		return p_heap->element_array[--(p_heap->size)].context;
Packit 13e616
Packit 13e616
	tmp = p_heap->element_array[--(p_heap->size)];
Packit 13e616
Packit 13e616
	p_heap->element_array[p_heap->size] = p_heap->element_array[index];
Packit 13e616
	p_heap->pfn_index_update(p_heap->element_array[p_heap->size].context,
Packit 13e616
				 p_heap->size);
Packit 13e616
Packit 13e616
	p_heap->element_array[index] = tmp;
Packit 13e616
	p_heap->pfn_index_update(p_heap->element_array[index].context, index);
Packit 13e616
Packit 13e616
	if (0 == index)
Packit 13e616
		heap_down(p_heap, index);
Packit 13e616
	else {
Packit 13e616
		d = (int64_t) p_heap->branching_factor;
Packit 13e616
		parent = (index - 1) / d;
Packit 13e616
		compare_result =
Packit 13e616
		    p_heap->pfn_compare(&(p_heap->element_array[parent].key),
Packit 13e616
					&(p_heap->element_array[index].key));
Packit 13e616
Packit 13e616
		/* if the parent is smaller than tmp (which we moved within
Packit 13e616
		 * the head), then we have to attempt a heap_down
Packit 13e616
		 */
Packit 13e616
		if (compare_result < 0)
Packit 13e616
			heap_down(p_heap, index);
Packit 13e616
		/* otherwise heap_up is needed to restore the heap property */
Packit 13e616
		else if (compare_result > 0)
Packit 13e616
			heap_up(p_heap, index);
Packit 13e616
	}
Packit 13e616
Packit 13e616
	return p_heap->element_array[p_heap->size].context;
Packit 13e616
}
Packit 13e616
Packit 13e616
void *cl_heap_extract_root(IN cl_heap_t * const p_heap)
Packit 13e616
{
Packit 13e616
	return cl_heap_delete(p_heap, 0);
Packit 13e616
}
Packit 13e616
Packit 13e616
boolean_t cl_is_stored_in_heap(IN const cl_heap_t * const p_heap,
Packit 13e616
			       IN const void *const ctx, IN const size_t index)
Packit 13e616
{
Packit 13e616
	CL_ASSERT(p_heap);
Packit 13e616
	CL_ASSERT(cl_is_heap_inited(p_heap));
Packit 13e616
Packit 13e616
	return ((index < 0 || index >= p_heap->size ||
Packit 13e616
		 p_heap->element_array[index].context != ctx) ? FALSE : TRUE);
Packit 13e616
}
Packit 13e616
Packit 13e616
boolean_t cl_verify_heap_property(IN const cl_heap_t * const p_heap)
Packit 13e616
{
Packit 13e616
	int64_t first_child, child, parent, d;
Packit 13e616
Packit 13e616
	CL_ASSERT(p_heap);
Packit 13e616
	CL_ASSERT(cl_is_heap_inited(p_heap));
Packit 13e616
Packit 13e616
	d = (int64_t) p_heap->branching_factor;
Packit 13e616
	parent = 0;
Packit 13e616
Packit 13e616
	while (parent < p_heap->size) {
Packit 13e616
		first_child = parent * d + 1;
Packit 13e616
		/* find the min (or max) child among the children */
Packit 13e616
		for (child = first_child;
Packit 13e616
		     child < first_child + d && child < p_heap->size; child++)
Packit 13e616
			if (p_heap->
Packit 13e616
			    pfn_compare(&(p_heap->element_array[parent].key),
Packit 13e616
					&(p_heap->element_array[child].key)) >
Packit 13e616
			    0)
Packit 13e616
				return FALSE;
Packit 13e616
		parent++;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	return TRUE;
Packit 13e616
}