1 /* a generic DYNamic ARray implementation. */
3 /* Copyright (c) 2004-2019. The SimGrid Team. All rights reserved. */
5 /* This program is free software; you can redistribute it and/or modify it
6 * under the terms of the license (GNU LGPL) which comes with this package. */
8 #include "simgrid/Exception.hpp"
13 #include "xbt/sysdep.h"
14 #include <sys/types.h>
16 #include "src/include/catch.hpp"
20 TEST_CASE("xbt::dynar: generic C vector", "dynar")
23 SECTION("Dynars of integers")
25 /* Vars_decl [doxygen cruft] */
29 INFO("==== Traverse the empty dynar");
30 xbt_dynar_t d = xbt_dynar_new(sizeof(int), nullptr);
31 xbt_dynar_foreach (d, cursor, i) {
32 xbt_die("Damnit, there is something in the empty dynar");
34 xbt_dynar_free(&d); /* This code is used both as example and as regression test, so we try to */
35 xbt_dynar_free(&d); /* free the struct twice here to check that it's ok, but freeing it only once */
36 /* in your code is naturally the way to go outside a regression test */
38 INFO("==== Push " << NB_ELEM << " int, set them again 3 times, traverse them, shift them");
39 /* Populate_ints [doxygen cruft] */
40 /* 1. Populate the dynar */
41 d = xbt_dynar_new(sizeof(int), nullptr);
42 for (int cpt = 0; cpt < NB_ELEM; cpt++) {
43 xbt_dynar_push_as(d, int, cpt); /* This is faster (and possible only with scalars) */
44 /* xbt_dynar_push(d,&cpt); This would also work */
47 /* 2. Traverse manually the dynar */
48 for (cursor = 0; cursor < NB_ELEM; cursor++) {
49 int* iptr = (int*)xbt_dynar_get_ptr(d, cursor);
50 REQUIRE(cursor == (unsigned int)*iptr); // The retrieved value is not the same than the injected one
53 /* 3. Traverse the dynar using the neat macro to that extend */
55 xbt_dynar_foreach (d, cursor, cpt) {
56 REQUIRE(cursor == (unsigned int)cpt); // The retrieved value is not the same than the injected one
58 /* end_of_traversal */
60 for (int cpt = 0; cpt < NB_ELEM; cpt++)
61 *(int*)xbt_dynar_get_ptr(d, cpt) = cpt;
63 for (int cpt = 0; cpt < NB_ELEM; cpt++)
64 *(int*)xbt_dynar_get_ptr(d, cpt) = cpt;
66 for (int cpt = 0; cpt < NB_ELEM; cpt++)
67 *(int*)xbt_dynar_get_ptr(d, cpt) = cpt;
70 xbt_dynar_foreach (d, cursor, i) {
71 REQUIRE(i == cpt); // The retrieved value is not the same than the injected one
74 REQUIRE(cpt == NB_ELEM); // Cannot retrieve all my values. cpt is the last one I got
76 /* shifting [doxygen cruft] */
77 /* 4. Shift all the values */
78 for (int cpt = 0; cpt < NB_ELEM; cpt++) {
79 xbt_dynar_shift(d, &i);
80 REQUIRE(i == cpt); // The retrieved value is not the same than the injected one
82 REQUIRE(xbt_dynar_is_empty(d));
84 for (int cpt = 0; cpt < NB_ELEM; cpt++) {
85 xbt_dynar_push_as(d, int, -1);
88 xbt_dynar_foreach_ptr(d, cursor, pi) { *pi = 0; }
89 xbt_dynar_foreach (d, cursor, i) {
90 REQUIRE(i == 0); // The value is not the same as the expected one.
92 xbt_dynar_foreach_ptr(d, cursor, pi) { *pi = 1; }
93 xbt_dynar_foreach (d, cursor, i) {
94 REQUIRE(i == 1); // The value is not the same as the expected one
97 /* 5. Free the resources */
98 xbt_dynar_free(&d); /* This code is used both as example and as regression test, so we try to */
99 xbt_dynar_free(&d); /* free the struct twice here to check that it's ok, but freeing it only once */
100 /* in your code is naturally the way to go outside a regression test */
102 INFO("==== Unshift/pop " << NB_ELEM << " int");
103 d = xbt_dynar_new(sizeof(int), nullptr);
104 for (int cpt = 0; cpt < NB_ELEM; cpt++) {
105 xbt_dynar_unshift(d, &cpt);
107 for (int cpt = 0; cpt < NB_ELEM; cpt++) {
108 i = xbt_dynar_pop_as(d, int);
109 REQUIRE(i == cpt); // The retrieved value is not the same than the injected one
111 xbt_dynar_free(&d); /* This code is used both as example and as regression test, so we try to */
112 xbt_dynar_free(&d); /* free the struct twice here to check that it's ok, but freeing it only once */
113 /* in your code is naturally the way to go outside a regression test */
115 INFO("==== Push " << NB_ELEM << "%d int, insert 1000 int in the middle, shift everything");
116 d = xbt_dynar_new(sizeof(int), nullptr);
117 for (cpt = 0; cpt < NB_ELEM; cpt++) {
118 xbt_dynar_push_as(d, int, cpt);
120 for (cpt = 0; cpt < NB_ELEM / 5; cpt++) {
121 xbt_dynar_insert_at_as(d, NB_ELEM / 2, int, cpt);
124 for (cpt = 0; cpt < NB_ELEM / 2; cpt++) {
125 xbt_dynar_shift(d, &i);
126 REQUIRE(i == cpt); // The retrieved value is not the same than the injected one at the begining
128 for (cpt = 999; cpt >= 0; cpt--) {
129 xbt_dynar_shift(d, &i);
130 REQUIRE(i == cpt); // The retrieved value is not the same than the injected one in the middle
132 for (cpt = 2500; cpt < NB_ELEM; cpt++) {
133 xbt_dynar_shift(d, &i);
134 REQUIRE(i == cpt); // The retrieved value is not the same than the injected one at the end
136 xbt_dynar_free(&d); /* This code is used both as example and as regression test, so we try to */
137 xbt_dynar_free(&d); /* free the struct twice here to check that it's ok, but freeing it only once */
138 /* in your code is naturally the way to go outside a regression test */
140 INFO("==== Push " << NB_ELEM << " int, remove 2000-4000. free the rest");
141 d = xbt_dynar_new(sizeof(int), nullptr);
142 for (cpt = 0; cpt < NB_ELEM; cpt++)
143 xbt_dynar_push_as(d, int, cpt);
145 for (cpt = 2000; cpt < 4000; cpt++) {
146 xbt_dynar_remove_at(d, 2000, &i);
147 REQUIRE(i == cpt); // Remove a bad value
149 xbt_dynar_free(&d); /* This code is used both as example and as regression test, so we try to */
150 xbt_dynar_free(&d); /* free the struct twice here to check that it's ok, but freeing it only once */
151 /* in your code is naturally the way to go outside a regression test */
154 /*******************************************************************************/
155 SECTION("Using the xbt_dynar_insert and xbt_dynar_remove functions")
157 xbt_dynar_t d = xbt_dynar_new(sizeof(unsigned int), nullptr);
160 INFO("==== Insert " << NB_ELEM << " int, traverse them, remove them");
161 /* Populate_ints [doxygen cruft] */
162 /* 1. Populate the dynar */
163 for (int cpt = 0; cpt < NB_ELEM; cpt++) {
164 xbt_dynar_insert_at(d, cpt, &cpt);
167 /* 3. Traverse the dynar */
169 xbt_dynar_foreach (d, cursor, cpt) {
170 REQUIRE(cursor == (unsigned int)cpt); // The retrieved value is not the same than the injected one
172 /* end_of_traversal */
174 /* Re-fill with the same values using set_as (and re-verify) */
175 for (int cpt = 0; cpt < NB_ELEM; cpt++)
176 xbt_dynar_set_as(d, cpt, int, cpt);
177 xbt_dynar_foreach (d, cursor, cpt)
178 REQUIRE(cursor == (unsigned int)cpt); // The retrieved value is not the same than the injected one
180 for (int cpt = 0; cpt < NB_ELEM; cpt++) {
182 xbt_dynar_remove_at(d, 0, &val);
183 REQUIRE(cpt == val); // The retrieved value is not the same than the injected one
185 REQUIRE(xbt_dynar_is_empty(d));
188 /* ********************* */
189 INFO("==== Insert " << NB_ELEM << " int in reverse order, traverse them, remove them");
190 d = xbt_dynar_new(sizeof(int), nullptr);
191 for (int cpt = NB_ELEM - 1; cpt >= 0; cpt--) {
192 xbt_dynar_replace(d, cpt, &cpt);
195 /* 3. Traverse the dynar */
196 xbt_dynar_foreach (d, cursor, cpt) {
197 REQUIRE(cursor == (unsigned)cpt); // The retrieved value is not the same than the injected one
199 /* end_of_traversal */
201 for (cpt = NB_ELEM - 1; cpt >= 0; cpt--) {
203 xbt_dynar_remove_at(d, xbt_dynar_length(d) - 1, &val);
204 REQUIRE(cpt == val); // The retrieved value is not the same than the injected one
206 REQUIRE(xbt_dynar_is_empty(d));
210 /*******************************************************************************/
211 SECTION("Dynars of doubles")
218 INFO("==== Traverse the empty dynar");
219 d = xbt_dynar_new(sizeof(int), nullptr);
220 xbt_dynar_foreach (d, cursor, cpt) {
221 REQUIRE(false); // Damnit, there is something in the empty dynar
223 xbt_dynar_free(&d); /* This code is used both as example and as regression test, so we try to */
224 xbt_dynar_free(&d); /* free the struct twice here to check that it's ok, but freeing it only once */
225 /* in your code is naturally the way to go outside a regression test */
227 INFO("==== Push/shift 5000 doubles");
228 d = xbt_dynar_new(sizeof(double), nullptr);
229 for (cpt = 0; cpt < 5000; cpt++) {
231 xbt_dynar_push(d, &d1);
233 xbt_dynar_foreach (d, cursor, d2) {
235 REQUIRE(d1 == d2); // The retrieved value is not the same than the injected one
237 for (cpt = 0; cpt < 5000; cpt++) {
239 xbt_dynar_shift(d, &d2);
240 REQUIRE(d1 == d2); // The retrieved value is not the same than the injected one
242 xbt_dynar_free(&d); /* This code is used both as example and as regression test, so we try to */
243 xbt_dynar_free(&d); /* free the struct twice here to check that it's ok, but freeing it only once */
244 /* in your code is naturally the way to go outside a regression test */
246 INFO("==== Unshift/pop 5000 doubles");
247 d = xbt_dynar_new(sizeof(double), nullptr);
248 for (cpt = 0; cpt < 5000; cpt++) {
250 xbt_dynar_unshift(d, &d1);
252 for (cpt = 0; cpt < 5000; cpt++) {
254 xbt_dynar_pop(d, &d2);
255 REQUIRE(d1 == d2); // The retrieved value is not the same than the injected one
257 xbt_dynar_free(&d); /* This code is used both as example and as regression test, so we try to */
258 xbt_dynar_free(&d); /* free the struct twice here to check that it's ok, but freeing it only once */
259 /* in your code is naturally the way to go outside a regression test */
261 INFO("==== Push 5000 doubles, insert 1000 doubles in the middle, shift everything");
262 d = xbt_dynar_new(sizeof(double), nullptr);
263 for (cpt = 0; cpt < 5000; cpt++) {
265 xbt_dynar_push(d, &d1);
267 for (cpt = 0; cpt < 1000; cpt++) {
269 xbt_dynar_insert_at(d, 2500, &d1);
272 for (cpt = 0; cpt < 2500; cpt++) {
274 xbt_dynar_shift(d, &d2);
275 REQUIRE(d1 == d2); // The retrieved value is not the same than the injected one at the begining
277 for (cpt = 999; cpt >= 0; cpt--) {
279 xbt_dynar_shift(d, &d2);
280 REQUIRE(d1 == d2); // The retrieved value is not the same than the injected one in the middle
282 for (cpt = 2500; cpt < 5000; cpt++) {
284 xbt_dynar_shift(d, &d2);
285 REQUIRE(d1 == d2); // The retrieved value is not the same than the injected one at the end
287 xbt_dynar_free(&d); /* This code is used both as example and as regression test, so we try to */
288 xbt_dynar_free(&d); /* free the struct twice here to check that it's ok, but freeing it only once */
289 /* in your code is naturally the way to go outside a regression test */
291 INFO("==== Push 5000 double, remove 2000-4000. free the rest");
292 d = xbt_dynar_new(sizeof(double), nullptr);
293 for (cpt = 0; cpt < 5000; cpt++) {
295 xbt_dynar_push(d, &d1);
297 for (cpt = 2000; cpt < 4000; cpt++) {
299 xbt_dynar_remove_at(d, 2000, &d2);
300 REQUIRE(d1 == d2); // Remove a bad value
302 xbt_dynar_free(&d); /* This code is used both as example and as regression test, so we try to */
303 xbt_dynar_free(&d); /* free the struct twice here to check that it's ok, but freeing it only once */
304 /* in your code is naturally the way to go outside a regression test */
307 /*******************************************************************************/
308 SECTION("Dynars of strings")
314 INFO("==== Traverse the empty dynar");
315 xbt_dynar_t d = xbt_dynar_new(sizeof(char*), &xbt_free_ref);
316 xbt_dynar_foreach (d, iter, s1) {
317 REQUIRE(false); // Damnit, there is something in the empty dynar"
319 xbt_dynar_free(&d); /* This code is used both as example and as regression test, so we try to */
320 xbt_dynar_free(&d); /* free the struct twice here to check that it's ok, but freeing it only once */
321 /* in your code is naturally the way to go outside a regression test */
323 INFO("==== Push " << NB_ELEM << " strings, set them again 3 times, shift them");
324 /* Populate_str [doxygen cruft] */
325 d = xbt_dynar_new(sizeof(char*), &xbt_free_ref);
326 /* 1. Populate the dynar */
327 for (int cpt = 0; cpt < NB_ELEM; cpt++) {
328 snprintf(buf, 1023, "%d", cpt);
329 s1 = xbt_strdup(buf);
330 xbt_dynar_push(d, &s1);
332 for (int i = 0; i < 3; i++) {
333 for (int cpt = 0; cpt < NB_ELEM; cpt++) {
334 snprintf(buf, 1023, "%d", cpt);
335 s1 = xbt_strdup(buf);
336 xbt_dynar_replace(d, cpt, &s1);
339 for (int cpt = 0; cpt < NB_ELEM; cpt++) {
340 snprintf(buf, 1023, "%d", cpt);
341 xbt_dynar_shift(d, &s2);
342 REQUIRE(not strcmp(buf, s2)); // The retrieved value is not the same than the injected one
345 xbt_dynar_free(&d); /* This code is used both as example and as regression test, so we try to */
346 xbt_dynar_free(&d); /* free the struct twice here to check that it's ok, but freeing it only once */
347 /* in your code is naturally the way to go outside a regression test */
349 INFO("==== Unshift, traverse and pop " << NB_ELEM << " strings");
350 d = xbt_dynar_new(sizeof(char**), &xbt_free_ref);
351 for (int cpt = 0; cpt < NB_ELEM; cpt++) {
352 snprintf(buf, 1023, "%d", cpt);
353 s1 = xbt_strdup(buf);
354 xbt_dynar_unshift(d, &s1);
356 /* 2. Traverse the dynar with the macro */
357 xbt_dynar_foreach (d, iter, s1) {
358 snprintf(buf, 1023, "%u", NB_ELEM - iter - 1);
359 REQUIRE(not strcmp(buf, s1)); // The retrieved value is not the same than the injected one
361 /* 3. Traverse the dynar with the macro */
362 for (int cpt = 0; cpt < NB_ELEM; cpt++) {
363 snprintf(buf, 1023, "%d", cpt);
364 xbt_dynar_pop(d, &s2);
365 REQUIRE(not strcmp(buf, s2)); // The retrieved value is not the same than the injected one
368 /* 4. Free the resources */
369 xbt_dynar_free(&d); /* This code is used both as example and as regression test, so we try to */
370 xbt_dynar_free(&d); /* free the struct twice here to check that it's ok, but freeing it only once */
371 /* in your code is naturally the way to go outside a regression test */
373 INFO("==== Push " << NB_ELEM << " strings, insert " << (NB_ELEM / 5) << " strings in the middle, shift everything");
374 d = xbt_dynar_new(sizeof(char*), &xbt_free_ref);
375 for (int cpt = 0; cpt < NB_ELEM; cpt++) {
376 snprintf(buf, 1023, "%d", cpt);
377 s1 = xbt_strdup(buf);
378 xbt_dynar_push(d, &s1);
380 for (int cpt = 0; cpt < NB_ELEM / 5; cpt++) {
381 snprintf(buf, 1023, "%d", cpt);
382 s1 = xbt_strdup(buf);
383 xbt_dynar_insert_at(d, NB_ELEM / 2, &s1);
386 for (int cpt = 0; cpt < NB_ELEM / 2; cpt++) {
387 snprintf(buf, 1023, "%d", cpt);
388 xbt_dynar_shift(d, &s2);
389 REQUIRE(not strcmp(buf, s2)); // The retrieved value is not the same than the injected one at the beginning
392 for (int cpt = (NB_ELEM / 5) - 1; cpt >= 0; cpt--) {
393 snprintf(buf, 1023, "%d", cpt);
394 xbt_dynar_shift(d, &s2);
395 REQUIRE(not strcmp(buf, s2)); // The retrieved value is not the same than the injected one in the middle
398 for (int cpt = NB_ELEM / 2; cpt < NB_ELEM; cpt++) {
399 snprintf(buf, 1023, "%d", cpt);
400 xbt_dynar_shift(d, &s2);
401 REQUIRE(not strcmp(buf, s2)); // The retrieved value is not the same than the injected one at the end
404 xbt_dynar_free(&d); /* This code is used both as example and as regression test, so we try to */
405 xbt_dynar_free(&d); /* free the struct twice here to check that it's ok, but freeing it only once */
406 /* in your code is naturally the way to go outside a regression test */
408 INFO("==== Push " << NB_ELEM << " strings, remove " << (2 * NB_ELEM / 5) << "-" << (4 * NB_ELEM / 5)
409 << ". free the rest");
410 d = xbt_dynar_new(sizeof(char*), &xbt_free_ref);
411 for (int cpt = 0; cpt < NB_ELEM; cpt++) {
412 snprintf(buf, 1023, "%d", cpt);
413 s1 = xbt_strdup(buf);
414 xbt_dynar_push(d, &s1);
416 for (int cpt = 2 * (NB_ELEM / 5); cpt < 4 * (NB_ELEM / 5); cpt++) {
417 snprintf(buf, 1023, "%d", cpt);
418 xbt_dynar_remove_at(d, 2 * (NB_ELEM / 5), &s2);
419 REQUIRE(not strcmp(buf, s2)); // Remove a bad value
422 xbt_dynar_free(&d); /* end_of_doxygen */