#ifndef _T_JRunArray
#define _T_JRunArray

/******************************************************************************
 JRunArray.tmpl

	JRunArray is a dynamic array optimized to conserve space where
	consecutive entries have the same value. Such a sequence of
	identical entries is called a run. Rather than storing N
	consecutive, identical entries, JRunArray stores the value once, 
	along with the length of the run.

	When using a JRunArray, operator== must be defined for the data type.

	gcc 2.7.2 does not implement static data for template classes, without
	which we cannot provide an efficient implementation of Sort().

	Implementation details:

	A JArray is used to store the run lengths + actual items.
	Thus, JRunArrays cannot store objects, only intrinisic types.

	BASE CLASS = JOrderedSet

	Copyright © 1994-97 by John Lindal. All rights reserved.

 ******************************************************************************/

#include <JRunArray.h>
#include <jAssert.h>

#if !defined __GNUG__
template <class T>
JOrderedSetT::CompareResult (*JRunArray<T>::itsCurrentCompareFn)(const T&, const T&) = NULL;
#endif

static int (*theCurrentQuickSortCompareFn)(const void*, const void*) = NULL;

/******************************************************************************
 Constructor

 ******************************************************************************/

template <class T>
JRunArray<T>::JRunArray()
	:
	JOrderedSet<T>()
{
	itsRuns = new JArray< JRunArrayElement<T> >;
	assert( itsRuns != NULL );
}

/******************************************************************************
 Copy constructor

 ******************************************************************************/

template <class T>
JRunArray<T>::JRunArray
	(
	const JRunArray<T>& source
	)
	:
	JOrderedSet<T>(source)
{
	itsRuns = new JArray< JRunArrayElement<T> >(*(source.itsRuns));
	assert( itsRuns != NULL );
}

/******************************************************************************
 Destructor

 ******************************************************************************/

template <class T>
JRunArray<T>::~JRunArray()
{
	delete itsRuns;
}

/******************************************************************************
 Assignment operator

 ******************************************************************************/

template <class T>
const JRunArray<T>&
JRunArray<T>::operator=
	(
	const JRunArray<T>& source
	)
{
	if (this == &source)
		{
		return *this;
		}

	JCollection::operator=(source);		// JOrderedSet::operator= is private

	*itsRuns = *(source.itsRuns);
	OrderedSetAssigned(source);

	return *this;
}

/******************************************************************************
 InsertElementAtIndex

	Insert an element into the array at the specified index. Any elements
	at or above index are moved down. If index is any value greater
	than the current size, then the element is appended to the end
	of the array.

 ******************************************************************************/

template <class T>
void
JRunArray<T>::InsertElementAtIndex
	(
	const JIndex	elementIndex,
	const T&		data
	)
{
	InsertElementsAtIndex(elementIndex, data, 1);
}

/******************************************************************************
 InsertElementsAtIndex

	Insert a run of elements into the array at the specified index.
	Any elements at or below elementIndex are moved down. If index is any value
	greater than the current size, then the elements are appended to the end
	of the array.

	The second version assumes *runIndex,*firstIndexInRun refer to the run
	containing elementIndex and updates them based on what has to be done
	to the runs.

 ******************************************************************************/

template <class T>
void
JRunArray<T>::InsertElementsAtIndex
	(
	const JIndex	elementIndex,
	const T&		data,
	const JSize		newElementCount
	)
{
	const JIndex trueElementIndex =
		PrivateInsertElementsAtIndex(elementIndex, data, newElementCount);

	JOrderedSetT::ElementsInserted message(trueElementIndex, newElementCount);
	NotifyIterators(message);
	Broadcast(message);
}

template <class T>
void
JRunArray<T>::InsertElementsAtIndex
	(
	const JIndex	elementIndex,
	const T&		data,
	const JSize		newElementCount,
	JIndex*			runIndex,
	JIndex*			firstIndexInRun
	)
{
	assert( *firstIndexInRun <= elementIndex );

	const JIndex trueElementIndex =
		PrivateInsertElementsAtIndex(elementIndex, data, newElementCount,
									 runIndex, firstIndexInRun);

	JOrderedSetT::ElementsInserted message(trueElementIndex, newElementCount);
	NotifyIterators(message);
	Broadcast(message);
}

/******************************************************************************
 PrependElements

	Prepend a run of elements.

 ******************************************************************************/

template <class T>
void
JRunArray<T>::PrependElements
	(
	const T&	data,
	const JSize	newElementCount
	)
{
	InsertElementsAtIndex(1, data, newElementCount);
}

/******************************************************************************
 AppendElements

	Append a run of elements.

 ******************************************************************************/

template <class T>
void
JRunArray<T>::AppendElements
	(
	const T&	data,
	const JSize	newElementCount
	)
{
	InsertElementsAtIndex(GetElementCount()+1, data, newElementCount);
}

/******************************************************************************
 PrivateInsertElementsAtIndex

	We need this method so MoveElementToIndex can insert an element without
	the ElementsInserted message being broadcast.

	It returns the actual starting index so InsertElementsAtIndex can
	broadcast the correct index.

	The second version assumes *runIndex,*firstIndexInRun refer to the run
	containing elementIndex and updates them based on what has to be done
	to the runs.

 ******************************************************************************/

template <class T>
JIndex
JRunArray<T>::PrivateInsertElementsAtIndex
	(
	const JIndex	elementIndex,
	const T&		data,
	const JSize		newElementCount
	)
{
	JIndex runIndex, firstIndexInRun;
	FindRun(elementIndex, &runIndex, &firstIndexInRun);
	return PrivateInsertElementsAtIndex(elementIndex, data, newElementCount,
										&runIndex, &firstIndexInRun);
}

template <class T>
JIndex
JRunArray<T>::PrivateInsertElementsAtIndex
	(
	const JIndex	elementIndex,
	const T&		data,
	const JSize		newElementCount,
	JIndex*			runIndex,
	JIndex*			firstIndexInRun
	)
{
	assert( elementIndex > 0 );
	assert( newElementCount > 0 );

	if (IndexValid(elementIndex))
		{
		if (data == GetRunDataRef(*runIndex))
			{
			IncrementRunLength(*runIndex, newElementCount);
			}
		else
			{
			// We save a lot of code by incrementing the run length and
			// then asking SetValue to handle the details of splitting
			// the run.

			IncrementRunLength(*runIndex, 1);
			PrivateSetElement(elementIndex, data, runIndex, firstIndexInRun);

			// now insert the rest, if any, once we know the runs won't change

			if (newElementCount > 1)
				{
				IncrementRunLength(*runIndex, newElementCount-1);
				}
			}

		return elementIndex;
		}
	else
		{
		// We need to append the data to the end of the array.

		const JSize elementCount = GetElementCount();
		const JSize runCount     = GetRunCount();

		if (runCount > 0 && data == GetRunDataRef(runCount))
			{
			IncrementRunLength(runCount, newElementCount);
			}
		else
			{
			InsertRun(runCount+1, newElementCount, data);
			}

		*runIndex        = GetRunCount();
		*firstIndexInRun = GetElementCount() - GetRunLength(*runIndex) + 1;

		return elementCount + 1;
		}
}

/******************************************************************************
 InsertElementsAtIndex

	Copy the specified number of elements from the given JRunArray.

 ******************************************************************************/

template <class T>
void
JRunArray<T>::InsertElementsAtIndex
	(
	const JIndex		origInsertionIndex,
	const JRunArray<T>&	source,
	const JIndex		origFirstIndex,
	const JSize			count
	)
{
	JIndex runIndex, firstIndexInRun;
	const JBoolean found = source.FindRun(origFirstIndex, &runIndex, &firstIndexInRun);
	assert( found );

	JIndex insertIndex = origInsertionIndex;
	JIndex firstIndex  = origFirstIndex;
	JSize remainder    = count;
	while (remainder > 0)
		{
		const JSize runLength  = source.GetRunLength(runIndex);
		const JSize rightCount = runLength - (firstIndex - firstIndexInRun);

		const T& data = source.GetRunDataRef(runIndex);
		if (rightCount < remainder)
			{
			InsertElementsAtIndex(insertIndex, data, rightCount);
			insertIndex += rightCount;
			firstIndex  += rightCount;
			remainder   -= rightCount;

			firstIndexInRun += runLength;
			runIndex++;
			}
		else	// remainder <= rightCount
			{
			InsertElementsAtIndex(insertIndex, data, remainder);
			break;
			}
		}
}

/******************************************************************************
 RemoveNextElements

	The second version assumes *runIndex,*firstIndexInRun refer to the run
	containing firstIndex and updates them based on what has to be done
	to the runs.

 ******************************************************************************/

template <class T>
void
JRunArray<T>::RemoveNextElements
	(
	const JIndex	firstIndex,
	const JSize		count
	)
{
	assert( IndexValid(firstIndex) && IndexValid(firstIndex+count-1) );

	PrivateRemoveNextElements(firstIndex, count);

	JOrderedSetT::ElementsRemoved message(firstIndex, count);
	NotifyIterators(message);
	Broadcast(message);
}

template <class T>
void
JRunArray<T>::RemoveNextElements
	(
	const JIndex	firstIndex,
	const JSize		count,
	JIndex*			runIndex,
	JIndex*			firstIndexInRun
	)
{
	assert( IndexValid(firstIndex) && IndexValid(firstIndex+count-1) );
	assert( *firstIndexInRun <= firstIndex );

	PrivateRemoveNextElements(firstIndex, count, runIndex, firstIndexInRun);

	JOrderedSetT::ElementsRemoved message(firstIndex, count);
	NotifyIterators(message);
	Broadcast(message);
}

// private

template <class T>
void
JRunArray<T>::IteratorRemoveNextElements
	(
	const JIndex	firstIndex,
	const JSize		count,
	const JIndex	origRunIndex,
	const JIndex	origFirstIndexInRun
	)
{
	JIndex runIndex        = origRunIndex;
	JIndex firstIndexInRun = origFirstIndexInRun;
	PrivateRemoveNextElements(firstIndex, count, &runIndex, &firstIndexInRun);

	JOrderedSetT::ElementsRemoved message(firstIndex, count);
	NotifyIterators(message);
	Broadcast(message);
}

/******************************************************************************
 PrivateRemoveNextElements (private)

	We need this method so MoveElementToIndex() can remove an element without
	the ElementsRemoved message being broadcast.

	The second version assumes *runIndex,*firstIndexInRun refer to the run
	containing firstIndex and updates them based on what has to be done
	to the runs.

 ******************************************************************************/

template <class T>
void
JRunArray<T>::PrivateRemoveNextElements
	(
	const JIndex	firstIndex,
	const JSize		count
	)
{
	JIndex runIndex, firstIndexInRun;
	const JBoolean found = FindRun(firstIndex, &runIndex, &firstIndexInRun);
	assert( found );

	PrivateRemoveNextElements(firstIndex, count, &runIndex, &firstIndexInRun);
}

template <class T>
void
JRunArray<T>::PrivateRemoveNextElements
	(
	const JIndex	firstIndex,
	const JSize		count,
	JIndex*			runIndex,
	JIndex*			firstIndexInRun
	)
{
	if (firstIndex == 1 && count == GetElementCount())
		{
		RemoveAll();
		return;
		}

	JSize remainder = count;
	while (remainder > 0)
		{
		const JSize rightCount =
			GetRunLength(*runIndex) - (firstIndex - *firstIndexInRun);

		if (*firstIndexInRun == firstIndex && rightCount <= remainder)
			{
			RemoveRun(*runIndex, runIndex, firstIndexInRun);
			remainder -= rightCount;
			}
		else if (*firstIndexInRun < firstIndex && rightCount <= remainder)
			{
			DecrementRunLength(*runIndex, rightCount);
			remainder       -= rightCount;
			*firstIndexInRun = firstIndex;
			(*runIndex)++;
			}
		else	// remainder < rightCount
			{
			DecrementRunLength(*runIndex, remainder);
			break;
			}
		}
}

/******************************************************************************
 RemoveAll

 ******************************************************************************/

template <class T>
void
JRunArray<T>::RemoveAll()
{
	if (!IsEmpty())
		{
		itsRuns->RemoveAll();
		SetElementCount(0);

		JOrderedSetT::AllElementsRemoved message;
		NotifyIterators(message);
		Broadcast(message);
		}
}

/******************************************************************************
 GetElement

 ******************************************************************************/

template <class T>
const T
JRunArray<T>::GetElement
	(
	const JIndex elementIndex
	)
	const
{
	JIndex runIndex, firstIndexInRun;
	const JBoolean ok = FindRun(elementIndex, &runIndex, &firstIndexInRun);
	assert( ok );
	return GetRunDataRef(runIndex);
}

/******************************************************************************
 SetElement

 ******************************************************************************/

template <class T>
void
JRunArray<T>::SetElement
	(
	const JIndex	elementIndex,
	const T&		data
	)
{
	assert( IndexValid(elementIndex) );

	if (PrivateSetElement(elementIndex, data))
		{
		JOrderedSetT::ElementChanged message(elementIndex);
		NotifyIterators(message);
		Broadcast(message);
		}
}

// private

template <class T>
void
JRunArray<T>::IteratorSetElement
	(
	const JIndex	elementIndex,
	const T&		data,
	const JIndex	origRunIndex,
	const JIndex	origFirstIndexInRun
	)
{
	JIndex runIndex        = origRunIndex;
	JIndex firstIndexInRun = origFirstIndexInRun;
	if (PrivateSetElement(elementIndex, data, &runIndex, &firstIndexInRun))
		{
		JOrderedSetT::ElementChanged message(elementIndex);
		NotifyIterators(message);
		Broadcast(message);
		}
}

/******************************************************************************
 PrivateSetElement (private)

	We need this method so SwapElements can avoid the ElementChanged message.

	Returns kTrue if the element actually changed.

	The second version assumes *runIndex,*firstIndexInRun refer to the run
	containing elementIndex and updates them based on what has to be done
	to the runs.

 ******************************************************************************/

template <class T>
JBoolean
JRunArray<T>::PrivateSetElement
	(
	const JIndex	elementIndex,
	const T&		data
	)
{
	JIndex runIndex, firstIndexInRun;
	const JBoolean found = FindRun(elementIndex, &runIndex, &firstIndexInRun);
	assert( found );

	return PrivateSetElement(elementIndex, data, &runIndex, &firstIndexInRun);
}

template <class T>
JBoolean
JRunArray<T>::PrivateSetElement
	(
	const JIndex	elementIndex,
	const T&		data,
	JIndex*			runIndex,
	JIndex*			firstIndexInRun
	)
{
	const T originalElement = GetRunDataRef(*runIndex);
	if (data == originalElement)
		{
		return kFalse;
		}

	const JSize origRunLength   = GetRunLength(*runIndex);
	const JIndex lastIndexInRun = *firstIndexInRun + origRunLength - 1;

	// check if the element can go in the previous run

	if (*runIndex > 1 && elementIndex == *firstIndexInRun &&
		data == GetRunDataRef(*runIndex-1))
		{
		*firstIndexInRun -= GetRunLength(*runIndex-1);

		if (origRunLength == 1)
			{
			RemoveRun(*runIndex);
			}
		else
			{
			DecrementRunLength(*runIndex, 1);
			}

		(*runIndex)--;
		IncrementRunLength(*runIndex, 1);
		}

	// check if the element can go in the next run

	else if (*runIndex < GetRunCount() && elementIndex == lastIndexInRun &&
			 data == GetRunDataRef(*runIndex+1))
		{
		IncrementRunLength(*runIndex+1, 1);

		if (origRunLength == 1)
			{
			RemoveRun(*runIndex, runIndex, firstIndexInRun);
			}
		else
			{
			DecrementRunLength(*runIndex, 1);
			*firstIndexInRun += GetRunLength(*runIndex);
			(*runIndex)++;
			}
		}

	// Since we can't merge it with the previous or the next run,
	// check if this is the only element in the run.

	else if (origRunLength == 1)
		{
		SetRunData(*runIndex, data);
		}

	// We have to break the run into two or more runs.

	else
		{
		// At this point we know the run size is greater than
		// one and if the item is at the start or end of the
		// run, we can't merge it with the previous or next run.
		// Therefore the item itself starts a new run, and there
		// may be a new run preceeding or following the item.

		if (elementIndex > *firstIndexInRun)
			{
			InsertRun(*runIndex, elementIndex - *firstIndexInRun, originalElement);
			(*runIndex)++;							// everything just moved down
			}
		if (elementIndex < lastIndexInRun)
			{
			InsertRun(*runIndex+1, lastIndexInRun - elementIndex, originalElement);
			}

		// The item now has the run all to itself. Update the value and length.

		SetRunInfo(*runIndex, 1, data);

		*firstIndexInRun = elementIndex;
		}

	return kTrue;
}

/******************************************************************************
 SetNextElements

 ******************************************************************************/

template <class T>
void
JRunArray<T>::SetNextElements
	(
	const JIndex	firstIndex,
	const JSize		count,
	const T&		data
	)
{
	JIndex runIndex, firstIndexInRun;
	const JBoolean found = FindRun(firstIndex, &runIndex, &firstIndexInRun);
	assert( found );

	SetNextElements(firstIndex, count, data, &runIndex, &firstIndexInRun);
}

template <class T>
void
JRunArray<T>::SetNextElements
	(
	const JIndex	firstIndex,
	const JSize		count,
	const T&		data,
	JIndex*			runIndex,
	JIndex*			firstIndexInRun
	)
{
	RemoveNextElements(firstIndex, count, runIndex, firstIndexInRun);
	InsertElementsAtIndex(firstIndex, data, count, runIndex, firstIndexInRun);
}

/******************************************************************************
 MoveElementToIndex

 ******************************************************************************/

template <class T>
void
JRunArray<T>::MoveElementToIndex
	(
	const JIndex currentIndex,
	const JIndex newIndex
	)
{
	assert( IndexValid(currentIndex) );
	assert( IndexValid(newIndex) );

	if (currentIndex == newIndex)
		{
		return;
		}

	const T savedElement = GetElement(currentIndex);
	PrivateRemoveNextElements(currentIndex, 1);
	PrivateInsertElementsAtIndex(newIndex, savedElement, 1);

	JOrderedSetT::ElementMoved message(currentIndex, newIndex);
	NotifyIterators(message);
	Broadcast(message);
}

/******************************************************************************
 SwapElements

	Sends dependents an arrayElementChanged message for both elements.

 ******************************************************************************/

template <class T>
void
JRunArray<T>::SwapElements
	(
	const JIndex index1,
	const JIndex index2
	)
{
	assert( IndexValid(index1) );
	assert( IndexValid(index2) );

	if (index1 == index2)
		{
		return;
		}

	const T savedElement = GetElement(index1);
	if (PrivateSetElement(index1, GetElement(index2)))
		{
		// We only have to do this if the elements are different.

		PrivateSetElement(index2, savedElement);
		}

	JOrderedSetT::ElementsSwapped message(index1, index2);
	NotifyIterators(message);
	Broadcast(message);
}

#if !defined __GNUG__

/******************************************************************************
 Sort (virtual)

	We sort the runs and then merge them afterwards.
	Broadcasts JOrderedSetT::Sorted.

 ******************************************************************************/

template <class T>
void
JRunArray<T>::Sort()
{
	assert( itsCurrentCompareFn == NULL );

	itsCurrentCompareFn = GetCompareFunction();
	itsRuns->SetCompareFunction(CompareRuns);
	itsRuns->SetSortOrder(GetSortOrder());

	itsRuns->Sort();

	itsCurrentCompareFn = NULL;
	itsRuns->SetCompareFunction(NULL);

	MergeAdjacentRuns();

	JOrderedSetT::Sorted message;
	NotifyIterators(message);
	Broadcast(message);
}

/******************************************************************************
 SearchSorted1 (virtual)

	We search by run.

 ******************************************************************************/

template <class T>
JIndex
JRunArray<T>::SearchSorted1
	(
	const T&							origTarget,
	const JOrderedSetT::SearchReturn	which,
	JBoolean*							found
	)
	const
{
	assert( itsCurrentCompareFn == NULL );

	itsCurrentCompareFn = GetCompareFunction();
	itsRuns->SetCompareFunction(CompareRuns);
	itsRuns->SetSortOrder(GetSortOrder());

	JRunArrayElement<T> target(1, origTarget);
	const JIndex runIndex = itsRuns->SearchSorted1(target, which, found);

	itsCurrentCompareFn = NULL;
	itsRuns->SetCompareFunction(NULL);

	const JRunArrayElement<T>* runData = itsRuns->GetCArray();

	JIndex elementIndex = 1;
	for (JIndex i=1; i<runIndex; i++)
		{
		elementIndex += runData[i-1].length;
		}
	if (*found && which == JOrderedSetT::kLastMatch)
		{
		elementIndex += runData[runIndex-1].length - 1;
		}
	return elementIndex;
}

/******************************************************************************
 CompareRuns (static private)

	This function translates comparisons of JRunArrayElement<T>
	into comparisons of T.

 ******************************************************************************/

template <class T>
JOrderedSetT::CompareResult
JRunArray<T>::CompareRuns
	(
	const JRunArrayElement<T>& r1,
	const JRunArrayElement<T>& r2
	)
{
	return itsCurrentCompareFn(r1.data, r2.data);
}

#endif

/******************************************************************************
 QuickSort

	We sort the runs and then merge them afterwards.

	Uses qsort() and broadcasts JOrderedSetT::Sorted afterwards.

	Since qsort() wants the sort order to be encoded in the comparison
	function, and since the comparison function prototype is different,
	we do -not- use the sorting information from JOrderedSet.

	The compare function should compare the data, not JRunArrayElements.

 ******************************************************************************/

template <class T>
void
JRunArray<T>::QuickSort
	(
	int (*compare)(const void*, const void*)
	)
{
	assert( theCurrentQuickSortCompareFn == NULL );

	theCurrentQuickSortCompareFn = compare;
	itsRuns->QuickSort(QuickSortCompareRuns);
	theCurrentQuickSortCompareFn = NULL;

	MergeAdjacentRuns();

	JOrderedSetT::Sorted message;
	NotifyIterators(message);
	Broadcast(message);
}

/******************************************************************************
 QuickSortCompareRuns (static private)

	This function translates comparisons of JRunArrayElement<T>
	into comparisons of T.

 ******************************************************************************/

template <class T>
int
JRunArray<T>::QuickSortCompareRuns
	(
	const void* p1,
	const void* p2
	)
{
	const JRunArrayElement<T>* r1 = static_cast<const JRunArrayElement<T>*>(p1);
	const JRunArrayElement<T>* r2 = static_cast<const JRunArrayElement<T>*>(p2);
	return theCurrentQuickSortCompareFn(&(r1->data), &(r2->data));
}

/******************************************************************************
 MergeAdjacentRuns (private)

	Called after sorting the runs.

 ******************************************************************************/

template <class T>
void
JRunArray<T>::MergeAdjacentRuns()
{
	JSize runCount = GetRunCount();
	for (JIndex i=1; i<runCount; i++)
		{
		if (GetRunDataRef(i) == GetRunDataRef(i+1))
			{
			IncrementRunLength(i, GetRunLength(i+1));
			RemoveRun(i+1);
			runCount = GetRunCount();
			}
		}
}

/******************************************************************************
 NewIterator

 ******************************************************************************/

template <class T>
JOrderedSetIterator<T>*
JRunArray<T>::NewIterator
	(
	const JIteratorPosition	start,
	const JIndex			index
	)
{
	JRunArrayIterator<T>* iter = new JRunArrayIterator<T>(this, start, index);
	assert( iter != NULL );
	return iter;
}

template <class T>
JOrderedSetIterator<T>*
JRunArray<T>::NewIterator
	(
	const JIteratorPosition	start,
	const JIndex			index
	)
	const
{
	JRunArrayIterator<T>* iter = new JRunArrayIterator<T>(*this, start, index);
	assert( iter != NULL );
	return iter;
}

/******************************************************************************
 SetBlockSize

	Set the block size used by the underlying JArray.

 ******************************************************************************/

template <class T>
void
JRunArray<T>::SetBlockSize
	(
	const JArrayBlockSize newBlockSize
	)
{
	itsRuns->SetBlockSize(newBlockSize);
}

/******************************************************************************
 GetRunCount

 ******************************************************************************/

template <class T>
JSize
JRunArray<T>::GetRunCount()
	const
{
	return itsRuns->GetElementCount();
}

/******************************************************************************
 FindRun

	Return the index of the run containing the element with the specified index.
	firstIndexInRun is updated with the index of the first element in the run.

	Returns kFalse if elementIndex is not in the array.

	On the assumption that most run arrays have a relatively uniform
	distribution of runs (JTextEditor is a good example, JTableSelection
	with a rectangular selection is a counterexample), we start from the
	edge of the array that is closest to elementIndex.

 ******************************************************************************/

template <class T>
JBoolean
JRunArray<T>::FindRun
	(
	const JIndex	elementIndex,

	JIndex*			runIndex,
	JIndex*			firstIndexInRun
	)
	const
{
	const JSize count = GetElementCount();
	if (elementIndex <= 1 + count/2)	// automatically catches count==0
		{
		*runIndex        = 1;
		*firstIndexInRun = 1;
		return FindRun(1, elementIndex, runIndex, firstIndexInRun);
		}
	else
		{
		*runIndex         = GetRunCount();
		*firstIndexInRun  = count - GetRunLength(*runIndex) + 1;
		return FindRun(count, elementIndex, runIndex, firstIndexInRun);
		}
}

/******************************************************************************
 FindRun

	Assuming that *runIndex,*firstIndexInRun correspond to origIndex,
	modify them to correspond to newIndex.

	Returns kFalse if origIndex or newIndex is not in the array.

 ******************************************************************************/

template <class T>
JBoolean
JRunArray<T>::FindRun
	(
	const JIndex	origIndex,
	const JIndex	newIndex,

	JIndex*			runIndex,
	JIndex*			firstIndexInRun
	)
	const
{
	if (!IndexValid(origIndex) || !IndexValid(newIndex))
		{
		return kFalse;
		}

	assert( *firstIndexInRun <= origIndex );

	if (newIndex < origIndex)
		{
		const JRunArrayElement<T>* r = itsRuns->GetCArray() + *runIndex-1;

		JBoolean found = kFalse;
		for (JIndex i=*runIndex; i>=1; i--)
			{
			if (*firstIndexInRun <= newIndex)
				{
				*runIndex = i;
				found     = kTrue;
				break;
				}
			if (i > 1)
				{
				r--;
				*firstIndexInRun -= r->length;
				}
			}
		return found;
		}
	else if (origIndex < newIndex)
		{
		const JRunArrayElement<T>* r = itsRuns->GetCArray() + *runIndex-1;
		JIndex lastIndexInRun        = *firstIndexInRun - 1;

		JBoolean found       = kFalse;
		const JSize runCount = itsRuns->GetElementCount();
		for (JIndex i=*runIndex; i<=runCount; i++, r++)
			{
			lastIndexInRun += r->length;
			if (newIndex <= lastIndexInRun)
				{
				*runIndex        = i;
				*firstIndexInRun = lastIndexInRun - r->length + 1;
				found            = kTrue;
				break;
				}
			}
		return found;
		}
	else	// origIndex == newIndex
		{
		return kTrue;
		}
}

/******************************************************************************
 InsertRun (private)

 ******************************************************************************/

template <class T>
void
JRunArray<T>::InsertRun
	(
	const JIndex	runIndex,
	const JSize		newRunLength,
	const T&		data
	)
{
	JRunArrayElement<T> run(newRunLength, data);
	itsRuns->InsertElementAtIndex(runIndex, run);

	SetElementCount(GetElementCount() + newRunLength);
}

/******************************************************************************
 RemoveRun (private)

	This can result in the merging of two adjacent runs
	if they have the same value.

	newRunIndex,newFirstInRun can be NULL.  If they are not, they must
	apply to the run that is being removed.  They are then updated if runs
	end up being merged.

 ******************************************************************************/

template <class T>
void
JRunArray<T>::RemoveRun
	(
	const JIndex	runIndex,
	JIndex*			newRunIndex,
	JIndex*			newFirstInRun
	)
{
	assert( newRunIndex == NULL || (*newRunIndex == runIndex && newFirstInRun != NULL) );

	SetElementCount(GetElementCount() - GetRunLength(runIndex));
	itsRuns->RemoveElement(runIndex);

	// If the specified run was between two runs with the same value,
	// then we can merge them.

	if (1 < runIndex && runIndex <= GetRunCount() &&
		GetRunDataRef(runIndex-1) == GetRunDataRef(runIndex))
		{
		if (newRunIndex != NULL)
			{
			*newFirstInRun -= GetRunLength(runIndex-1);
			(*newRunIndex)--;
			}

		const JSize runLength = GetRunLength(runIndex);
		IncrementRunLength(runIndex-1, runLength);

		SetElementCount(GetElementCount() - runLength);
		itsRuns->RemoveElement(runIndex);
		}
}

/******************************************************************************
 GetRunLength

 ******************************************************************************/

template <class T>
JSize
JRunArray<T>::GetRunLength
	(
	const JIndex runIndex
	)
	const
{
	assert( itsRuns->IndexValid(runIndex) );
	const JRunArrayElement<T>* runData = itsRuns->GetCArray();
	return runData[runIndex-1].length;
}

/******************************************************************************
 SetRunLength (private)

	Set the length of the specified run, and keep elementCount up to date.

 ******************************************************************************/

template <class T>
void
JRunArray<T>::SetRunLength
	(
	const JIndex	runIndex,
	const JSize		newLength
	)
{
	JRunArrayElement<T> run = itsRuns->GetElement(runIndex);

	SetElementCount(GetElementCount() - run.length + newLength);

	run.length = newLength;
	itsRuns->SetElement(runIndex, run);
}

/******************************************************************************
 IncrementRunLength (private)

	Add value of "extraElementCount" to the length of the specified run.

 ******************************************************************************/

template <class T>
void
JRunArray<T>::IncrementRunLength
	(
	const JIndex	runIndex,
	const JSize		delta
	)
{
	SetRunLength(runIndex, GetRunLength(runIndex) + delta);
}

/******************************************************************************
 DecrementRunLength (private)

	Subtract value of "extraElementCount" from the length of the specified run.

 ******************************************************************************/

template <class T>
void
JRunArray<T>::DecrementRunLength
	(
	const JIndex	runIndex,
	const JSize		delta
	)
{
	SetRunLength(runIndex, GetRunLength(runIndex) - delta);
}

/******************************************************************************
 GetRunData

 ******************************************************************************/

template <class T>
T
JRunArray<T>::GetRunData
	(
	const JIndex runIndex
	)
	const
{
	return GetRunDataRef(runIndex);
}

template <class T>
const T&
JRunArray<T>::GetRunDataRef
	(
	const JIndex runIndex
	)
	const
{
	assert( itsRuns->IndexValid(runIndex) );
	const JRunArrayElement<T>* runData = itsRuns->GetCArray();
	return runData[runIndex-1].data;
}

/******************************************************************************
 SetRunData

	*** This function does not broadcast ElementChanged.

 ******************************************************************************/

template <class T>
void
JRunArray<T>::SetRunData
	(
	const JIndex	runIndex,
	const T&		data
	)
{
	JRunArrayElement<T> run = itsRuns->GetElement(runIndex);
	run.data = data;
	itsRuns->SetElement(runIndex, run);
}

/******************************************************************************
 SetRunInfo (private)

	Set the length and data of the specified run, and keep elementCount up to date.

 ******************************************************************************/

template <class T>
void
JRunArray<T>::SetRunInfo
	(
	const JIndex	runIndex,
	const JSize		newLength,
	const T&		data
	)
{
	JRunArrayElement<T> run = itsRuns->GetElement(runIndex);

	SetElementCount(GetElementCount() - run.length + newLength);

	run.length = newLength;
	run.data   = data;
	itsRuns->SetElement(runIndex, run);
}

#endif

// Instantiate the template for the specified type.

#if defined JTemplateType && ! defined JOnlyWantTemplateDefinition
	#define JTemplateName JRunArray
	#include <instantiate_template.h>
	#undef JTemplateName
	#define JTemplateName JRunArrayElement
	#include <instantiate_template.h>
	#undef JTemplateName
#endif
