/* Copyright (C) 2015 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with 0 A.D. If not, see .
*/
#ifndef INCLUDED_PRIORITYQUEUE
#define INCLUDED_PRIORITYQUEUE
/*
* Priority queues for pathfinder.
* (These probably aren't suitable for more general uses.)
*/
#ifdef NDEBUG
#define PRIORITYQUEUE_DEBUG 0
#else
#define PRIORITYQUEUE_DEBUG 1
#endif
template
struct QueueItemPriority
{
bool operator()(const Item& a, const Item& b) const
{
if (CMP()(b.rank, a.rank)) // higher costs are lower priority
return true;
if (CMP()(a.rank, b.rank))
return false;
// Need to tie-break to get a consistent ordering
if (CMP()(b.h, a.h)) // higher heuristic costs are lower priority
return true;
if (CMP()(a.h, b.h))
return false;
if (a.id < b.id)
return true;
if (b.id < a.id)
return false;
#if PRIORITYQUEUE_DEBUG
debug_warn(L"duplicate tiles in queue");
#endif
return false;
}
};
/**
* Priority queue implemented as a binary heap.
* This is quite dreadfully slow in MSVC's debug STL implementation,
* so we shouldn't use it unless we reimplement the heap functions more efficiently.
*/
template >
class PriorityQueueHeap
{
public:
struct Item
{
ID id;
R rank; // f = g+h (estimated total cost of path through here)
H h; // heuristic cost
};
void push(const Item& item)
{
m_Heap.push_back(item);
push_heap(m_Heap.begin(), m_Heap.end(), QueueItemPriority- ());
}
void promote(ID id, R UNUSED(oldrank), R newrank, H newh)
{
// Loop backwards since it seems a little faster in practice
for (ssize_t n = m_Heap.size() - 1; n >= 0; --n)
{
if (m_Heap[n].id == id)
{
#if PRIORITYQUEUE_DEBUG
ENSURE(m_Heap[n].rank > newrank);
#endif
m_Heap[n].rank = newrank;
m_Heap[n].h = newh;
push_heap(m_Heap.begin(), m_Heap.begin()+n+1, QueueItemPriority
- ());
return;
}
}
}
Item pop()
{
#if PRIORITYQUEUE_DEBUG
ENSURE(m_Heap.size());
#endif
Item r = m_Heap[0];
pop_heap(m_Heap.begin(), m_Heap.end(), QueueItemPriority
- ());
m_Heap.pop_back();
return r;
}
bool empty()
{
return m_Heap.empty();
}
size_t size()
{
return m_Heap.size();
}
void clear()
{
m_Heap.clear();
}
std::vector
- m_Heap;
};
/**
* Priority queue implemented as an unsorted array.
* This means pop() is O(n), but push and promote are O(1), and n is typically small
* (average around 50-100 in some rough tests).
* It seems fractionally slower than a binary heap in optimised builds, but is
* much simpler and less susceptible to MSVC's painfully slow debug STL.
*/
template >
class PriorityQueueList
{
public:
struct Item
{
ID id;
R rank; // f = g+h (estimated total cost of path through here)
H h; // heuristic cost
};
void push(const Item& item)
{
m_List.push_back(item);
}
Item* find(ID id)
{
for (size_t n = 0; n < m_List.size(); ++n)
{
if (m_List[n].id == id)
return &m_List[n];
}
return NULL;
}
void promote(ID id, R UNUSED(oldrank), R newrank, H newh)
{
find(id)->rank = newrank;
find(id)->h = newh;
}
Item pop()
{
#if PRIORITYQUEUE_DEBUG
ENSURE(m_List.size());
#endif
// Loop backwards looking for the best (it's most likely to be one
// we've recently pushed, so going backwards saves a bit of copying)
Item best = m_List.back();
size_t bestidx = m_List.size()-1;
for (ssize_t i = (ssize_t)bestidx-1; i >= 0; --i)
{
if (QueueItemPriority
- ()(best, m_List[i]))
{
bestidx = i;
best = m_List[i];
}
}
// Swap the matched element with the last in the list, then pop the new last
m_List[bestidx] = m_List[m_List.size()-1];
m_List.pop_back();
return best;
}
bool empty()
{
return m_List.empty();
}
size_t size()
{
return m_List.size();
}
void clear()
{
m_List.clear();
}
std::vector
- m_List;
};
#endif // INCLUDED_PRIORITYQUEUE