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. */
9 #include "xbt/sysdep.h"
13 constexpr int NB_ELEM = 5000;
15 TEST_CASE("xbt::dynar: generic C vector", "dynar")
18 SECTION("Dynars of integers")
20 /* Vars_decl [doxygen cruft] */
24 INFO("==== Traverse the empty dynar");
25 xbt_dynar_t d = xbt_dynar_new(sizeof(int), nullptr);
26 xbt_dynar_foreach (d, cursor, cpt) {
27 xbt_die("Damnit, there is something in the empty dynar");
29 xbt_dynar_free(&d); /* This code is used both as example and as regression test, so we try to */
30 xbt_dynar_free(&d); /* free the struct twice here to check that it's ok, but freeing it only once */
31 /* in your code is naturally the way to go outside a regression test */
33 INFO("==== Push " << NB_ELEM << " int, set them again 3 times, traverse them, shift them");
34 /* Populate_ints [doxygen cruft] */
35 /* 1. Populate the dynar */
36 d = xbt_dynar_new(sizeof(int), nullptr);
37 for (int i = 0; i < NB_ELEM; i++) {
38 xbt_dynar_push_as(d, int, i); /* This is faster (and possible only with scalars) */
39 /* xbt_dynar_push(d, &i); This would also work */
42 /* 2. Traverse manually the dynar */
43 for (int i = 0; i < NB_ELEM; i++) {
44 int* iptr = (int*)xbt_dynar_get_ptr(d, i);
45 REQUIRE(i == *iptr); // The retrieved value is not the same than the injected one
48 /* 3. Traverse the dynar using the neat macro to that extend */
49 xbt_dynar_foreach (d, cursor, cpt) {
50 REQUIRE(cursor == (unsigned int)cpt); // The retrieved value is not the same than the injected one
52 /* end_of_traversal */
54 for (int i = 0; i < NB_ELEM; i++)
55 *(int*)xbt_dynar_get_ptr(d, i) = i;
57 for (int i = 0; i < NB_ELEM; i++)
58 *(int*)xbt_dynar_get_ptr(d, i) = i;
60 for (int i = 0; i < NB_ELEM; i++)
61 *(int*)xbt_dynar_get_ptr(d, i) = i;
64 xbt_dynar_foreach (d, cursor, cpt) {
65 REQUIRE(cpt == count); // The retrieved value is not the same than the injected one
68 REQUIRE(count == NB_ELEM); // Cannot retrieve all my values. cpt is the last one I got
70 /* shifting [doxygen cruft] */
71 /* 4. Shift all the values */
72 for (int i = 0; i < NB_ELEM; i++) {
74 xbt_dynar_shift(d, &val);
75 REQUIRE(val == i); // The retrieved value is not the same than the injected one
77 REQUIRE(xbt_dynar_is_empty(d));
79 for (int i = 0; i < NB_ELEM; i++) {
80 xbt_dynar_push_as(d, int, -1);
83 xbt_dynar_foreach_ptr(d, cursor, pi) { *pi = 0; }
84 xbt_dynar_foreach (d, cursor, cpt) {
85 REQUIRE(cpt == 0); // The value is not the same as the expected one.
87 xbt_dynar_foreach_ptr(d, cursor, pi) { *pi = 1; }
88 xbt_dynar_foreach (d, cursor, cpt) {
89 REQUIRE(cpt == 1); // The value is not the same as the expected one
92 /* 5. Free the resources */
93 xbt_dynar_free(&d); /* This code is used both as example and as regression test, so we try to */
94 xbt_dynar_free(&d); /* free the struct twice here to check that it's ok, but freeing it only once */
95 /* in your code is naturally the way to go outside a regression test */
97 INFO("==== Unshift/pop " << NB_ELEM << " int");
98 d = xbt_dynar_new(sizeof(int), nullptr);
99 for (int i = 0; i < NB_ELEM; i++) {
100 xbt_dynar_unshift(d, &i);
102 for (int i = 0; i < NB_ELEM; i++) {
103 int val = xbt_dynar_pop_as(d, int);
104 REQUIRE(val == i); // The retrieved value is not the same than the injected one
106 xbt_dynar_free(&d); /* This code is used both as example and as regression test, so we try to */
107 xbt_dynar_free(&d); /* free the struct twice here to check that it's ok, but freeing it only once */
108 /* in your code is naturally the way to go outside a regression test */
110 INFO("==== Push " << NB_ELEM << "%d int, insert 1000 int in the middle, shift everything");
111 d = xbt_dynar_new(sizeof(int), nullptr);
112 for (int i = 0; i < NB_ELEM; i++) {
113 xbt_dynar_push_as(d, int, i);
115 for (int i = 0; i < NB_ELEM / 5; i++) {
116 xbt_dynar_insert_at_as(d, NB_ELEM / 2, int, i);
119 for (int i = 0; i < NB_ELEM / 2; i++) {
121 xbt_dynar_shift(d, &val);
122 REQUIRE(val == i); // The retrieved value is not the same than the injected one at the begining
124 for (int i = 999; i >= 0; i--) {
126 xbt_dynar_shift(d, &val);
127 REQUIRE(val == i); // The retrieved value is not the same than the injected one in the middle
129 for (int i = 2500; i < NB_ELEM; i++) {
131 xbt_dynar_shift(d, &val);
132 REQUIRE(val == i); // The retrieved value is not the same than the injected one at the end
134 xbt_dynar_free(&d); /* This code is used both as example and as regression test, so we try to */
135 xbt_dynar_free(&d); /* free the struct twice here to check that it's ok, but freeing it only once */
136 /* in your code is naturally the way to go outside a regression test */
138 INFO("==== Push " << NB_ELEM << " int, remove 2000-4000. free the rest");
139 d = xbt_dynar_new(sizeof(int), nullptr);
140 for (int i = 0; i < NB_ELEM; i++)
141 xbt_dynar_push_as(d, int, i);
143 for (int i = 2000; i < 4000; i++) {
145 xbt_dynar_remove_at(d, 2000, &val);
146 REQUIRE(val == i); // Remove a bad value
148 xbt_dynar_free(&d); /* This code is used both as example and as regression test, so we try to */
149 xbt_dynar_free(&d); /* free the struct twice here to check that it's ok, but freeing it only once */
150 /* in your code is naturally the way to go outside a regression test */
153 /*******************************************************************************/
154 SECTION("Using the xbt_dynar_insert and xbt_dynar_remove functions")
156 xbt_dynar_t d = xbt_dynar_new(sizeof(unsigned int), nullptr);
159 INFO("==== Insert " << NB_ELEM << " int, traverse them, remove them");
160 /* Populate_ints [doxygen cruft] */
161 /* 1. Populate the dynar */
162 for (int i = 0; i < NB_ELEM; i++) {
163 xbt_dynar_insert_at(d, i, &i);
166 /* 3. Traverse the dynar */
168 xbt_dynar_foreach (d, cursor, cpt) {
169 REQUIRE(cursor == (unsigned int)cpt); // The retrieved value is not the same than the injected one
171 /* end_of_traversal */
173 /* Re-fill with the same values using set_as (and re-verify) */
174 for (int i = 0; i < NB_ELEM; i++)
175 xbt_dynar_set_as(d, i, int, i);
176 xbt_dynar_foreach (d, cursor, cpt)
177 REQUIRE(cursor == (unsigned int)cpt); // The retrieved value is not the same than the injected one
179 for (int i = 0; i < NB_ELEM; i++) {
181 xbt_dynar_remove_at(d, 0, &val);
182 REQUIRE(i == val); // The retrieved value is not the same than the injected one
184 REQUIRE(xbt_dynar_is_empty(d));
187 /* ********************* */
188 INFO("==== Insert " << NB_ELEM << " int in reverse order, traverse them, remove them");
189 d = xbt_dynar_new(sizeof(int), nullptr);
190 for (int i = NB_ELEM - 1; i >= 0; i--) {
191 xbt_dynar_replace(d, i, &i);
194 /* 3. Traverse the dynar */
195 xbt_dynar_foreach (d, cursor, cpt) {
196 REQUIRE(cursor == (unsigned)cpt); // The retrieved value is not the same than the injected one
198 /* end_of_traversal */
200 for (int i = NB_ELEM - 1; i >= 0; i--) {
202 xbt_dynar_remove_at(d, xbt_dynar_length(d) - 1, &val);
203 REQUIRE(val == i); // The retrieved value is not the same than the injected one
205 REQUIRE(xbt_dynar_is_empty(d));
209 /*******************************************************************************/
210 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 (int i = 0; i < 5000; i++) {
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 (int i = 0; i < 5000; i++) {
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 (int i = 0; i < 5000; i++) {
250 xbt_dynar_unshift(d, &d1);
252 for (int i = 0; i < 5000; i++) {
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 (int i = 0; i < 5000; i++) {
265 xbt_dynar_push(d, &d1);
267 for (int i = 0; i < 1000; i++) {
269 xbt_dynar_insert_at(d, 2500, &d1);
272 for (int i = 0; i < 2500; i++) {
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 (int i = 999; i >= 0; i--) {
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 (int i = 2500; i < 5000; i++) {
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 (int i = 0; i < 5000; i++) {
295 xbt_dynar_push(d, &d1);
297 for (int i = 2000; i < 4000; i++) {
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")
315 INFO("==== Traverse the empty dynar");
316 xbt_dynar_t d = xbt_dynar_new(sizeof(char*), &xbt_free_ref);
317 xbt_dynar_foreach (d, iter, s1) {
318 REQUIRE(false); // Damnit, there is something in the empty dynar"
320 xbt_dynar_free(&d); /* This code is used both as example and as regression test, so we try to */
321 xbt_dynar_free(&d); /* free the struct twice here to check that it's ok, but freeing it only once */
322 /* in your code is naturally the way to go outside a regression test */
324 INFO("==== Push " << NB_ELEM << " strings, set them again 3 times, shift them");
325 /* Populate_str [doxygen cruft] */
326 d = xbt_dynar_new(sizeof(char*), &xbt_free_ref);
327 /* 1. Populate the dynar */
328 for (int i = 0; i < NB_ELEM; i++) {
329 snprintf(buf, 1023, "%d", i);
330 s1 = xbt_strdup(buf);
331 xbt_dynar_push(d, &s1);
333 for (int k = 0; k < 3; k++) {
334 for (int i = 0; i < NB_ELEM; i++) {
335 snprintf(buf, 1023, "%d", i);
336 s1 = xbt_strdup(buf);
337 xbt_dynar_replace(d, i, &s1);
340 for (int i = 0; i < NB_ELEM; i++) {
341 snprintf(buf, 1023, "%d", i);
342 xbt_dynar_shift(d, &s2);
343 REQUIRE(not strcmp(buf, s2)); // The retrieved value is not the same than the injected one
346 xbt_dynar_free(&d); /* This code is used both as example and as regression test, so we try to */
347 xbt_dynar_free(&d); /* free the struct twice here to check that it's ok, but freeing it only once */
348 /* in your code is naturally the way to go outside a regression test */
350 INFO("==== Unshift, traverse and pop " << NB_ELEM << " strings");
351 d = xbt_dynar_new(sizeof(char**), &xbt_free_ref);
352 for (int i = 0; i < NB_ELEM; i++) {
353 snprintf(buf, 1023, "%d", i);
354 s1 = xbt_strdup(buf);
355 xbt_dynar_unshift(d, &s1);
357 /* 2. Traverse the dynar with the macro */
358 xbt_dynar_foreach (d, iter, s1) {
359 snprintf(buf, 1023, "%u", NB_ELEM - iter - 1);
360 REQUIRE(not strcmp(buf, s1)); // The retrieved value is not the same than the injected one
362 /* 3. Traverse the dynar with the macro */
363 for (int i = 0; i < NB_ELEM; i++) {
364 snprintf(buf, 1023, "%d", i);
365 xbt_dynar_pop(d, &s2);
366 REQUIRE(not strcmp(buf, s2)); // The retrieved value is not the same than the injected one
369 /* 4. Free the resources */
370 xbt_dynar_free(&d); /* This code is used both as example and as regression test, so we try to */
371 xbt_dynar_free(&d); /* free the struct twice here to check that it's ok, but freeing it only once */
372 /* in your code is naturally the way to go outside a regression test */
374 INFO("==== Push " << NB_ELEM << " strings, insert " << (NB_ELEM / 5) << " strings in the middle, shift everything");
375 d = xbt_dynar_new(sizeof(char*), &xbt_free_ref);
376 for (int i = 0; i < NB_ELEM; i++) {
377 snprintf(buf, 1023, "%d", i);
378 s1 = xbt_strdup(buf);
379 xbt_dynar_push(d, &s1);
381 for (int i = 0; i < NB_ELEM / 5; i++) {
382 snprintf(buf, 1023, "%d", i);
383 s1 = xbt_strdup(buf);
384 xbt_dynar_insert_at(d, NB_ELEM / 2, &s1);
387 for (int i = 0; i < NB_ELEM / 2; i++) {
388 snprintf(buf, 1023, "%d", i);
389 xbt_dynar_shift(d, &s2);
390 REQUIRE(not strcmp(buf, s2)); // The retrieved value is not the same than the injected one at the beginning
393 for (int i = (NB_ELEM / 5) - 1; i >= 0; i--) {
394 snprintf(buf, 1023, "%d", i);
395 xbt_dynar_shift(d, &s2);
396 REQUIRE(not strcmp(buf, s2)); // The retrieved value is not the same than the injected one in the middle
399 for (int i = NB_ELEM / 2; i < NB_ELEM; i++) {
400 snprintf(buf, 1023, "%d", i);
401 xbt_dynar_shift(d, &s2);
402 REQUIRE(not strcmp(buf, s2)); // The retrieved value is not the same than the injected one at the end
405 xbt_dynar_free(&d); /* This code is used both as example and as regression test, so we try to */
406 xbt_dynar_free(&d); /* free the struct twice here to check that it's ok, but freeing it only once */
407 /* in your code is naturally the way to go outside a regression test */
409 INFO("==== Push " << NB_ELEM << " strings, remove " << (2 * NB_ELEM / 5) << "-" << (4 * NB_ELEM / 5)
410 << ". free the rest");
411 d = xbt_dynar_new(sizeof(char*), &xbt_free_ref);
412 for (int i = 0; i < NB_ELEM; i++) {
413 snprintf(buf, 1023, "%d", i);
414 s1 = xbt_strdup(buf);
415 xbt_dynar_push(d, &s1);
417 for (int i = 2 * (NB_ELEM / 5); i < 4 * (NB_ELEM / 5); i++) {
418 snprintf(buf, 1023, "%d", i);
419 xbt_dynar_remove_at(d, 2 * (NB_ELEM / 5), &s2);
420 REQUIRE(not strcmp(buf, s2)); // Remove a bad value
423 xbt_dynar_free(&d); /* end_of_doxygen */