Pyrogenesis  13997
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
PriorityQueue.h
Go to the documentation of this file.
1 /* Copyright (C) 2010 Wildfire Games.
2  * This file is part of 0 A.D.
3  *
4  * 0 A.D. is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * 0 A.D. is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef INCLUDED_PRIORITYQUEUE
19 #define INCLUDED_PRIORITYQUEUE
20 
21 /*
22  * Priority queues for pathfinder.
23  * (These probably aren't suitable for more general uses.)
24  */
25 
26 #ifdef NDEBUG
27 #define PRIORITYQUEUE_DEBUG 0
28 #else
29 #define PRIORITYQUEUE_DEBUG 1
30 #endif
31 
32 template <typename Item, typename CMP>
34 {
35  bool operator()(const Item& a, const Item& b)
36  {
37  if (CMP()(b.rank, a.rank)) // higher costs are lower priority
38  return true;
39  if (CMP()(a.rank, b.rank))
40  return false;
41  // Need to tie-break to get a consistent ordering
42  // TODO: Should probably tie-break on g or h or something, but don't bother for now
43  if (a.id < b.id)
44  return true;
45  if (b.id < a.id)
46  return false;
47 #if PRIORITYQUEUE_DEBUG
48  debug_warn(L"duplicate tiles in queue");
49 #endif
50  return false;
51  }
52 };
53 
54 
55 /**
56  * Priority queue implemented as a binary heap.
57  * This is quite dreadfully slow in MSVC's debug STL implementation,
58  * so we shouldn't use it unless we reimplement the heap functions more efficiently.
59  */
60 template <typename ID, typename R, typename CMP = std::less<R> >
62 {
63 public:
64  struct Item
65  {
66  ID id;
67  R rank; // f = g+h (estimated total cost of path through here)
68  };
69 
70  void push(const Item& item)
71  {
72  m_Heap.push_back(item);
73  push_heap(m_Heap.begin(), m_Heap.end(), QueueItemPriority<Item, CMP>());
74  }
75 
76  Item* find(ID id)
77  {
78  for (size_t n = 0; n < m_Heap.size(); ++n)
79  {
80  if (m_Heap[n].id == id)
81  return &m_Heap[n];
82  }
83  return NULL;
84  }
85 
86  void promote(ID id, R newrank)
87  {
88  for (size_t n = 0; n < m_Heap.size(); ++n)
89  {
90  if (m_Heap[n].id == id)
91  {
92 #if PRIORITYQUEUE_DEBUG
93  ENSURE(m_Heap[n].rank > newrank);
94 #endif
95  m_Heap[n].rank = newrank;
96  push_heap(m_Heap.begin(), m_Heap.begin()+n+1, QueueItemPriority<Item, CMP>());
97  return;
98  }
99  }
100  }
101 
102  Item pop()
103  {
104 #if PRIORITYQUEUE_DEBUG
105  ENSURE(m_Heap.size());
106 #endif
107  Item r = m_Heap.front();
108  pop_heap(m_Heap.begin(), m_Heap.end(), QueueItemPriority<Item, CMP>());
109  m_Heap.pop_back();
110  return r;
111  }
112 
113  bool empty()
114  {
115  return m_Heap.empty();
116  }
117 
118  size_t size()
119  {
120  return m_Heap.size();
121  }
122 
123  std::vector<Item> m_Heap;
124 };
125 
126 /**
127  * Priority queue implemented as an unsorted array.
128  * This means pop() is O(n), but push and promote are O(1), and n is typically small
129  * (average around 50-100 in some rough tests).
130  * It seems fractionally slower than a binary heap in optimised builds, but is
131  * much simpler and less susceptible to MSVC's painfully slow debug STL.
132  */
133 template <typename ID, typename R, typename CMP = std::less<R> >
135 {
136 public:
137  struct Item
138  {
139  ID id;
140  R rank; // f = g+h (estimated total cost of path through here)
141  };
142 
143  void push(const Item& item)
144  {
145  m_List.push_back(item);
146  }
147 
148  Item* find(ID id)
149  {
150  for (size_t n = 0; n < m_List.size(); ++n)
151  {
152  if (m_List[n].id == id)
153  return &m_List[n];
154  }
155  return NULL;
156  }
157 
158  void promote(ID id, R newrank)
159  {
160  find(id)->rank = newrank;
161  }
162 
164  {
165 #if PRIORITYQUEUE_DEBUG
166  ENSURE(m_List.size());
167 #endif
168  // Loop backwards looking for the best (it's most likely to be one
169  // we've recently pushed, so going backwards saves a bit of copying)
170  Item best = m_List.back();
171  size_t bestidx = m_List.size()-1;
172  for (ssize_t i = (ssize_t)bestidx-1; i >= 0; --i)
173  {
174  if (QueueItemPriority<Item, CMP>()(best, m_List[i]))
175  {
176  bestidx = i;
177  best = m_List[i];
178  }
179  }
180  // Swap the matched element with the last in the list, then pop the new last
181  m_List[bestidx] = m_List[m_List.size()-1];
182  m_List.pop_back();
183  return best;
184  }
185 
186  bool empty()
187  {
188  return m_List.empty();
189  }
190 
191  size_t size()
192  {
193  return m_List.size();
194  }
195 
196  std::vector<Item> m_List;
197 };
198 
199 #endif // INCLUDED_PRIORITYQUEUE
Priority queue implemented as a binary heap.
Definition: PriorityQueue.h:61
void push(const Item &item)
bool operator()(const Item &a, const Item &b)
Definition: PriorityQueue.h:35
std::vector< Item > m_Heap
#define ENSURE(expr)
ensure the expression &lt;expr&gt; evaluates to non-zero.
Definition: debug.h:282
void promote(ID id, R newrank)
Item * find(ID id)
Definition: PriorityQueue.h:76
void promote(ID id, R newrank)
Definition: PriorityQueue.h:86
std::vector< Item > m_List
intptr_t ssize_t
Definition: wposix_types.h:82
Priority queue implemented as an unsorted array.
Item * find(ID id)
#define debug_warn(expr)
display the error dialog with the given text.
Definition: debug.h:324
void push(const Item &item)
Definition: PriorityQueue.h:70
#define CMP(f)