/* -----------------------------------------------------------------------------
	GSFramework
	Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */


#ifndef	__NSORT__
#define	__NSORT__


		#include "ntypes.h"
		#include "container/narray.h"


namespace GS {

/*!
	Sort class.

	Can sort floating point numbers using QuickSort.
	Can also sort integer numbers using Radix sort (byte-sort).

	Use T to specify the type of value to sort and O to track a user value in
	the sorted array (for example an index into the unsorted array).

	@author Emmanuel Julien (ejulien@gsworks.fr)
*/
template <typename T, typename O> struct Sort
{
		//----------------------------------------------------------------------
		struct	Entry
		{
			T		v;
			O		o;
		};
		//----------------------------------------------------------------------

protected:

static	void inline	SwapEntries(Entry &a, Entry &b)
		{	Entry t = a; a = b; b = t;	}

static	void		RecurseQuickSort(Entry *entries, int left, int right)
		{
			if	(left >= right)
				return;

			int pivot = (left + right) >> 1;
			SwapEntries(entries[left], entries[pivot]);

			int ls = left;
			for	(int cr = left + 1; cr <= right; ++cr)
				if	(entries[cr].v < entries[left].v)
					SwapEntries(entries[cr], entries[++ls]);

			SwapEntries(entries[left], entries[ls]);
			RecurseQuickSort(entries, left, ls - 1);
			RecurseQuickSort(entries, ls + 1, right);
		}

public:

		/// Quicksort n entries in-place.
static	void		QuickSort(int n, Entry *entries)
		{
			RecurseQuickSort(entries, 0, n - 1);
		}

		/// Byte-sort sort n entries from in to out.
static	Array <Entry>	*ByteSort(uint n, Array <Entry> *a, Array <Entry> *b)
		{
			if	(!a || !b)
				return 0;

			uint radix[257];

			for (size_t pass = 0; pass < sizeof(T); ++pass)
			{
				// clear radix buffer
				for (uint i = 0; i < 257; ++i)
					radix[i] = 0;

				// count radix
				for (uint i = 0; i < n; ++i)
					++radix[uint((*a)[i].v & 255) + 1];

				// convert count to index
				for (uint i = 0; i < 256; ++i)
					radix[i + 1] += radix[i];

				// insert values
				for (uint i = 0; i < n; i++)
				{
					const uint p = radix[uint((*a)[i].v & 255)]++;
					(*b)[p].v = (*a)[i].v >> 8;	// transfer & shift radix
					(*b)[p].o = (*a)[i].o;
				}

				// swap arrays
				Array <Entry> *tmp = b; b = a; a = tmp;
			}
			return a;
		}
		//----------------------------------------------------------------------
};

} // GS


#endif

