Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
7572c34e7ad083c650b882d225aee289e79c1e0a
[simgrid.git] / src / xbt / dynar.c
1 /* $Id$ */
2
3 /* a generic DYNamic ARray implementation.                                  */
4
5 /* Copyright (c) 2003, 2004 Martin Quinson. All rights reserved.            */
6
7 /* This program is free software; you can redistribute it and/or modify it
8  * under the terms of the license (GNU LGPL) which comes with this package. */
9
10 #include "portable.h" /* SIZEOF_MAX */
11 #include "xbt/misc.h"
12 #include "xbt/sysdep.h"
13 #include "xbt/log.h"
14 #include "xbt/ex.h"
15 #include "xbt/dynar.h"
16 #include <sys/types.h>
17
18 #include "xbt/dynar_private.h" /* type definition, which we share with the
19                                   code in charge of sending this across the net */
20
21 /* IMPLEMENTATION NOTE ON SYNCHRONIZATION: every functions which name is prefixed by _
22  * assumes that the dynar is already locked if we have to.
23  * Other functions (public ones) check for this.
24  */
25
26 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(xbt_dyn,xbt,"Dynamic arrays");
27
28 static XBT_INLINE void  _dynar_lock(xbt_dynar_t dynar) {
29         if (dynar->mutex)
30                 xbt_mutex_acquire(dynar->mutex);
31 }
32 static XBT_INLINE void  _dynar_unlock(xbt_dynar_t dynar) {
33         if (dynar->mutex)
34                 xbt_mutex_release(dynar->mutex);
35 }
36 static XBT_INLINE void _sanity_check_dynar(xbt_dynar_t dynar) {
37         xbt_assert0(dynar, "dynar is NULL");
38 }
39 static XBT_INLINE void _sanity_check_idx(int idx) {
40         xbt_assert1(idx >= 0, "dynar idx(=%d) < 0", (int) (idx));
41 }
42
43 static XBT_INLINE void _check_inbound_idx(xbt_dynar_t dynar, int idx) {
44         if (idx>=dynar->used) {
45                 _dynar_unlock(dynar);
46                 THROW2(bound_error,idx,
47                                 "dynar is not that long. You asked %d, but it's only %lu long",
48                                 (int) (idx), (unsigned long) dynar->used);
49         }
50 }
51 static XBT_INLINE void _check_sloppy_inbound_idx(xbt_dynar_t dynar, int idx) {
52         if (idx > dynar->used) {
53                 _dynar_unlock(dynar);
54                 THROW2(bound_error,idx,
55                                 "dynar is not that long. You asked %d, but it's only %lu long (could have been equal to it)",
56                                 (int) (idx), (unsigned long) dynar->used);
57         }
58 }
59 static XBT_INLINE void  _check_populated_dynar(xbt_dynar_t dynar) {
60         if (dynar->used == 0) {
61                 _dynar_unlock(dynar);
62                 THROW1(bound_error,0, "dynar %p is empty", dynar);
63         }
64 }
65
66 static void _dynar_map(const xbt_dynar_t  dynar,
67                        void_f_pvoid_t     const op);
68
69 static XBT_INLINE
70 void _xbt_clear_mem(void * const ptr,
71                     const unsigned long length) {
72   memset(ptr, 0, length);
73 }
74
75 static XBT_INLINE
76 void
77 _xbt_dynar_expand(xbt_dynar_t const dynar,
78                   const unsigned long          nb) {
79   const unsigned long old_size    = dynar->size;
80
81   if (nb > old_size) {
82     char * const old_data    = (char *) dynar->data;
83
84     const unsigned long elmsize     = dynar->elmsize;
85     const unsigned long old_length  = old_size*elmsize;
86
87     const unsigned long used        = dynar->used;
88     const unsigned long used_length = used*elmsize;
89
90     const unsigned long new_size    = nb > (2*(old_size+1)) ? nb : (2*(old_size+1));
91     const unsigned long new_length  = new_size*elmsize;
92     char * const new_data    = (char *) xbt_malloc0(elmsize*new_size);
93
94     DEBUG3("expend %p from %lu to %lu elements", (void*)dynar, (unsigned long)old_size, nb);
95
96     if (old_data) {
97       memcpy(new_data, old_data, used_length);
98       _xbt_clear_mem(old_data, old_length);
99       free(old_data);
100     }
101
102     _xbt_clear_mem(new_data + used_length, new_length - used_length);
103
104     dynar->size = new_size;
105     dynar->data = new_data;
106   }
107 }
108
109 static XBT_INLINE
110 void *
111 _xbt_dynar_elm(const xbt_dynar_t  dynar,
112                const unsigned long idx) {
113   char * const data    = (char*) dynar->data;
114   const unsigned long elmsize = dynar->elmsize;
115
116   return data + idx*elmsize;
117 }
118
119 static XBT_INLINE
120 void
121 _xbt_dynar_get_elm(void  * const       dst,
122                    const xbt_dynar_t  dynar,
123                    const unsigned long idx) {
124   void * const elm     = _xbt_dynar_elm(dynar, idx);
125
126   memcpy(dst, elm, dynar->elmsize);
127 }
128
129 static XBT_INLINE
130 void
131 _xbt_dynar_put_elm(const xbt_dynar_t  dynar,
132                    const unsigned long idx,
133                    const void * const  src) {
134   void * const elm     = _xbt_dynar_elm(dynar, idx);
135   const unsigned long elmsize = dynar->elmsize;
136
137   memcpy(elm, src, elmsize);
138 }
139
140 static XBT_INLINE
141 void
142 _xbt_dynar_remove_at(xbt_dynar_t  const dynar,
143                 const unsigned long            idx,
144                 void         * const object) {
145
146         unsigned long nb_shift;
147         unsigned long offset;
148
149         _sanity_check_dynar(dynar);
150         _sanity_check_idx(idx);
151         _check_inbound_idx(dynar, idx);
152
153         if (object) {
154                 _xbt_dynar_get_elm(object, dynar, idx);
155         } else if (dynar->free_f) {
156                 if (dynar->elmsize <= SIZEOF_MAX) {
157                         char elm[SIZEOF_MAX];
158                         _xbt_dynar_get_elm(elm, dynar, idx);
159                         (*dynar->free_f)(elm);
160                 } else {
161                         char *elm=malloc(dynar->elmsize);
162                         _xbt_dynar_get_elm(elm, dynar, idx);
163                         (*dynar->free_f)(elm);
164                         free(elm);
165                 }
166         }
167
168         nb_shift =  dynar->used-1 - idx;
169         offset   =  nb_shift * dynar->elmsize;
170
171         memmove(_xbt_dynar_elm(dynar, idx),
172                         _xbt_dynar_elm(dynar, idx+1),
173                         offset);
174
175         dynar->used--;
176 }
177
178 void
179 xbt_dynar_dump(xbt_dynar_t dynar) {
180         INFO5("Dynar dump: size=%lu; used=%lu; elmsize=%lu; data=%p; free_f=%p",
181         dynar->size, dynar->used, dynar->elmsize, dynar->data, dynar->free_f);
182 }
183
184 /** @brief Constructor
185  *
186  * \param elmsize size of each element in the dynar
187  * \param free_f function to call each time we want to get rid of an element (or NULL if nothing to do).
188  *
189  * Creates a new dynar. If a free_func is provided, the elements have to be
190  * pointer of pointer. That is to say that dynars can contain either base
191  * types (int, char, double, etc) or pointer of pointers (struct **).
192  */
193 xbt_dynar_t
194 xbt_dynar_new(const unsigned long elmsize,
195               void_f_pvoid_t const free_f) {
196
197   xbt_dynar_t dynar = xbt_new0(s_xbt_dynar_t,1);
198
199   dynar->size    = 0;
200   dynar->used    = 0;
201   dynar->elmsize = elmsize;
202   dynar->data    = NULL;
203   dynar->free_f    = free_f;
204   dynar->mutex    = NULL;
205
206   return dynar;
207 }
208
209 /** @brief Creates a synchronized dynar.
210  *
211  * Just like #xbt_dynar_new, but each access to the structure will be protected by a mutex
212  *
213  */
214 xbt_dynar_t
215 xbt_dynar_new_sync(const unsigned long elmsize,
216                    void_f_pvoid_t const free_f) {
217   xbt_dynar_t res = xbt_dynar_new(elmsize,free_f);
218   res->mutex = xbt_mutex_init();
219   return res;
220 }
221
222 /** @brief Destructor of the structure not touching to the content
223  *
224  * \param dynar poor victim
225  *
226  * kilkil a dynar BUT NOT its content. Ie, the array is freed, but the content
227  * is not touched (the \a free_f function is not used)
228  */
229 void
230 xbt_dynar_free_container(xbt_dynar_t *dynar) {
231   if (dynar && *dynar) {
232
233     if ((*dynar)->data) {
234       _xbt_clear_mem((*dynar)->data, (*dynar)->size);
235       free((*dynar)->data);
236     }
237
238     if ((*dynar)->mutex)
239       xbt_mutex_destroy((*dynar)->mutex);
240
241     _xbt_clear_mem(*dynar, sizeof(s_xbt_dynar_t));
242
243     free(*dynar);
244     *dynar=NULL;
245   }
246 }
247
248 /** @brief Frees the content and set the size to 0
249  *
250  * \param dynar who to squeeze
251  */
252 void
253 xbt_dynar_reset(xbt_dynar_t const dynar) {
254   _dynar_lock(dynar);
255
256   _sanity_check_dynar(dynar);
257
258   DEBUG1("Reset the dynar %p",(void*)dynar);
259   if (dynar->free_f) {
260     _dynar_map(dynar, dynar->free_f);
261   }
262   /*
263   if (dynar->data)
264     free(dynar->data);
265
266   dynar->size = 0;
267    */
268   dynar->used = 0;
269
270   _dynar_unlock(dynar);
271
272   /*  dynar->data = NULL;*/
273 }
274
275 /**
276  * \brief Shrink the dynar by removing empty slots at the end of the internal array
277  * \param dynar a dynar
278  * \param empty_slots_wanted number of empty slots you want to keep at the end of the
279  * internal array for further insertions
280  *
281  * Reduces the internal array size of the dynar to the number of elements plus
282  * \a empty_slots_wanted.
283  * After removing elements from the dynar, you can call this function to make
284  * the dynar use less memory.
285  * Set \a empty_slots_wanted to zero to reduce the dynar internal array as much
286  * as possible.
287  * Note that if \a empty_slots_wanted is greater than the array size, the internal
288  * array is not expanded and nothing is done.
289  */
290 void xbt_dynar_shrink(xbt_dynar_t dynar, int empty_slots_wanted) {
291   unsigned long size_wanted;
292
293   _dynar_lock(dynar);
294
295   size_wanted = dynar->used + empty_slots_wanted;
296   if (size_wanted < dynar->size) {
297     dynar->size = size_wanted;
298     dynar->data = xbt_realloc(dynar->data, sizeof(void*) * dynar->size);
299   }
300   _dynar_unlock(dynar);
301 }
302
303 /** @brief Destructor
304  *
305  * \param dynar poor victim
306  *
307  * kilkil a dynar and its content
308  */
309
310 void
311 xbt_dynar_free(xbt_dynar_t * dynar) {
312   if (dynar && *dynar) {
313     xbt_dynar_reset(*dynar);
314     xbt_dynar_free_container(dynar);
315   }
316 }
317 /** \brief free a dynar passed as void* (handy to store dynar in dynars or dict) */
318 void xbt_dynar_free_voidp(void *d) {
319   xbt_dynar_free( (xbt_dynar_t*) d);
320 }
321
322 /** @brief Count of dynar's elements
323  *
324  * \param dynar the dynar we want to mesure
325  */
326 unsigned long
327 xbt_dynar_length(const xbt_dynar_t dynar) {
328   return (dynar ? (unsigned long) dynar->used : (unsigned long)0);
329 }
330
331 /** @brief Retrieve a copy of the Nth element of a dynar.
332  *
333  * \param dynar information dealer
334  * \param idx index of the slot we want to retrieve
335  * \param[out] dst where to put the result to.
336  */
337 void
338 xbt_dynar_get_cpy(const xbt_dynar_t dynar,
339                   const unsigned long         idx,
340                   void       * const dst) {
341   _dynar_lock(dynar);
342   _sanity_check_dynar(dynar);
343   _sanity_check_idx(idx);
344   _check_inbound_idx(dynar, idx);
345
346   _xbt_dynar_get_elm(dst, dynar, idx);
347   _dynar_unlock(dynar);
348 }
349
350 /** @brief Retrieve a pointer to the Nth element of a dynar.
351  *
352  * \param dynar information dealer
353  * \param idx index of the slot we want to retrieve
354  * \return the \a idx-th element of \a dynar.
355  *
356  * \warning The returned value is the actual content of the dynar.
357  * Make a copy before fooling with it.
358  */
359 void*
360 xbt_dynar_get_ptr(const xbt_dynar_t dynar, const unsigned long idx) {
361
362   void *res;
363   _dynar_lock(dynar);
364   _sanity_check_dynar(dynar);
365   _sanity_check_idx(idx);
366   _check_inbound_idx(dynar, idx);
367
368   res = _xbt_dynar_elm(dynar, idx);
369   _dynar_unlock(dynar);
370   return res;
371 }
372
373
374 static void XBT_INLINE /* not synchronized */
375 _xbt_dynar_set(xbt_dynar_t         dynar,
376                const unsigned long   idx,
377                const void   * const src) {
378
379   _sanity_check_dynar(dynar);
380   _sanity_check_idx(idx);
381
382   _xbt_dynar_expand(dynar, idx+1);
383
384   if (idx >= dynar->used) {
385     dynar->used = idx+1;
386   }
387
388   _xbt_dynar_put_elm(dynar, idx, src);
389 }
390
391 /** @brief Set the Nth element of a dynar (expended if needed). Previous value at this position is NOT freed
392  *
393  * \param dynar information dealer
394  * \param idx index of the slot we want to modify
395  * \param src What will be feeded to the dynar
396  *
397  * If you want to free the previous content, use xbt_dynar_replace().
398  */
399 void
400 xbt_dynar_set(xbt_dynar_t         dynar,
401               const int            idx,
402               const void   * const src) {
403
404   _dynar_lock(dynar);
405   _xbt_dynar_set(dynar,idx,src);
406   _dynar_unlock(dynar);
407 }
408
409 /** @brief Set the Nth element of a dynar (expended if needed). Previous value is freed
410  *
411  * \param dynar
412  * \param idx
413  * \param object
414  *
415  * Set the Nth element of a dynar, expanding the dynar if needed, AND DO
416  * free the previous value at this position. If you don't want to free the
417  * previous content, use xbt_dynar_set().
418  */
419 void
420 xbt_dynar_replace(xbt_dynar_t         dynar,
421                   const unsigned long       idx,
422                   const void   * const object) {
423   _dynar_lock(dynar);
424   _sanity_check_dynar(dynar);
425   _sanity_check_idx(idx);
426
427   if (idx < dynar->used && dynar->free_f) {
428     void * const old_object = _xbt_dynar_elm(dynar, idx);
429
430     (*(dynar->free_f))(old_object);
431   }
432
433   _xbt_dynar_set(dynar, idx, object);
434   _dynar_unlock(dynar);
435 }
436
437 static XBT_INLINE void *
438 _xbt_dynar_insert_at_ptr(xbt_dynar_t const dynar,
439                          const unsigned long            idx) {
440   void *res;
441   unsigned long old_used;
442   unsigned long new_used;
443   unsigned long nb_shift;
444
445   _sanity_check_dynar(dynar);
446   _sanity_check_idx(idx);
447   _check_sloppy_inbound_idx(dynar, idx);
448
449   old_used = dynar->used;
450   new_used = old_used + 1;
451
452   _xbt_dynar_expand(dynar, new_used);
453
454   nb_shift =  old_used - idx;
455
456   if (nb_shift)
457     memmove(_xbt_dynar_elm(dynar, idx+1),
458             _xbt_dynar_elm(dynar, idx),
459             nb_shift * dynar->elmsize);
460
461   dynar->used = new_used;
462   res = _xbt_dynar_elm(dynar,idx);
463   return res;
464 }
465
466 /** @brief Make room for a new element, and return a pointer to it
467  *
468  * You can then use regular affectation to set its value instead of relying
469  * on the slow memcpy. This is what xbt_dynar_insert_at_as() does.
470  */
471 void *
472 xbt_dynar_insert_at_ptr(xbt_dynar_t const dynar,
473                         const int            idx) {
474   void *res;
475
476   _dynar_lock(dynar);
477   res = _xbt_dynar_insert_at_ptr(dynar,idx);
478   _dynar_unlock(dynar);
479   return res;
480 }
481
482 /** @brief Set the Nth dynar's element, expending the dynar and sliding the previous values to the right
483  *
484  * Set the Nth element of a dynar, expanding the dynar if needed, and
485  * moving the previously existing value and all subsequent ones to one
486  * position right in the dynar.
487  */
488 void
489 xbt_dynar_insert_at(xbt_dynar_t  const dynar,
490                     const int            idx,
491                     const void   * const src) {
492
493   _dynar_lock(dynar);
494   /* checks done in xbt_dynar_insert_at_ptr */
495   memcpy(_xbt_dynar_insert_at_ptr(dynar,idx),
496          src,
497          dynar->elmsize);
498   _dynar_unlock(dynar);
499 }
500
501 /** @brief Remove the Nth dynar's element, sliding the previous values to the left
502  *
503  * Get the Nth element of a dynar, removing it from the dynar and moving
504  * all subsequent values to one position left in the dynar.
505  *
506  * If the object argument of this function is a non-null pointer, the removed
507  * element is copied to this address. If not, the element is freed using the
508  * free_f function passed at dynar creation.
509  */
510 void
511 xbt_dynar_remove_at(xbt_dynar_t  const dynar,
512                     const int            idx,
513                     void         * const object) {
514
515   _dynar_lock(dynar);
516   _xbt_dynar_remove_at(dynar, idx, object);
517   _dynar_unlock(dynar);
518 }
519
520 /** @brief Returns the position of the element in the dynar
521  *
522  * Raises not_found_error if not found.
523  */
524 int
525 xbt_dynar_search(xbt_dynar_t  const dynar,
526                  void        *const elem) {
527   unsigned long it;
528
529   _dynar_lock(dynar);
530   for (it=0; it< dynar->used; it++)
531     if (!memcmp(_xbt_dynar_elm(dynar, it),elem,dynar->elmsize)) {
532       _dynar_unlock(dynar);
533       return it;
534     }
535
536   _dynar_unlock(dynar);
537   THROW2(not_found_error,0,"Element %p not part of dynar %p",elem,dynar);
538 }
539
540 /** @brief Returns a boolean indicating whether the element is part of the dynar */
541 int
542 xbt_dynar_member(xbt_dynar_t  const dynar,
543                  void        *const elem) {
544
545   xbt_ex_t e;
546
547   TRY {
548     xbt_dynar_search(dynar,elem);
549   } CATCH(e) {
550     if (e.category == not_found_error) {
551       xbt_ex_free(e);
552       return 0;
553     }
554     RETHROW;
555   }
556   return 1;
557 }
558
559 /** @brief Make room at the end of the dynar for a new element, and return a pointer to it.
560  *
561  * You can then use regular affectation to set its value instead of relying
562  * on the slow memcpy. This is what xbt_dynar_push_as() does.
563  */
564 void *
565 xbt_dynar_push_ptr(xbt_dynar_t  const dynar) {
566   void *res;
567
568   /* we have to inline xbt_dynar_insert_at_ptr here to make sure that
569     dynar->used don't change between reading it and getting the lock
570    within xbt_dynar_insert_at_ptr */
571   _dynar_lock(dynar);
572   res = _xbt_dynar_insert_at_ptr(dynar,dynar->used);
573   _dynar_unlock(dynar);
574   return res;
575 }
576
577 /** @brief Add an element at the end of the dynar */
578 void
579 xbt_dynar_push(xbt_dynar_t  const dynar,
580                const void   * const src) {
581   _dynar_lock(dynar);
582   /* checks done in xbt_dynar_insert_at_ptr */
583   memcpy(_xbt_dynar_insert_at_ptr(dynar,dynar->used),
584          src,
585          dynar->elmsize);
586   _dynar_unlock(dynar);
587 }
588
589 /** @brief Mark the last dynar's element as unused and return a pointer to it.
590  *
591  * You can then use regular affectation to set its value instead of relying
592  * on the slow memcpy. This is what xbt_dynar_pop_as() does.
593  */
594 void *
595 xbt_dynar_pop_ptr(xbt_dynar_t  const dynar) {
596   void *res;
597
598   _dynar_lock(dynar);
599   _check_populated_dynar(dynar);
600   DEBUG1("Pop %p",(void*)dynar);
601   dynar->used--;
602   res = _xbt_dynar_elm(dynar,dynar->used);
603   _dynar_unlock(dynar);
604   return res;
605 }
606
607 /** @brief Get and remove the last element of the dynar */
608 void
609 xbt_dynar_pop(xbt_dynar_t  const dynar,
610               void         * const dst) {
611
612   /* sanity checks done by remove_at */
613   DEBUG1("Pop %p",(void*)dynar);
614   _dynar_lock(dynar);
615   _xbt_dynar_remove_at(dynar, dynar->used-1, dst);
616   _dynar_unlock(dynar);
617 }
618
619 /** @brief Add an element at the begining of the dynar.
620  *
621  * This is less efficient than xbt_dynar_push()
622  */
623 void
624 xbt_dynar_unshift(xbt_dynar_t  const dynar,
625                   const void   * const src) {
626
627   /* sanity checks done by insert_at */
628   xbt_dynar_insert_at(dynar, 0, src);
629 }
630
631 /** @brief Get and remove the first element of the dynar.
632  *
633  * This is less efficient than xbt_dynar_pop()
634  */
635 void
636 xbt_dynar_shift(xbt_dynar_t  const dynar,
637                 void         * const dst) {
638
639   /* sanity checks done by remove_at */
640   xbt_dynar_remove_at(dynar, 0, dst);
641 }
642
643 static void _dynar_map(const xbt_dynar_t  dynar,
644                        void_f_pvoid_t     const op) {
645   char         elm[SIZEOF_MAX];
646   const unsigned long used = dynar->used;
647   unsigned long       i    = 0;
648
649   for (i = 0; i < used; i++) {
650     _xbt_dynar_get_elm(elm, dynar, i);
651     (*op)(elm);
652   }
653 }
654
655 /** @brief Apply a function to each member of a dynar
656  *
657  * The mapped function may change the value of the element itself,
658  * but should not mess with the structure of the dynar.
659  *
660  * If the dynar is synchronized, it is locked during the whole map
661  * operation, so make sure your function don't call any function
662  * from xbt_dynar_* on it, or you'll get a deadlock.
663  */
664 void
665 xbt_dynar_map(const xbt_dynar_t  dynar,
666               void_f_pvoid_t     const op) {
667
668   _dynar_lock(dynar);
669   _sanity_check_dynar(dynar);
670
671   _dynar_map(dynar,op);
672
673   _dynar_unlock(dynar);
674 }
675
676 /** @brief Put the cursor at the begining of the dynar.
677  *
678  * Actually, the cursor is set one step before the begining, so that you
679  * can iterate over the dynar with a for loop.
680  *
681  * @warning Do not call this function directly, but only through xbt_dynar_foreach.
682  */
683 void
684 _xbt_dynar_cursor_first(const xbt_dynar_t dynar,
685                         unsigned int * const cursor) {
686
687   _dynar_lock(dynar);
688   DEBUG1("Set cursor on %p to the first position",(void*)dynar);
689   *cursor = 0;
690 }
691
692 /** @brief Move the cursor to the next value
693  *
694  * @warning Do not call this function directly, but only through xbt_dynar_foreach.
695  */
696 void
697 _xbt_dynar_cursor_step(const xbt_dynar_t dynar,
698                        unsigned int * const cursor) {
699
700   (*cursor)++;
701 }
702
703 /** @brief Get the data currently pointed by the cursor
704  *
705  * @warning Do not call this function directly, but only through xbt_dynar_foreach.
706  */
707 int
708 _xbt_dynar_cursor_get(const xbt_dynar_t dynar,
709                       unsigned int  * const cursor,
710                       void               * const dst) {
711
712   _sanity_check_dynar(dynar);
713   {
714
715     const unsigned long idx = *cursor;
716
717     if (idx >= dynar->used) {
718       DEBUG1("Cursor on %p already on last elem",(void*)dynar);
719       _dynar_unlock(dynar);
720       return FALSE;
721     }
722     DEBUG2("Cash out cursor on %p at %lu",(void*)dynar,idx);
723
724     _xbt_dynar_get_elm(dst, dynar, idx);
725   }
726   return TRUE;
727
728 }
729
730 /** @brief Removes and free the entry pointed by the cursor
731  *
732  * This function can be used while traversing without problem.
733  */
734 void xbt_dynar_cursor_rm(xbt_dynar_t dynar,
735                          unsigned int * const cursor) {
736
737   _xbt_dynar_remove_at(dynar,(*cursor)--,NULL);
738 }
739
740 /** @brief Unlocks a synchronized dynar when you want to break the traversal
741  *
742  * This function must be used if you <tt>break</tt> the
743  * xbt_dynar_foreach loop, but shouldn't be called at the end of a
744  * regular traversal reaching the end of the elements
745  */
746 void xbt_dynar_cursor_unlock(xbt_dynar_t dynar) {
747   _dynar_unlock(dynar);
748 }
749
750 #ifdef SIMGRID_TEST
751
752 #define NB_ELEM 5000
753
754 XBT_TEST_SUITE("dynar","Dynar data container");
755 XBT_LOG_EXTERNAL_CATEGORY(xbt_dyn);
756 XBT_LOG_DEFAULT_CATEGORY(xbt_dyn);
757
758 XBT_TEST_UNIT("int",test_dynar_int,"Dynars of integers") {
759   /* Vars_decl [doxygen cruft] */
760   xbt_dynar_t d;
761   int i,cpt;
762   unsigned int cursor;
763   int *iptr;
764
765   xbt_test_add0("==== Traverse the empty dynar");
766   d=xbt_dynar_new(sizeof(int),NULL);
767   xbt_dynar_foreach(d,cursor,i){
768     xbt_assert0(0,"Damnit, there is something in the empty dynar");
769   }
770   xbt_dynar_free(&d);
771   xbt_dynar_free(&d);
772
773   xbt_test_add1("==== Push %d int, set them again 3 times, traverse them, shift them",
774                 NB_ELEM);
775   /* Populate_ints [doxygen cruft] */
776   /* 1. Populate the dynar */
777   d=xbt_dynar_new(sizeof(int),NULL);
778   for (cpt=0; cpt< NB_ELEM; cpt++) {
779     xbt_dynar_push_as(d,int,cpt); /* This is faster (and possible only with scalars) */
780     /* xbt_dynar_push(d,&cpt);       This would also work */
781     xbt_test_log2("Push %d, length=%lu",cpt, xbt_dynar_length(d));
782   }
783
784   /* 2. Traverse manually the dynar */
785   for (cursor=0; cursor< NB_ELEM; cursor++) {
786     iptr=xbt_dynar_get_ptr(d,cursor);
787     xbt_test_assert2(cursor == *iptr,
788                      "The retrieved value is not the same than the injected one (%d!=%d)",
789                      cursor,cpt);
790   }
791
792   /* 3. Traverse the dynar using the neat macro to that extend */
793   xbt_dynar_foreach(d,cursor,cpt){
794     xbt_test_assert2(cursor == cpt,
795                      "The retrieved value is not the same than the injected one (%d!=%d)",
796                      cursor,cpt);
797   }
798   /* end_of_traversal */
799
800   for (cpt=0; cpt< NB_ELEM; cpt++)
801     *(int*)xbt_dynar_get_ptr(d,cpt) = cpt;
802
803   for (cpt=0; cpt< NB_ELEM; cpt++)
804     *(int*)xbt_dynar_get_ptr(d,cpt) = cpt;
805   /*     xbt_dynar_set(d,cpt,&cpt);*/
806
807   for (cpt=0; cpt< NB_ELEM; cpt++)
808     *(int*)xbt_dynar_get_ptr(d,cpt) = cpt;
809
810   cpt=0;
811   xbt_dynar_foreach(d,cursor,i){
812     xbt_test_assert2(i == cpt,
813                      "The retrieved value is not the same than the injected one (%d!=%d)",
814                      i,cpt);
815     cpt++;
816   }
817   xbt_test_assert2(cpt == NB_ELEM,
818                    "Cannot retrieve my %d values. Last got one is %d",
819                    NB_ELEM, cpt);
820
821   /* shifting [doxygen cruft] */
822   /* 4. Shift all the values */
823   for (cpt=0; cpt< NB_ELEM; cpt++) {
824     xbt_dynar_shift(d,&i);
825     xbt_test_assert2(i == cpt,
826                      "The retrieved value is not the same than the injected one (%d!=%d)",
827                      i,cpt);
828     xbt_test_log2("Pop %d, length=%lu",cpt, xbt_dynar_length(d));
829   }
830
831   /* 5. Free the resources */
832   xbt_dynar_free(&d);
833   xbt_dynar_free(&d);
834
835
836   xbt_test_add1("==== Unshift/pop %d int",NB_ELEM);
837   d=xbt_dynar_new(sizeof(int),NULL);
838   for (cpt=0; cpt< NB_ELEM; cpt++) {
839     xbt_dynar_unshift(d,&cpt);
840     DEBUG2("Push %d, length=%lu",cpt, xbt_dynar_length(d));
841   }
842   for (cpt=0; cpt< NB_ELEM; cpt++) {
843     i=xbt_dynar_pop_as(d,int);
844     xbt_test_assert2(i == cpt,
845                      "The retrieved value is not the same than the injected one (%d!=%d)",
846                      i,cpt);
847     xbt_test_log2("Pop %d, length=%lu",cpt, xbt_dynar_length(d));
848   }
849   xbt_dynar_free(&d);
850   xbt_dynar_free(&d);
851
852
853   xbt_test_add1("==== Push %d int, insert 1000 int in the middle, shift everything",NB_ELEM);
854   d=xbt_dynar_new(sizeof(int),NULL);
855   for (cpt=0; cpt< NB_ELEM; cpt++) {
856     xbt_dynar_push_as(d,int,cpt);
857     DEBUG2("Push %d, length=%lu",cpt, xbt_dynar_length(d));
858   }
859   for (cpt=0; cpt< 1000; cpt++) {
860     xbt_dynar_insert_at_as(d,2500,int,cpt);
861     DEBUG2("Push %d, length=%lu",cpt, xbt_dynar_length(d));
862   }
863
864   for (cpt=0; cpt< 2500; cpt++) {
865     xbt_dynar_shift(d,&i);
866     xbt_test_assert2(i == cpt,
867                      "The retrieved value is not the same than the injected one at the begining (%d!=%d)",
868                      i,cpt);
869     DEBUG2("Pop %d, length=%lu",cpt, xbt_dynar_length(d));
870   }
871   for (cpt=999; cpt>=0; cpt--) {
872     xbt_dynar_shift(d,&i);
873     xbt_test_assert2(i == cpt,
874                      "The retrieved value is not the same than the injected one in the middle (%d!=%d)",
875                      i,cpt);
876   }
877   for (cpt=2500; cpt< NB_ELEM; cpt++) {
878     xbt_dynar_shift(d,&i);
879     xbt_test_assert2(i == cpt,
880                      "The retrieved value is not the same than the injected one at the end (%d!=%d)",
881                      i,cpt);
882   }
883   xbt_dynar_free(&d);
884   xbt_dynar_free(&d);
885
886
887   xbt_test_add1("==== Push %d int, remove 2000-4000. free the rest",NB_ELEM);
888   d=xbt_dynar_new(sizeof(int),NULL);
889   for (cpt=0; cpt< NB_ELEM; cpt++)
890     xbt_dynar_push_as(d,int,cpt);
891
892   for (cpt=2000; cpt< 4000; cpt++) {
893     xbt_dynar_remove_at(d,2000,&i);
894     xbt_test_assert2(i == cpt,
895                      "Remove a bad value. Got %d, expected %d",
896                      i,cpt);
897     DEBUG2("remove %d, length=%lu",cpt, xbt_dynar_length(d));
898   }
899   xbt_dynar_free(&d);
900   xbt_dynar_free(&d);
901 }
902 /*******************************************************************************/
903 /*******************************************************************************/
904 /*******************************************************************************/
905 XBT_TEST_UNIT("double",test_dynar_double,"Dynars of doubles") {
906   xbt_dynar_t d;
907   int cpt;
908   unsigned int cursor;
909   double d1,d2;
910
911   xbt_test_add0("==== Traverse the empty dynar");
912   d=xbt_dynar_new(sizeof(int),NULL);
913   xbt_dynar_foreach(d,cursor,cpt){
914     xbt_test_assert0(FALSE,
915                      "Damnit, there is something in the empty dynar");
916   }
917   xbt_dynar_free(&d);
918   xbt_dynar_free(&d);
919
920   xbt_test_add0("==== Push/shift 5000 doubles");
921   d=xbt_dynar_new(sizeof(double),NULL);
922   for (cpt=0; cpt< 5000; cpt++) {
923     d1=(double)cpt;
924     xbt_dynar_push(d,&d1);
925   }
926   xbt_dynar_foreach(d,cursor,d2){
927     d1=(double)cursor;
928     xbt_test_assert2(d1 == d2,
929                      "The retrieved value is not the same than the injected one (%f!=%f)",
930                      d1,d2);
931   }
932   for (cpt=0; cpt< 5000; cpt++) {
933     d1=(double)cpt;
934     xbt_dynar_shift(d,&d2);
935     xbt_test_assert2(d1 == d2,
936                      "The retrieved value is not the same than the injected one (%f!=%f)",
937                      d1,d2);
938   }
939   xbt_dynar_free(&d);
940   xbt_dynar_free(&d);
941
942
943   xbt_test_add0("==== Unshift/pop 5000 doubles");
944   d=xbt_dynar_new(sizeof(double),NULL);
945   for (cpt=0; cpt< 5000; cpt++) {
946     d1=(double)cpt;
947     xbt_dynar_unshift(d,&d1);
948   }
949   for (cpt=0; cpt< 5000; cpt++) {
950     d1=(double)cpt;
951     xbt_dynar_pop(d,&d2);
952     xbt_test_assert2 (d1 == d2,
953                       "The retrieved value is not the same than the injected one (%f!=%f)",
954                       d1,d2);
955   }
956   xbt_dynar_free(&d);
957   xbt_dynar_free(&d);
958
959
960
961   xbt_test_add0("==== Push 5000 doubles, insert 1000 doubles in the middle, shift everything");
962   d=xbt_dynar_new(sizeof(double),NULL);
963   for (cpt=0; cpt< 5000; cpt++) {
964     d1=(double)cpt;
965     xbt_dynar_push(d,&d1);
966   }
967   for (cpt=0; cpt< 1000; cpt++) {
968     d1=(double)cpt;
969     xbt_dynar_insert_at(d,2500,&d1);
970   }
971
972   for (cpt=0; cpt< 2500; cpt++) {
973     d1=(double)cpt;
974     xbt_dynar_shift(d,&d2);
975     xbt_test_assert2(d1 == d2,
976                      "The retrieved value is not the same than the injected one at the begining (%f!=%f)",
977                      d1,d2);
978     DEBUG2("Pop %d, length=%lu",cpt, xbt_dynar_length(d));
979   }
980   for (cpt=999; cpt>=0; cpt--) {
981     d1=(double)cpt;
982     xbt_dynar_shift(d,&d2);
983     xbt_test_assert2 (d1 == d2,
984                       "The retrieved value is not the same than the injected one in the middle (%f!=%f)",
985                       d1,d2);
986   }
987   for (cpt=2500; cpt< 5000; cpt++) {
988     d1=(double)cpt;
989     xbt_dynar_shift(d,&d2);
990     xbt_test_assert2 (d1 == d2,
991                       "The retrieved value is not the same than the injected one at the end (%f!=%f)",
992                       d1,d2);
993   }
994   xbt_dynar_free(&d);
995   xbt_dynar_free(&d);
996
997
998   xbt_test_add0("==== Push 5000 double, remove 2000-4000. free the rest");
999   d=xbt_dynar_new(sizeof(double),NULL);
1000   for (cpt=0; cpt< 5000; cpt++) {
1001     d1=(double)cpt;
1002     xbt_dynar_push(d,&d1);
1003   }
1004   for (cpt=2000; cpt< 4000; cpt++) {
1005     d1=(double)cpt;
1006     xbt_dynar_remove_at(d,2000,&d2);
1007     xbt_test_assert2 (d1 == d2,
1008                       "Remove a bad value. Got %f, expected %f",
1009                       d2,d1);
1010   }
1011   xbt_dynar_free(&d);
1012   xbt_dynar_free(&d);
1013 }
1014
1015
1016 /* doxygen_string_cruft */
1017
1018 /*******************************************************************************/
1019 /*******************************************************************************/
1020 /*******************************************************************************/
1021 XBT_TEST_UNIT("string",test_dynar_string,"Dynars of strings") {
1022   xbt_dynar_t d;
1023   int cpt;
1024   unsigned int iter;
1025   char buf[1024];
1026   char *s1,*s2;
1027
1028   xbt_test_add0("==== Traverse the empty dynar");
1029   d=xbt_dynar_new(sizeof(char *),&xbt_free_ref);
1030   xbt_dynar_foreach(d,iter,s1){
1031     xbt_test_assert0(FALSE,
1032                      "Damnit, there is something in the empty dynar");
1033   }
1034   xbt_dynar_free(&d);
1035   xbt_dynar_free(&d);
1036
1037   xbt_test_add1("==== Push %d strings, set them again 3 times, shift them",NB_ELEM);
1038   /* Populate_str [doxygen cruft] */
1039   d=xbt_dynar_new(sizeof(char*),&xbt_free_ref);
1040   /* 1. Populate the dynar */
1041   for (cpt=0; cpt< NB_ELEM; cpt++) {
1042     sprintf(buf,"%d",cpt);
1043     s1=strdup(buf);
1044     xbt_dynar_push(d,&s1);
1045   }
1046   for (cpt=0; cpt< NB_ELEM; cpt++) {
1047     sprintf(buf,"%d",cpt);
1048     s1=strdup(buf);
1049     xbt_dynar_replace(d,cpt,&s1);
1050   }
1051   for (cpt=0; cpt< NB_ELEM; cpt++) {
1052     sprintf(buf,"%d",cpt);
1053     s1=strdup(buf);
1054     xbt_dynar_replace(d,cpt,&s1);
1055   }
1056   for (cpt=0; cpt< NB_ELEM; cpt++) {
1057     sprintf(buf,"%d",cpt);
1058     s1=strdup(buf);
1059     xbt_dynar_replace(d,cpt,&s1);
1060   }
1061   for (cpt=0; cpt< NB_ELEM; cpt++) {
1062     sprintf(buf,"%d",cpt);
1063     xbt_dynar_shift(d,&s2);
1064     xbt_test_assert2 (!strcmp(buf,s2),
1065                       "The retrieved value is not the same than the injected one (%s!=%s)",
1066                       buf,s2);
1067     free(s2);
1068   }
1069   xbt_dynar_free(&d);
1070   xbt_dynar_free(&d);
1071
1072
1073   xbt_test_add1("==== Unshift, traverse and pop %d strings",NB_ELEM);
1074   d=xbt_dynar_new(sizeof(char**),&xbt_free_ref);
1075   for (cpt=0; cpt< NB_ELEM; cpt++) {
1076     sprintf(buf,"%d",cpt);
1077     s1=strdup(buf);
1078     xbt_dynar_unshift(d,&s1);
1079   }
1080   /* 2. Traverse the dynar with the macro */
1081   xbt_dynar_foreach(d,iter,s1) {
1082     sprintf(buf,"%d",NB_ELEM - iter -1);
1083     xbt_test_assert2 (!strcmp(buf,s1),
1084                       "The retrieved value is not the same than the injected one (%s!=%s)",
1085                       buf,s1);
1086   }
1087   /* 3. Traverse the dynar with the macro */
1088   for (cpt=0; cpt< NB_ELEM; cpt++) {
1089     sprintf(buf,"%d",cpt);
1090     xbt_dynar_pop(d,&s2);
1091     xbt_test_assert2 (!strcmp(buf,s2),
1092                       "The retrieved value is not the same than the injected one (%s!=%s)",
1093                       buf,s2);
1094     free(s2);
1095   }
1096   /* 4. Free the resources */
1097   xbt_dynar_free(&d);
1098   xbt_dynar_free(&d);
1099
1100
1101   xbt_test_add2("==== Push %d strings, insert %d strings in the middle, shift everything",NB_ELEM,NB_ELEM/5);
1102   d=xbt_dynar_new(sizeof(char*),&xbt_free_ref);
1103   for (cpt=0; cpt< NB_ELEM; cpt++) {
1104     sprintf(buf,"%d",cpt);
1105     s1=strdup(buf);
1106     xbt_dynar_push(d,&s1);
1107   }
1108   for (cpt=0; cpt< NB_ELEM/5; cpt++) {
1109     sprintf(buf,"%d",cpt);
1110     s1=strdup(buf);
1111     xbt_dynar_insert_at(d,NB_ELEM/2,&s1);
1112   }
1113
1114   for (cpt=0; cpt< NB_ELEM/2; cpt++) {
1115     sprintf(buf,"%d",cpt);
1116     xbt_dynar_shift(d,&s2);
1117     xbt_test_assert2(!strcmp(buf,s2),
1118                      "The retrieved value is not the same than the injected one at the begining (%s!=%s)",
1119                      buf,s2);
1120     free(s2);
1121   }
1122   for (cpt=(NB_ELEM/5)-1; cpt>=0; cpt--) {
1123     sprintf(buf,"%d",cpt);
1124     xbt_dynar_shift(d,&s2);
1125     xbt_test_assert2 (!strcmp(buf,s2),
1126                       "The retrieved value is not the same than the injected one in the middle (%s!=%s)",
1127                       buf,s2);
1128     free(s2);
1129   }
1130   for (cpt=NB_ELEM/2; cpt< NB_ELEM; cpt++) {
1131     sprintf(buf,"%d",cpt);
1132     xbt_dynar_shift(d,&s2);
1133     xbt_test_assert2 (!strcmp(buf,s2),
1134                       "The retrieved value is not the same than the injected one at the end (%s!=%s)",
1135                       buf,s2);
1136     free(s2);
1137   }
1138   xbt_dynar_free(&d);
1139   xbt_dynar_free(&d);
1140
1141
1142   xbt_test_add3("==== Push %d strings, remove %d-%d. free the rest",NB_ELEM,2*(NB_ELEM/5),4*(NB_ELEM/5));
1143   d=xbt_dynar_new(sizeof(char*),&xbt_free_ref);
1144   for (cpt=0; cpt< NB_ELEM; cpt++) {
1145     sprintf(buf,"%d",cpt);
1146     s1=strdup(buf);
1147     xbt_dynar_push(d,&s1);
1148   }
1149   for (cpt=2*(NB_ELEM/5); cpt< 4*(NB_ELEM/5); cpt++) {
1150     sprintf(buf,"%d",cpt);
1151     xbt_dynar_remove_at(d,2*(NB_ELEM/5),&s2);
1152     xbt_test_assert2(!strcmp(buf,s2),
1153                      "Remove a bad value. Got %s, expected %s",
1154                      s2,buf);
1155     free(s2);
1156   }
1157   xbt_dynar_free(&d); /* end_of_doxygen */
1158 }
1159
1160
1161 /*******************************************************************************/
1162 /*******************************************************************************/
1163 /*******************************************************************************/
1164 #include "xbt/synchro.h"
1165 static void pusher_f(void *a) {
1166   xbt_dynar_t d=(xbt_dynar_t)a;
1167   int i;
1168   for (i=0; i<500; i++) {
1169     xbt_dynar_push(d,&i);
1170   }
1171 }
1172 static void poper_f(void *a) {
1173   xbt_dynar_t d=(xbt_dynar_t)a;
1174   int i;
1175   int data;
1176   xbt_ex_t e;
1177
1178   for (i=0; i<500; i++) {
1179     TRY {
1180       xbt_dynar_pop(d,&data);
1181     } CATCH(e) {
1182       if (e.category == bound_error) {
1183         xbt_ex_free(e);
1184         i--;
1185       } else {
1186         RETHROW;
1187       }
1188     }
1189   }
1190 }
1191
1192
1193 XBT_TEST_UNIT("synchronized int",test_dynar_sync_int,"Synchronized dynars of integers") {
1194   /* Vars_decl [doxygen cruft] */
1195   xbt_dynar_t d;
1196   xbt_thread_t pusher,poper;
1197
1198   xbt_test_add0("==== Have a pusher and a popper on the dynar");
1199   d=xbt_dynar_new_sync(sizeof(int),NULL);
1200   pusher = xbt_thread_create("pusher",pusher_f,d);
1201   poper = xbt_thread_create("poper",poper_f,d);
1202   xbt_thread_join(pusher);
1203   xbt_thread_join(poper);
1204   xbt_dynar_free(&d);
1205 }
1206
1207 #endif /* SIMGRID_TEST */