/****************************************************************************/
/*	Copyright (c) 2009, Bendor Research Pty. Ltd. All rights reserved.		*/
/*	This software is released under the GNU General Public License, version	*/
/*	3, with the exemptions that 1) the header files installed by this 	 	*/
/*	package can be included in closed-source code and 2) the libraries		*/
/*	built by this package can be statically linked into a closed-source 	*/
/*	binary. See the file LICENSE for the details.							*/
/*	This software is provided "AS IS", without any warranty or guarantee.	*/
/*	By using this software you acknowledge that neither Bendor Research nor	*/
/*	any of its personnel or affiliates can be held liable for any damages,	*/
/*	including, but not limited to, loss of business, loss of money, loss of */
/*	life, loss of reputation, arising out of this software being faulty or	*/
/*	not performing as advertised, even if Bendor Research was aware of such	*/
/*	faults in the software. You use this software at your own risk, any and */
/*	all liabilities that arise out of your using this software are strictly	*/
/*	yours.																	*/
/****************************************************************************/

#include <stdlib.h>

/****************************************************************************/
/*					Public API functions									*/
/****************************************************************************/

/** @addtogroup stdlib */
/**	@{ */

/**
*	Sort an array.
*
*	The routine sorts an array of arbitrary comparable objects into
*	ascending order. Unlike the qsort() function, this function does
*	not assume that your array is a real array of identical objects
*	in memory. Rather, the objects you want to sort are identified by
*	an index, between 0 and N-1 where N is the number of objects you
*	want to sort. The comparison function receives the indices, not
*	pointers to objects. Since the hsort() function does not assume anything
*	about your objects, it can not copy them. Therefore, you also have
*	to supply a function that can copy an object to an other, receiving
*	the index of both.
*	<br><br>
*	In addition, you have to facilitate the temporary storage of one
*	object outside of your array. When you receive the index of -1, then
*	that index refers to this extra storage facility. This is true for
*	both the comparison and the copy function. This storage must be persistent
*	during the execution of the hsort() function.
*	<br><br>
*	The function implements heapsort, thus the time needed to sort your
*	array is O( N * log2( N ) ) operations, both compares and copies,
*	regardless of the state of your array. In practice, hsort() will
*	call the copy function somewhere between N*log<sub>2</sub>(N) and
*	2*N*log<sub>2</sub>(N) times and the compare function about 1.42
*	times more than the copy.
*	<br><br>
*	Note that since the function does not actually dereference any of your
*	objects, the objects do not really have to be in an array, not even in
*	memory and they do not need to be of the same size, or even the same
*	object type. As long as you can compare and copy them by an index, that
*	is, an integer identifying an object, you can sort them using this
*	function.
*
*
*	@param	numb	The number of objects to sort.
*
*	@param	parm	A void pointer that will be passed as the third argument
*					of the comparison and copy functions. The hsort() function
*					only passes this argument to the two other functions, it
*					does not use it itself.
*
*	@param	comp	A pointer to a function that receives the index of two
*					objects and returns less than 0, 0 or greater than 0
*					if the first object is, respectively, less than, equal
*					to or greater than the second object. The index value
*					of -1 refers to an extra storage facility, able to hold
*					one object. A third parameter, a void pointer is also
*					passed to the function, which is the second argument of
*					the hsort() function.
*
*	@param	copy	A pointer to a function that receives the index of two
*					objects and copies the one selected by the second
*					index to the object selected by the first. The index value
*					of -1 refers to a temporary storage facility that can hold
*					one object. A third parameter, a void pointer is also
*					passed to the function, which is the second argument of
*					the hsort() function.
*/

void	hsort( int numb, void *parm, int (*comp)( int, int, void *),
			   void (*copy)( int, int, void * ) )
{
int		this, that, temp;

	if ( numb <= 0 ) return;

	for ( temp = ( numb - 2 ) / 2 ; temp >= 0 ; temp-- ) {

		this = temp;
		that = 2 * this + 2;
		if ( that > numb ) continue;
		if ( that == numb || (*comp)( that, that - 1, parm ) < 0 ) that--;
		if ( (*comp)( this, that, parm ) >= 0 ) continue;

		(*copy)( -1, this, parm );
		(*copy)( this, that, parm );
		this = that;

		while ( ( that = 2 * this + 2 ) <= numb ) {

			if ( that == numb || (*comp)( that, that-1, parm ) < 0 ) that--;
			if ( (*comp)( -1, that, parm ) >= 0 ) break;
			(*copy)( this, that, parm );
			this = that;
		}

		(*copy)( this, -1, parm );
	}

	while ( numb-- > 2 ) {

		(*copy)( -1, numb, parm );
		(*copy)( numb, 0, parm );

		this = 0;
		that = 2;

		if ( numb == 2 || (*comp)( 2, 1, parm ) < 0 ) that = 1;

		if ( (*comp)( -1, that, parm ) >= 0 ) {

			(*copy)( 0, -1, parm );
			continue;
		}

		(*copy)( 0, that, parm );
		this = that;

		while ( ( that = 2 * this + 1 ) < numb ) {

			temp = that + 1;
			if ( temp < numb && (*comp)( temp, that, parm ) >= 0 ) that = temp;
			if ( (*comp)( -1, that, parm ) >= 0 ) break;
			(*copy)( this, that, parm );
			this = that;
		}

		(*copy)( this, -1, parm );
	}

	(*copy)( -1, 0, parm );
	(*copy)( 0, 1, parm );
	(*copy)( 1, -1, parm );
}

/** @} */

