1 /**********************************************************************
2 Freeciv - Copyright (C) 2002 - The Freeciv Project
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; either version 2, or (at your option)
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12 ***********************************************************************/
14 /* specpqs: "specific priority queues".
16 * This file is used to implement a "specific" priority queues.
17 * That is, a (sometimes) type-checked priority queue. (Or at least a
18 * priority queue with related functions with distinctly typed parameters.)
20 * Before including this file, you must define the following:
21 * SPECPQ_TAG - this tag will be used to form names for functions etc.
22 * SPECPQ_PRIORITY_TYPE - the type for the priority property of the cells.
23 * SPECPQ_DATA_TYPE - the type for the data property of the cells.
25 * Assuming SPECPQ_TAG were 'foo', SPECPQ_PRIORITY_TYPE were 'priority_t',
26 * and SPECPQ_DATA_TYPE were 'data_t'.
27 * including this file would provide a struct definition for:
31 * typedef void (*foo_pq_data_free_fn_t) (data_t);
33 * and prototypes for the following functions:
34 * struct foo_pq *foo_pq_new(int initial_size);
35 * void foo_pq_destroy(struct foo_pq *pq);
36 * void foo_pq_destroy_full(struct foo_pq *pq,
37 * foo_pq_data_free_fn_t data_free);
38 * void foo_pq_insert(struct foo_pq *pq, data_t data,
39 * priority_t priority);
40 * void foo_pq_replace(struct foo_pq *pq, data_t data,
41 * priority_t priority);
42 * bool foo_pq_remove(struct foo_pq *pq, data_t *pdata);
43 * bool foo_pq_peek(const struct foo_pq *pq, data_t *pdata);
44 * bool foo_pq_priority(const struct foo_pq *pq, priority_t *ppriority);
46 * Note this is not protected against multiple inclusions; this is so that
47 * you can have multiple different speclists. For each speclist, this file
48 * should be included _once_, inside a .h file which _is_ itself protected
49 * against multiple inclusions. */
53 #endif /* __cplusplus */
59 #error Must define a SPECPQ_TAG to use this header
61 #ifndef SPECPQ_PRIORITY_TYPE
62 #error Must define a SPECPQ_PRIORITY_TYPE to use this header
64 #ifndef SPECPQ_DATA_TYPE
65 #error Must define a SPECPQ_DATA_TYPE to use this header
68 #define SPECPQ_PASTE_(x, y) x ## y
69 #define SPECPQ_PASTE(x, y) SPECPQ_PASTE_(x, y)
71 #define SPECPQ_PQ struct SPECPQ_PASTE(SPECPQ_TAG, _pq)
72 #define SPECPQ_PQ_ struct SPECPQ_PASTE(SPECPQ_TAG, _pq_private_)
73 #define SPECPQ_CELL_ struct SPECPQ_PASTE(SPECPQ_TAG, _cell_private_)
74 #define SPECPQ_FOO(suffix) SPECPQ_PASTE(SPECPQ_TAG, suffix)
76 /* Dummy type. Actually a SPECPQ_PQ_, and not defined anywhere. */
79 /* Function related typedefs. */
80 typedef void (*SPECPQ_FOO(_pq_data_free_fn_t
)) (SPECPQ_DATA_TYPE
);
85 SPECPQ_DATA_TYPE data
;
86 SPECPQ_PRIORITY_TYPE priority
;
96 /****************************************************************************
98 'initial_size' is the numer of queue items for which memory should be
99 preallocated, that is, the initial size of the item array the queue
100 uses. If you insert more than n items to the queue, another n items
101 will be allocated automatically.
102 ****************************************************************************/
103 static inline SPECPQ_PQ
*SPECPQ_FOO(_pq_new
)(int initial_size
)
105 SPECPQ_PQ_
*pq
= fc_malloc(sizeof(*pq
));
107 pq
->cells
= fc_malloc(sizeof(*pq
->cells
) * initial_size
);
108 pq
->avail
= initial_size
;
109 pq
->step
= initial_size
;
111 return (SPECPQ_PQ
*) pq
;
114 /****************************************************************************
115 Destructor for queue structure.
116 ****************************************************************************/
117 static inline void SPECPQ_FOO(_pq_destroy
)(SPECPQ_PQ
*_pq
)
119 SPECPQ_PQ_
*pq
= (SPECPQ_PQ_
*) _pq
;
125 /****************************************************************************
126 Alternative destructor for queue structure.
127 ****************************************************************************/
129 SPECPQ_FOO(_pq_destroy_full
)(SPECPQ_PQ
*_pq
,
130 SPECPQ_FOO(_pq_data_free_fn_t
) data_free
)
132 SPECPQ_PQ_
*pq
= (SPECPQ_PQ_
*) _pq
;
135 if (data_free
!= NULL
) {
136 for (i
= 1; i
< pq
->size
; i
++) {
137 data_free(pq
->cells
[i
].data
);
144 /****************************************************************************
145 Insert an item into the queue.
146 ****************************************************************************/
147 static inline void SPECPQ_FOO(_pq_insert
)(SPECPQ_PQ
*_pq
,
148 SPECPQ_DATA_TYPE data
,
149 SPECPQ_PRIORITY_TYPE priority
)
151 SPECPQ_PQ_
*pq
= (SPECPQ_PQ_
*) _pq
;
154 /* Allocate more memory if necessary. */
155 if (pq
->size
>= pq
->avail
) {
156 int newsize
= pq
->size
+ pq
->step
;
158 pq
->cells
= fc_realloc(pq
->cells
, sizeof(*pq
->cells
) * newsize
);
164 while (i
> 1 && (j
= i
/ 2) && pq
->cells
[j
].priority
< priority
) {
165 pq
->cells
[i
] = pq
->cells
[j
];
168 pq
->cells
[i
].data
= data
;
169 pq
->cells
[i
].priority
= priority
;
172 /****************************************************************************
173 Set a better priority for datum. Insert if 'data' is not present yet.
174 ****************************************************************************/
175 static inline void SPECPQ_FOO(_pq_replace
)(SPECPQ_PQ
*_pq
,
176 SPECPQ_DATA_TYPE data
,
177 SPECPQ_PRIORITY_TYPE priority
)
179 SPECPQ_PQ_
*pq
= (SPECPQ_PQ_
*) _pq
;
182 /* Lookup for 'data'... */
183 for (i
= pq
->size
- 1; i
>= 1; i
--) {
184 if (pq
->cells
[i
].data
== data
) {
190 /* Not found, insert. */
191 SPECPQ_FOO(_pq_insert
)(_pq
, data
, priority
);
192 } else if (pq
->cells
[i
].priority
< priority
) {
193 /* Found, percolate-up. */
194 while ((j
= i
/ 2) && pq
->cells
[j
].priority
< priority
) {
195 pq
->cells
[i
] = pq
->cells
[j
];
198 pq
->cells
[i
].data
= data
;
199 pq
->cells
[i
].priority
= priority
;
203 /****************************************************************************
204 Remove the highest-ranking item from the queue and store it in 'pdata'.
205 'pdata' may be NULL. Return FALSE iff no item could be removed, because
207 ****************************************************************************/
208 static inline bool SPECPQ_FOO(_pq_remove
)(SPECPQ_PQ
*_pq
,
209 SPECPQ_DATA_TYPE
*pdata
)
211 SPECPQ_PQ_
*pq
= (SPECPQ_PQ_
*) _pq
;
213 SPECPQ_CELL_
*pcelli
, *pcellj
;
214 SPECPQ_DATA_TYPE top
;
221 fc_assert_ret_val(pq
->size
<= pq
->avail
, FALSE
);
222 top
= pq
->cells
[1].data
;
224 tmp
= pq
->cells
[pq
->size
];
227 pcelli
= pq
->cells
+ 1;
230 pcellj
= pq
->cells
+ j
;
231 if (j
< pq
->size
&& pcellj
->priority
< pq
->cells
[j
+ 1].priority
) {
235 if (pcellj
->priority
<= tmp
.priority
) {
249 /****************************************************************************
250 Store the highest-ranking item in dest without removing it. Return FALSE
251 if the queue is empty, in case 'pdata' is not set.
252 ****************************************************************************/
253 static inline bool SPECPQ_FOO(_pq_peek
)(const SPECPQ_PQ
*_pq
,
254 SPECPQ_DATA_TYPE
*pdata
)
256 const SPECPQ_PQ_
*pq
= (SPECPQ_PQ_
*) _pq
;
262 *pdata
= pq
->cells
[1].data
;
266 /****************************************************************************
267 Set the highest priority of the queue in 'datum_priority'. Return FALSE
268 iff the queue is empty.
269 ****************************************************************************/
270 static inline bool SPECPQ_FOO(_pq_priority
)(const SPECPQ_PQ
*_pq
,
271 SPECPQ_PRIORITY_TYPE
*ppriority
)
274 const SPECPQ_PQ_
*pq
= (SPECPQ_PQ_
*) _pq
;
280 *ppriority
= pq
->cells
[1].priority
;
285 #undef SPECPQ_PRIORITY_TYPE
286 #undef SPECPQ_DATA_TYPE
296 #endif /* __cplusplus */