PaStiX Handbook  6.3.2
queue.c
Go to the documentation of this file.
1 /**
2  *
3  * @file queue.c
4  *
5  * PaStiX queue structure.
6  *
7  * @copyright 2004-2023 Bordeaux INP, CNRS (LaBRI UMR 5800), Inria,
8  * Univ. Bordeaux. All rights reserved.
9  *
10  * @version 6.3.2
11  * @author Pascal Henon
12  * @author Mathieu Faverge
13  * @author Pierre Ramet
14  * @author Tony Delarue
15  * @date 2023-07-21
16  *
17  * @addtogroup blend_dev_queue
18  * @{
19  *
20  **/
21 #include <stdio.h>
22 #include "common.h"
23 #include "queue.h"
24 
25 /**
26  *******************************************************************************
27  *
28  * @brief Compare two items of the queue based on the couple (key1, key2).
29  *
30  *******************************************************************************
31  *
32  * @param[in] item1
33  * The first item to compare.
34  *
35  * @param[in] item2
36  * The second item to compare.
37  *
38  *******************************************************************************
39  *
40  * @retval 1 if item1 < item2
41  * @retval 0 otherwise
42  *
43  *******************************************************************************/
44 static inline int
46  const pastix_queue_item_t *item2)
47 {
48  /* if elt1 < elt2 return 1 */
49  /* if elt1 = elt2 return 0 */
50  /* if elt1 > elt2 return 0 */
51 
52  if ( item1->key1 == item2->key1) {
53  return item1->key2 < item2->key2;
54  }
55  else {
56  return item1->key1 < item2->key1;
57  }
58 }
59 
60 /**
61  *******************************************************************************
62  *
63  * @brief Initialize the queue structure with an initial space to store the
64  * elements.
65  *
66  *******************************************************************************
67  *
68  * @param[inout] q
69  * The qallocated pointer to the queue to initialize.
70  *
71  * @param[in] size
72  * The initial size for the queue.
73  *
74  *******************************************************************************
75  *
76  * @retval PASTIX_SUCCESS if success.
77  * @retval PASTIX_ERR_OUTOFMEMORY if malloc failed.
78  *
79  *******************************************************************************/
80 int
82  pastix_int_t size)
83 {
84  q->size = size;
85  q->used = 0;
86  q->lock = PASTIX_ATOMIC_UNLOCKED;
87  if (q->size != 0)
88  {
89  MALLOC_INTERN(q->elttab, size, pastix_queue_item_t);
90  }
91  else
92  {
93  q->elttab = NULL;
94  }
95  return PASTIX_SUCCESS;
96 }
97 
98 /**
99  *******************************************************************************
100  *
101  * @brief Free the structure associated to the queue.
102  *
103  *******************************************************************************
104  *
105  * @param[inout] q
106  * The pointer to the queue to free.
107  *
108  *******************************************************************************/
109 void
111 {
112  if(q->size != 0)
113  {
114  memFree_null(q->elttab);
115  }
116  q->size = 0;
117 }
118 
119 /**
120  *******************************************************************************
121  *
122  * @brief Return the size of the queue.
123  *
124  *******************************************************************************
125  *
126  * @param[in] q
127  * The pointer to the queue.
128  *
129  *******************************************************************************
130  *
131  * @return The size of the queue.
132  *
133  *******************************************************************************/
136 {
137  return q->used;
138 }
139 
140 /**
141  *******************************************************************************
142  *
143  * @brief Reset the number of used element to 0.
144  *
145  *******************************************************************************
146  *
147  * @param[inout] q
148  * The pointer to the queue.
149  *
150  *******************************************************************************/
151 void
153 {
154  q->used = 0;
155 }
156 
157 /**
158  *******************************************************************************
159  *
160  * @brief Insert an element into the sorted queue.
161  *
162  *******************************************************************************
163  *
164  * @param[inout] q
165  * The pointer to the queue.
166  *
167  * @param[in] elt
168  * The element to insert in the queue.
169  *
170  * @param[in] key1
171  * The first key of the element.
172  *
173  * @param[in] key2
174  * The second key of the element.
175  *
176  *******************************************************************************/
177 void
179  pastix_int_t elt,
180  double key1,
181  double key2)
182 {
183  pastix_atomic_lock( &(q->lock) );
184  pastix_int_t i, hi;
185 
186  /* Allocate more space if necessary */
187  if(q->size == q->used)
188  {
189  pastix_queue_item_t *tmp;
190  tmp = q->elttab;
191 
192  assert( (q->size == 0) || (tmp != NULL) );
193 
194  MALLOC_INTERN(q->elttab, q->size*2+1, pastix_queue_item_t);
195  memcpy(q->elttab, tmp, q->size * sizeof(pastix_queue_item_t));
196 
197  q->size = q->size*2 +1;
198  memFree_null(tmp);
199  }
200 
201  q->elttab[q->used].key1 = key1;
202  q->elttab[q->used].key2 = key2;
203  q->elttab[q->used].eltptr = elt;
204  q->used++;
205 
206  i = q->used - 1;
207  hi= (i+1)/2-1;
208 
209  while( (i > 0) &&
211  q->elttab + hi) )
212  {
213  pastix_queue_item_t swap = q->elttab[i];
214 
215  q->elttab[i ] = q->elttab[hi];
216  q->elttab[hi] = swap;
217 
218  i = hi; hi = (i+1)/2-1;
219  }
220  pastix_atomic_unlock( &(q->lock) );
221 }
222 
223 /**
224  *******************************************************************************
225  *
226  * @brief Read the first element of the queue.
227  *
228  *******************************************************************************
229  *
230  * @param[in] q
231  * The pointer to the queue.
232  *
233  *******************************************************************************
234  *
235  * @return The value of the first element sorted by (key1, key2).
236  *
237  *******************************************************************************/
240 {
241  return q->elttab[0].eltptr;
242 }
243 
244 /**
245  *******************************************************************************
246  *
247  * @brief Remove the first element of the queue and return its keys if needed.
248  *
249  *******************************************************************************
250  *
251  * @param[inout] q
252  * The pointer to the queue. On exit, the queue without its head.
253  *
254  * @param[out] key1
255  * If key1 != NULL, stores the associated key1 to the first element on
256  * exit.
257  *
258  * @param[out] key2
259  * If key2 != NULL, stores the associated key2 to the first element on
260  * exit.
261  *
262  *******************************************************************************
263  *
264  * @return The value of the first element sorted by (key1, key2).
265  *
266  *******************************************************************************/
268 pqueuePop2(pastix_queue_t *q, double *key1, double*key2)
269 {
270  pastix_atomic_lock( &(q->lock) );
271  pastix_int_t i, j;
272  pastix_int_t return_elt;
273 
274  if (q->used == 0) {
275  pastix_atomic_unlock( &(q->lock) );
276  pastix_yield();
277  return -1;
278  }
279 
280  return_elt = q->elttab[0].eltptr;
281  if (key1 != NULL) { *key1 = q->elttab[0].key1; }
282  if (key2 != NULL) { *key2 = q->elttab[0].key2; }
283 
284  q->elttab[0] = q->elttab[q->used-1];
285  q->used--;
286 
287  i = 1;
288  while(i <= (q->used/2))
289  {
290  if( (2*i == q->used)
291  || pqueueItemComparison(q->elttab + 2*i-1,
292  q->elttab + 2*i ) ) /*(q->keytab[2*i-1] < q->keytab[2*i]))*/
293  {
294  j = 2*i;
295  }
296  else
297  {
298  j = 2*i+1;
299  }
300  if (!pqueueItemComparison(q->elttab + i-1,
301  q->elttab + j-1)) /*(q->keytab[i-1] >= q->keytab[j-1])*/
302  {
303  pastix_queue_item_t swap;
304 
305  swap = q->elttab[i-1];
306  q->elttab[i-1] = q->elttab[j-1];
307  q->elttab[j-1] = swap;
308 
309  i = j;
310  }
311  else {
312  break;
313  }
314  }
315  pastix_atomic_unlock( &(q->lock) );
316  return return_elt;
317 }
318 
319 /**
320  *******************************************************************************
321  *
322  * @brief Print the queue.
323  *
324  * Print the queue elements for debug. They are not printed in a sorted order,
325  * but in the order they are stored in the queue.
326  *
327  *******************************************************************************
328  *
329  * @param[in] q
330  * The pointer to the queue.
331  *
332  *******************************************************************************/
333 void
335 {
336  pastix_queue_item_t *item = q->elttab;
337  pastix_int_t i;
338 
339  fprintf(stderr, "Queue :\n");
340  for (i = 0; i < q->used; i++, item++) {
341  fprintf(stderr, "(%ld %ld %ld) ",
342  (long)(item->eltptr),
343  (long)(item->key1),
344  (long)(item->key2) );
345  if (i%4 == 3) {
346  fprintf(stderr, "\n");
347  }
348  }
349  fprintf(stderr, "\n");
350 }
351 
352 /**
353  *@}
354  */
BEGIN_C_DECLS typedef int pastix_int_t
Definition: datatypes.h:51
pastix_int_t size
Definition: queue.h:39
pastix_atomic_lock_t lock
Definition: queue.h:42
pastix_int_t eltptr
Definition: queue.h:32
pastix_queue_item_t * elttab
Definition: queue.h:41
volatile pastix_int_t used
Definition: queue.h:40
void pqueuePush2(pastix_queue_t *, pastix_int_t, double, double)
Insert an element into the sorted queue.
Definition: queue.c:178
pastix_int_t pqueueRead(const pastix_queue_t *)
Read the first element of the queue.
Definition: queue.c:239
void pqueueClear(pastix_queue_t *)
Reset the number of used element to 0.
Definition: queue.c:152
void pqueueExit(pastix_queue_t *)
Free the structure associated to the queue.
Definition: queue.c:110
pastix_int_t pqueuePop2(pastix_queue_t *, double *, double *)
Remove the first element of the queue and return its keys if needed.
Definition: queue.c:268
void pqueuePrint(const pastix_queue_t *)
Print the queue.
Definition: queue.c:334
pastix_int_t pqueueSize(const pastix_queue_t *)
Return the size of the queue.
Definition: queue.c:135
int pqueueInit(pastix_queue_t *, pastix_int_t)
Initialize the queue structure with an initial space to store the elements.
Definition: queue.c:81
static int pqueueItemComparison(const pastix_queue_item_t *item1, const pastix_queue_item_t *item2)
Compare two items of the queue based on the couple (key1, key2).
Definition: queue.c:45
Queue item structure.
Definition: queue.h:29
Queue structure.
Definition: queue.h:38
@ PASTIX_SUCCESS
Definition: api.h:367