Freeciv21
Develop your civilization from humble roots to a global empire
specpq.h
Go to the documentation of this file.
1 /**************************************************************************
2  Copyright (c) 1996-2020 Freeciv21 and Freeciv contributors. This file is
3  part of Freeciv21. Freeciv21 is free software: you can redistribute it
4  and/or modify it under the terms of the GNU General Public License as
5  published by the Free Software Foundation, either version 3 of the
6  License, or (at your option) any later version. You should have received
7  a copy of the GNU General Public License along with Freeciv21. If not,
8  see https://www.gnu.org/licenses/.
9 **************************************************************************/
10 
11 /* specpqs: "specific priority queues".
12  *
13  * This file is used to implement a "specific" priority queues.
14  * That is, a (sometimes) type-checked priority queue. (Or at least a
15  * priority queue with related functions with distinctly typed parameters.)
16  *
17  * Before including this file, you must define the following:
18  * SPECPQ_TAG - this tag will be used to form names for functions etc.
19  * SPECPQ_PRIORITY_TYPE - the type for the priority property of the cells.
20  * SPECPQ_DATA_TYPE - the type for the data property of the cells.
21  *
22  * Assuming SPECPQ_TAG were 'foo', SPECPQ_PRIORITY_TYPE were 'priority_t',
23  * and SPECPQ_DATA_TYPE were 'data_t'.
24  * including this file would provide a struct definition for:
25  * struct foo_pq;
26  *
27  * function typedefs:
28  * typedef void (*foo_pq_data_free_fn_t) (data_t);
29  *
30  * and prototypes for the following functions:
31  * struct foo_pq *foo_pq_new(int initial_size);
32  * void foo_pq_destroy(struct foo_pq *pq);
33  * void foo_pq_destroy_full(struct foo_pq *pq,
34  * foo_pq_data_free_fn_t data_free);
35  * void foo_pq_insert(struct foo_pq *pq, data_t data,
36  * priority_t priority);
37  * void foo_pq_replace(struct foo_pq *pq, data_t data,
38  * priority_t priority);
39  * bool foo_pq_remove(struct foo_pq *pq, data_t *pdata);
40  * bool foo_pq_peek(const struct foo_pq *pq, data_t *pdata);
41  * bool foo_pq_priority(const struct foo_pq *pq, priority_t *ppriority);
42  *
43  * Note this is not protected against multiple inclusions; this is so that
44  * you can have multiple different speclists. For each speclist, this file
45  * should be included _once_, inside a .h file which _is_ itself protected
46  * against multiple inclusions. */
47 
48 #ifndef SPECPQ_TAG
49 #error Must define a SPECPQ_TAG to use this header
50 #endif
51 #ifndef SPECPQ_PRIORITY_TYPE
52 #error Must define a SPECPQ_PRIORITY_TYPE to use this header
53 #endif
54 #ifndef SPECPQ_DATA_TYPE
55 #error Must define a SPECPQ_DATA_TYPE to use this header
56 #endif
57 
58 #define SPECPQ_PASTE_(x, y) x##y
59 #define SPECPQ_PASTE(x, y) SPECPQ_PASTE_(x, y)
60 
61 #define SPECPQ_PQ struct SPECPQ_PASTE(SPECPQ_TAG, _pq)
62 #define SPECPQ_PQ_ struct SPECPQ_PASTE(SPECPQ_TAG, _pq_private_)
63 #define SPECPQ_CELL_ struct SPECPQ_PASTE(SPECPQ_TAG, _cell_private_)
64 #define SPECPQ_FOO(suffix) SPECPQ_PASTE(SPECPQ_TAG, suffix)
65 
66 // Dummy type. Actually a SPECPQ_PQ_, and not defined anywhere.
68 
69 // Function related typedefs.
70 typedef void (*SPECPQ_FOO(_pq_data_free_fn_t))(SPECPQ_DATA_TYPE);
71 
72 // Private.
74 {
75  SPECPQ_DATA_TYPE data;
77 };
78 
80 {
81  int size;
82  int avail;
83  int step;
85 };
86 
87 /****************************************************************************
88  Build a new queue.
89  'initial_size' is the numer of queue items for which memory should be
90  preallocated, that is, the initial size of the item array the queue
91  uses. If you insert more than n items to the queue, another n items
92  will be allocated automatically.
93 ****************************************************************************/
94 static inline SPECPQ_PQ *SPECPQ_FOO(_pq_new)(int initial_size)
95 {
96  SPECPQ_PQ_ *pq = static_cast<SPECPQ_PQ_ *>(fc_malloc(sizeof(*pq)));
97 
98  pq->cells = static_cast<SPECPQ_CELL_ *>(
99  fc_malloc(sizeof(*pq->cells) * initial_size));
100  pq->avail = initial_size;
101  pq->step = initial_size;
102  pq->size = 1;
103  return reinterpret_cast<SPECPQ_PQ *>(pq);
104 }
105 
106 /****************************************************************************
107  Destructor for queue structure.
108 ****************************************************************************/
109 static inline void SPECPQ_FOO(_pq_destroy)(SPECPQ_PQ *_pq)
110 {
111  SPECPQ_PQ_ *pq = reinterpret_cast<SPECPQ_PQ_ *>(_pq);
112 
113  free(pq->cells);
114  free(pq);
115 }
116 
117 /****************************************************************************
118  Alternative destructor for queue structure.
119 ****************************************************************************/
120 static inline void
122  SPECPQ_FOO(_pq_data_free_fn_t) data_free)
123 {
124  SPECPQ_PQ_ *pq = reinterpret_cast<SPECPQ_PQ_ *>(_pq);
125  int i;
126 
127  if (data_free != nullptr) {
128  for (i = 1; i < pq->size; i++) {
129  data_free(pq->cells[i].data);
130  }
131  }
132  free(pq->cells);
133  free(pq);
134 }
135 
136 /****************************************************************************
137  Insert an item into the queue.
138 ****************************************************************************/
139 static inline void SPECPQ_FOO(_pq_insert)(SPECPQ_PQ *_pq,
140  SPECPQ_DATA_TYPE data,
142 {
143  SPECPQ_PQ_ *pq = reinterpret_cast<SPECPQ_PQ_ *>(_pq);
144  int i, j;
145 
146  // Allocate more memory if necessary.
147  if (pq->size >= pq->avail) {
148  int newsize = pq->size + pq->step;
149 
150  pq->cells = static_cast<SPECPQ_CELL_ *>(
151  fc_realloc(pq->cells, sizeof(*pq->cells) * newsize));
152  pq->avail = newsize;
153  }
154 
155  // Insert item.
156  i = pq->size++;
157  while (i > 1 && (j = i / 2) && pq->cells[j].priority < priority) {
158  pq->cells[i] = pq->cells[j];
159  i = j;
160  }
161  pq->cells[i].data = data;
162  pq->cells[i].priority = priority;
163 }
164 
165 /****************************************************************************
166  Set a better priority for datum. Insert if 'data' is not present yet.
167 ****************************************************************************/
168 static inline void SPECPQ_FOO(_pq_replace)(SPECPQ_PQ *_pq,
169  SPECPQ_DATA_TYPE data,
171 {
172  SPECPQ_PQ_ *pq = reinterpret_cast<SPECPQ_PQ_ *>(_pq);
173  int i, j;
174 
175  // Lookup for 'data'...
176  for (i = pq->size - 1; i >= 1; i--) {
177  if (pq->cells[i].data == data) {
178  break;
179  }
180  }
181 
182  if (i == 0) {
183  // Not found, insert.
184  SPECPQ_FOO(_pq_insert)(_pq, data, priority);
185  } else if (pq->cells[i].priority < priority) {
186  // Found, percolate-up.
187  while ((j = i / 2) && pq->cells[j].priority < priority) {
188  pq->cells[i] = pq->cells[j];
189  i = j;
190  }
191  pq->cells[i].data = data;
192  pq->cells[i].priority = priority;
193  }
194 }
195 
196 /****************************************************************************
197  Remove the highest-ranking item from the queue and store it in 'pdata'.
198  'pdata' may be nullptr. Return FALSE iff no item could be removed, because
199  the queue was empty.
200 ****************************************************************************/
201 static inline bool SPECPQ_FOO(_pq_remove)(SPECPQ_PQ *_pq,
202  SPECPQ_DATA_TYPE *pdata)
203 {
204  SPECPQ_PQ_ *pq = reinterpret_cast<SPECPQ_PQ_ *>(_pq);
205  SPECPQ_CELL_ tmp;
206  SPECPQ_CELL_ *pcelli, *pcellj;
207  SPECPQ_DATA_TYPE top;
208  int i, j, s;
209 
210  if (pq->size == 1) {
211  return false;
212  }
213 
214  fc_assert_ret_val(pq->size <= pq->avail, false);
215  top = pq->cells[1].data;
216  pq->size--;
217  tmp = pq->cells[pq->size];
218  s = pq->size / 2;
219  i = 1;
220  pcelli = pq->cells + 1;
221  while (i <= s) {
222  j = 2 * i;
223  pcellj = pq->cells + j;
224  if (j < pq->size && pcellj->priority < pq->cells[j + 1].priority) {
225  j++;
226  pcellj++;
227  }
228  if (pcellj->priority <= tmp.priority) {
229  break;
230  }
231  *pcelli = *pcellj;
232  i = j;
233  pcelli = pcellj;
234  }
235  *pcelli = tmp;
236  if (pdata) {
237  *pdata = top;
238  }
239  return true;
240 }
241 
242 /****************************************************************************
243  Store the highest-ranking item in dest without removing it. Return FALSE
244  if the queue is empty, in case 'pdata' is not set.
245 ****************************************************************************/
246 static inline bool SPECPQ_FOO(_pq_peek)(const SPECPQ_PQ *_pq,
247  SPECPQ_DATA_TYPE *pdata)
248 {
249  const SPECPQ_PQ_ *pq = (SPECPQ_PQ_ *) _pq;
250 
251  if (pq->size == 1) {
252  return false;
253  }
254 
255  *pdata = pq->cells[1].data;
256  return true;
257 }
258 
259 /****************************************************************************
260  Set the highest priority of the queue in 'datum_priority'. Return FALSE
261  iff the queue is empty.
262 ****************************************************************************/
263 static inline bool SPECPQ_FOO(_pq_priority)(const SPECPQ_PQ *_pq,
264  SPECPQ_PRIORITY_TYPE *ppriority)
265 
266 {
267  const SPECPQ_PQ_ *pq = (SPECPQ_PQ_ *) _pq;
268 
269  if (pq->size == 1) {
270  return false;
271  }
272 
273  *ppriority = pq->cells[1].priority;
274  return true;
275 }
276 
277 #undef SPECPQ_TAG
278 #undef SPECPQ_PRIORITY_TYPE
279 #undef SPECPQ_DATA_TYPE
280 #undef SPECPQ_PASTE_
281 #undef SPECPQ_PASTE
282 #undef SPECPQ_PQ
283 #undef SPECPQ_PQ_
284 #undef SPECPQ_CELL_
285 #undef SPECPQ_FOO
#define fc_assert_ret_val(condition, val)
Definition: log.h:114
#define SPECPQ_PRIORITY_TYPE
#define SPECPQ_DATA_TYPE
#define SPECPQ_FOO(suffix)
Definition: specpq.h:64
static void SPECPQ_FOO() _pq_insert(SPECPQ_PQ *_pq, SPECPQ_DATA_TYPE data, SPECPQ_PRIORITY_TYPE priority)
Definition: specpq.h:139
#define SPECPQ_CELL_
Definition: specpq.h:63
static void SPECPQ_FOO() _pq_replace(SPECPQ_PQ *_pq, SPECPQ_DATA_TYPE data, SPECPQ_PRIORITY_TYPE priority)
Definition: specpq.h:168
static void SPECPQ_FOO() _pq_destroy(SPECPQ_PQ *_pq)
Definition: specpq.h:109
static SPECPQ_PQ *SPECPQ_FOO() _pq_new(int initial_size)
Definition: specpq.h:94
#define SPECPQ_PQ
Definition: specpq.h:61
static bool SPECPQ_FOO() _pq_peek(const SPECPQ_PQ *_pq, SPECPQ_DATA_TYPE *pdata)
Definition: specpq.h:246
SPECPQ_CELL_ * cells
Definition: specpq.h:84
static void SPECPQ_FOO() _pq_destroy_full(SPECPQ_PQ *_pq, SPECPQ_FOO(_pq_data_free_fn_t) data_free)
Definition: specpq.h:121
SPECPQ_PRIORITY_TYPE priority
Definition: specpq.h:76
int avail
Definition: specpq.h:82
int step
Definition: specpq.h:83
#define SPECPQ_PQ_
Definition: specpq.h:62
static bool SPECPQ_FOO() _pq_remove(SPECPQ_PQ *_pq, SPECPQ_DATA_TYPE *pdata)
Definition: specpq.h:201
static bool SPECPQ_FOO() _pq_priority(const SPECPQ_PQ *_pq, SPECPQ_PRIORITY_TYPE *ppriority)
Definition: specpq.h:263
size_t size
Definition: specvec.h:64
#define fc_realloc(ptr, sz)
Definition: support.h:59
#define fc_malloc(sz)
Definition: support.h:58