#region Copyright & License Information
/*
* Copyright (c) The OpenRA Developers and Contributors
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version. For more
* information, see COPYING.
*/
#endregion
using System;
namespace OpenRA.Primitives
{
///
/// A random-access array which keeps track of the minimum item.
///
public sealed class PriorityArray where T : IComparable
{
readonly T[] items;
readonly int[] itemIndexToHeapIndex;
readonly int[] heapOfItemIndices;
///
/// Create a new PriorityArray of given size with all values preset to the given init value.
///
public PriorityArray(int size, T init)
{
items = new T[size];
itemIndexToHeapIndex = new int[size];
heapOfItemIndices = new int[size];
Array.Fill(items, init);
for (var i = 0; i < size; i++)
{
items[i] = init;
itemIndexToHeapIndex[i] = i;
heapOfItemIndices[i] = i;
}
}
public int Length => items.Length;
/// Get the index of the minimum element.
public int GetMinIndex() => heapOfItemIndices[0];
public T this[int itemIndex]
{
get => items[itemIndex];
set
{
items[itemIndex] = value;
Bubble(itemIndexToHeapIndex[itemIndex]);
}
}
void Bubble(int heapIndex)
{
if (!BubbleUp(heapIndex))
{
BubbleDown(heapIndex);
}
}
bool BubbleUp(int heapIndex)
{
if (heapIndex == 0)
return false;
var itemIndex = heapOfItemIndices[heapIndex];
var upHeapIndex = ((heapIndex + 1) >> 1) - 1;
var upItemIndex = heapOfItemIndices[upHeapIndex];
if (items[itemIndex].CompareTo(items[upItemIndex]) >= 0)
return false;
Swap(heapIndex, upHeapIndex, itemIndex, upItemIndex);
BubbleUp(upHeapIndex);
return true;
}
bool BubbleDown(int heapIndex)
{
var itemIndex = heapOfItemIndices[heapIndex];
var leftDownHeapIndex = ((heapIndex + 1) << 1) - 1;
var rightDownHeapIndex = leftDownHeapIndex + 1;
if (leftDownHeapIndex >= Length)
return false;
var item = items[itemIndex];
if (rightDownHeapIndex < Length)
{
var leftDownItemIndex = heapOfItemIndices[leftDownHeapIndex];
var rightDownItemIndex = heapOfItemIndices[rightDownHeapIndex];
var leftDownItem = items[leftDownItemIndex];
var rightDownItem = items[rightDownItemIndex];
if (item.CompareTo(leftDownItem) <= 0 && item.CompareTo(rightDownItem) <= 0)
return false;
if (leftDownItem.CompareTo(rightDownItem) <= 0)
{
Swap(heapIndex, leftDownHeapIndex, itemIndex, leftDownItemIndex);
BubbleDown(leftDownHeapIndex);
}
else
{
Swap(heapIndex, rightDownHeapIndex, itemIndex, rightDownItemIndex);
BubbleDown(rightDownHeapIndex);
}
return true;
}
else
{
// Just the left down one exists.
var leftDownItemIndex = heapOfItemIndices[leftDownHeapIndex];
var leftDownItem = items[leftDownItemIndex];
if (item.CompareTo(leftDownItem) <= 0)
return false;
Swap(heapIndex, leftDownHeapIndex, itemIndex, leftDownItemIndex);
BubbleDown(leftDownHeapIndex);
return true;
}
}
void Swap(int heapIndex1, int heapIndex2, int itemIndex1, int itemIndex2)
{
(itemIndexToHeapIndex[itemIndex1], itemIndexToHeapIndex[itemIndex2]) =
(itemIndexToHeapIndex[itemIndex2], itemIndexToHeapIndex[itemIndex1]);
(heapOfItemIndices[heapIndex1], heapOfItemIndices[heapIndex2]) =
(heapOfItemIndices[heapIndex2], heapOfItemIndices[heapIndex1]);
}
}
}