1 /* Copyright (c) 2000-2009, The Johns Hopkins University
2 * All rights reserved.
3 *
4 * The contents of this file are subject to a license (the ``License'').
5 * You may not use this file except in compliance with the License. The
6 * specific language governing the rights and limitations of the License
7 * can be found in the file ``STDUTIL_LICENSE'' found in this
8 * distribution.
9 *
10 * Software distributed under the License is distributed on an AS IS
11 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
12 *
13 * The Original Software is:
14 * The Stdutil Library
15 *
16 * Contributors:
17 * Creator - John Lane Schultz (jschultz@cnds.jhu.edu)
18 * The Center for Networking and Distributed Systems
19 * (CNDS - http://www.cnds.jhu.edu)
20 */
21
22 #include <stdlib.h>
23 #include <string.h>
24
25 #include <stdutil/stderror.h>
26 #include <stdutil/stdcarr.h>
27
28 #ifdef __cplusplus
29 extern "C" {
30 #endif
31
32 #define STDCARR_IS_LEGAL(carr) (( ((carr)->cap != 0 && (carr)->base != NULL) || ((carr)->cap == 0 && (carr)->base == NULL) ) && \
33 (stdsize) ((carr)->endbase - (carr)->base) == (carr)->cap * (carr)->vsize && \
34 (carr)->begin >= (carr)->base && (carr)->begin <= (carr)->endbase && \
35 (carr)->end >= (carr)->base && (carr)->end <= (carr)->endbase && \
36 (stdsize) ((carr)->begin > (carr)->end ? \
37 ((carr)->endbase - (carr)->begin) + ((carr)->end - (carr)->base) : \
38 (carr)->end - (carr)->begin) == (carr)->size * (carr)->vsize && \
39 ((carr)->endbase == NULL || ((carr)->begin != (carr)->endbase && (carr)->end != (carr)->endbase)) && \
40 ( ((carr)->size < (carr)->cap) || ((carr)->size == 0 && (carr)->cap == 0) ) && \
41 (carr)->vsize != 0 && \
42 ((carr)->opts & ~(STDCARR_OPTS_NO_AUTO_GROW | STDCARR_OPTS_NO_AUTO_SHRINK)) == 0)
43
44 #define STDCARR_IT_IS_LEGAL(carr, it) ((it)->base == (carr)->base && (it)->endbase == (carr)->endbase && \
45 (it)->begin == (carr)->begin && (it)->end == (carr)->end && (it)->vsize == (carr)->vsize)
46
47 #define STDCARR_IT_IS_LEGAL2(it) ((it)->base <= (it)->endbase && \
48 (it)->begin >= (it)->base && (it)->begin <= (it)->endbase && \
49 (it)->end >= (it)->base && (it)->end <= (it)->endbase && \
50 ((it)->begin <= (it)->end ? \
51 ((it)->val >= (it)->begin && (it)->val <= (it)->end) : \
52 (((it)->val >= (it)->begin && (it)->val < (it)->endbase) || \
53 ((it)->val >= (it)->base && (it)->val <= (it)->end))) && \
54 ((it)->endbase == NULL || ((it)->begin != (it)->endbase && (it)->end != (it)->endbase && (it)->val != (it)->endbase)) && \
55 (it)->vsize != 0)
56
57 #define STDIT_CARR_IS_LEGAL(it) ((it)->type_id == STDCARR_IT_ID && STDCARR_IT_IS_LEGAL2(&(it)->impl.carr))
58
59 #define STDCARR_INS_SHIFT_RIGHT(carr, ptr) \
60 ((ptr) >= (carr)->begin ? (stdsize) ((ptr) - (carr)->begin) > ((carr)->size >> 1) * (carr)->vsize \
61 : (stdsize) ((carr)->end - (ptr)) <= ((carr)->size >> 1) * (carr)->vsize)
62
63 /* NOTE: the '+' sign in '(carr)->size + (n)' is correct don't change it -- work it out on paper */
64
65 #define STDCARR_ERS_SHIFT_RIGHT(carr, ptr, n) \
66 ((ptr) >= (carr)->begin ? (stdsize) ((ptr) - (carr)->begin) < (((carr)->size - (n)) >> 1) * (carr)->vsize \
67 : (stdsize) ((carr)->end - (ptr)) >= (((carr)->size + (n)) >> 1) * (carr)->vsize)
68
69 /************************************************************************************************
70 * stdcarr_low_copy_to_buf: Copy a portion of a circular array to a
71 * buffer. Returns ptr to right after copied data in dst. 'c_begin'
72 * and 'c_end' point at positions inside of carr.
73 ***********************************************************************************************/
74
stdcarr_low_copy_to_buf(char * dst,const stdcarr * carr,const char * c_begin,const char * c_end)75 STDINLINE static char *stdcarr_low_copy_to_buf(char *dst, const stdcarr *carr, const char *c_begin, const char *c_end)
76 {
77 stdsize diff;
78
79 STDSAFETY_CHECK(c_begin >= carr->base && c_begin <= carr->endbase &&
80 c_end >= carr->base && c_end <= carr->endbase &&
81 (carr->endbase == NULL || (c_begin != carr->endbase && c_end != carr->endbase)));
82
83 if (c_begin <= c_end) {
84 diff = (stdsize) (c_end - c_begin);
85
86 memcpy(dst, c_begin, diff);
87 dst += diff;
88
89 } else {
90 diff = (stdsize) (carr->endbase - c_begin);
91
92 memcpy(dst, c_begin, diff);
93 dst += diff;
94
95 diff = (stdsize) (c_end - carr->base);
96
97 memcpy(dst, carr->base, diff);
98 dst += diff;
99 }
100
101 return dst;
102 }
103
104 /************************************************************************************************
105 * stdcarr_low_forward: Return 'p' advanced by 'n' bytes forward, with wrapping.
106 ***********************************************************************************************/
107
stdcarr_low_forward(char * p,stdsize n,const char * base,const char * endbase)108 STDINLINE static char *stdcarr_low_forward(char *p, stdsize n, const char *base, const char *endbase)
109 {
110 STDSAFETY_CHECK(p >= base && p <= endbase && (endbase == NULL || p != endbase));
111
112 return ((p += n) < endbase ? p : (char*) base + (p - (char*) endbase));
113 }
114
115 /************************************************************************************************
116 * stdcarr_low_backward: Return 'p' advanced by 'n' bytes backward, with wrapping.
117 ***********************************************************************************************/
118
stdcarr_low_backward(char * p,stdsize n,const char * base,const char * endbase)119 STDINLINE static char *stdcarr_low_backward(char *p, stdsize n, const char *base, const char *endbase)
120 {
121 STDSAFETY_CHECK(p >= base && p <= endbase && (endbase == NULL || p != endbase));
122
123 return ((p -= n) >= base ? p : (char*) endbase - ((char*) base - p));
124 }
125
126 /************************************************************************************************
127 * stdcarr_low_insert_shift_right: This function shifts all the values
128 * from 'it' and on, to the right by delta bytes. It also updates end
129 * and size.
130 ***********************************************************************************************/
131
stdcarr_low_insert_shift_right(stdcarr * carr,char * it,stdsize delta,stdsize new_size)132 STDINLINE static void stdcarr_low_insert_shift_right(stdcarr *carr, char *it, stdsize delta, stdsize new_size)
133 {
134 stdssize diff;
135 stdssize diff2;
136
137 if (carr->begin <= carr->end) {
138
139 if ((diff = carr->end + delta - carr->endbase) <= 0) { /* no data wraps around */
140 memmove(it + delta, it, (stdsize) (carr->end - it));
141
142 } else {
143
144 if ((diff2 = carr->end - it) <= diff) { /* data to shift can fit between base and new end */
145 memcpy(carr->base + diff - diff2, it, (stdsize) diff2);
146
147 } else { /* partial fit */
148 memcpy(carr->base, carr->end - diff, (stdsize) diff);
149 memmove(it + delta, it, (stdsize) (diff2 - diff));
150 }
151 }
152
153 } else { /* space exists between end and begin for insertion */
154
155 if ((diff = carr->end - it) >= 0) { /* it is below end */
156 memmove(it + delta, it, (stdsize) diff);
157
158 } else {
159 memmove(carr->base + delta, carr->base, (stdsize) (carr->end - carr->base)); /* shift lower data */
160
161 if ((stdsize) (diff = carr->endbase - it) <= delta) { /* higher data fits into newly opened area */
162 memcpy(carr->base + delta - diff, it, (stdsize) diff);
163
164 } else { /* partial fit */
165 memcpy(carr->base, carr->endbase - delta, delta);
166 memmove(it + delta, it, (stdsize) (diff - delta));
167 }
168 }
169 }
170
171 carr->size = new_size;
172 carr->end = stdcarr_low_forward(carr->end, delta, carr->base, carr->endbase);
173 }
174
175 /************************************************************************************************
176 * stdcarr_low_insert_shift_left: This function shifts all values
177 * before 'it' to the left by delta bytes. It also updates begin and
178 * size.
179 ***********************************************************************************************/
180
stdcarr_low_insert_shift_left(stdcarr * carr,char * it,stdsize delta,stdsize new_size)181 STDINLINE static void stdcarr_low_insert_shift_left(stdcarr *carr, char *it, stdsize delta, stdsize new_size)
182 {
183 stdssize diff;
184 stdssize diff2;
185
186 if (carr->begin <= carr->end) {
187
188 if ((diff = carr->base - (carr->begin - delta)) <= 0) { /* new begin doesn't wrap around */
189 memmove(carr->begin - delta, carr->begin, (stdsize) (it - carr->begin));
190
191 } else {
192
193 if ((diff2 = it - carr->begin) <= diff) { /* data to shift fits between new begin and endbase */
194 memcpy(carr->endbase - diff, carr->begin, (stdsize) diff2);
195
196 } else { /* partial fit */
197 memcpy(carr->endbase - diff, carr->begin, (stdsize) diff);
198 memmove(carr->base, carr->begin + diff, (stdsize) (diff2 - diff));
199 }
200 }
201
202 } else { /* space exists between end and begin for insertion */
203
204 if (it >= carr->begin) { /* it is above begin */
205 memmove(carr->begin - delta, carr->begin, (stdsize) (it - carr->begin));
206
207 } else {
208 memmove(carr->begin - delta, carr->begin, (stdsize) (carr->endbase - carr->begin));
209
210 if ((stdsize) (diff = it - carr->base) <= delta) { /* fits into newly opened area */
211 memcpy(carr->endbase - delta, carr->base, (stdsize) diff);
212
213 } else {
214 memcpy(carr->endbase - delta, carr->base, delta);
215 memmove(carr->base, carr->base + delta, (stdsize) (diff - delta));
216 }
217 }
218 }
219
220 carr->size = new_size;
221 carr->begin = stdcarr_low_backward(carr->begin, delta, carr->base, carr->endbase);
222 }
223
224 /************************************************************************************************
225 * stdcarr_low_erase_shift_left: This function shifts values from the
226 * right to the left into erased values. erase_end points to one past
227 * the last value to be erased. (e.g. - delta == 4 * carr->vsize)
228 *
229 * erase_shift_left(__****----1***___) => __****1***_______
230 *
231 * Legend: _ = empty slot, * = occupied slot, 1 = erase_end, - = to be
232 * deleted.
233 ***********************************************************************************************/
234
stdcarr_low_erase_shift_left(stdcarr * carr,char * erase_end,stdsize delta,stdsize new_size)235 STDINLINE static void stdcarr_low_erase_shift_left(stdcarr *carr, char *erase_end, stdsize delta, stdsize new_size)
236 {
237 char * erase_begin = erase_end - delta; /* may point outside alloc'ed mem */
238 stdssize diff;
239 stdssize diff2;
240
241 if ((diff = carr->end - erase_end) >= 0) { /* end is at or above erase_end */
242
243 if ((diff2 = carr->base - erase_begin) <= 0) { /* erase region doesn't wrap around */
244 memmove(erase_begin, erase_end, (stdsize) diff);
245
246 } else {
247 /* diff2: how many bytes to erase off of high portion of array */
248
249 erase_begin = carr->endbase - diff2; /* implicitly valid */
250
251 if (diff <= diff2) { /* data to shift fits between erase_begin and endbase */
252 memcpy(erase_begin, erase_end, (stdsize) diff);
253
254 } else { /* only a partial fit */
255 memcpy(erase_begin, erase_end, (stdsize) diff2);
256 memmove(carr->base, erase_end + diff2, (stdsize) (diff - diff2));
257 }
258 }
259
260 } else { /* carr->end is wrapped around */
261 diff = carr->endbase - erase_end;
262 memmove(erase_begin, erase_end, (stdsize) diff); /* shift higher data first */
263 erase_begin += diff; /* move erase_begin forward diff bytes */
264
265 if ((stdsize) (diff = carr->end - carr->base) <= delta) { /* lower data fits in opened area */
266 memcpy(erase_begin, carr->base, (stdsize) diff); /* copy lower data to higher */
267
268 } else { /* partial fit */
269 memcpy(erase_begin, carr->base, delta); /* copy delta bytes higher */
270 memmove(carr->base, carr->base + delta, (stdsize) (diff - delta)); /* shift rest lower */
271 }
272 }
273
274 carr->size = new_size;
275 carr->end = stdcarr_low_backward(carr->end, delta, carr->base, carr->endbase);
276 }
277
278 /************************************************************************************************
279 * stdcarr_low_erase_shift_right: This function shifts values from the
280 * left to the right into erased values. erase_begin points to the
281 * first value to be erased. (e.g. - delta == 4 * carr->vsize).
282 *
283 * erase_shift_right(__**1---*****___) => ______*******___
284 *
285 * Legend: _ = empty slot, * = occupied slot, 1 = it, - = to be
286 * deleted.
287 ***********************************************************************************************/
288
stdcarr_low_erase_shift_right(stdcarr * carr,char * erase_begin,stdsize delta,stdsize new_size)289 STDINLINE static void stdcarr_low_erase_shift_right(stdcarr *carr, char *erase_begin, stdsize delta, stdsize new_size)
290 {
291 char * erase_end = erase_begin + delta; /* may point outside valid range */
292 stdssize diff;
293 stdssize diff2;
294 stdssize diff3;
295
296 if ((diff = erase_begin - carr->begin) >= 0) { /* erase_begin is at or above begin */
297
298 if ((diff2 = erase_end - carr->endbase) <= 0) { /* erase region doesn't wrap around */
299 memmove(carr->begin + delta, carr->begin, (stdsize) diff);
300
301 } else {
302 /* diff2: how many bytes to erase off of low portion of array */
303
304 if ((diff3 = diff2 - diff) >= 0) { /* data to shift fits between base and erase_end */
305 memcpy(carr->base + diff3, carr->begin, (stdsize) diff);
306
307 } else { /* only a partial fit */
308 memcpy(carr->base, erase_begin - diff2, (stdsize) diff2);
309 memmove(carr->begin + delta, carr->begin, (stdsize) -diff3);
310 }
311 }
312
313 } else {
314 diff = erase_begin - carr->base;
315 erase_end -= diff; /* move erase_end back diff bytes */
316 memmove(erase_end, carr->base, (stdsize) diff); /* shift lower data first */
317
318 if ((stdsize) (diff = carr->endbase - carr->begin) <= delta) { /* fits into newly opened area */
319 memcpy(erase_end - diff, carr->begin, (stdsize) diff);
320
321 } else { /* partial fit */
322 memcpy(carr->base, carr->endbase - delta, delta); /* copy delta bytes lower */
323 memmove(carr->begin + delta, carr->begin, (stdsize) (diff - delta)); /* shift rest higher */
324 }
325 }
326
327 carr->size = new_size;
328 carr->begin = stdcarr_low_forward(carr->begin, delta, carr->base, carr->endbase);
329 }
330
331 /************************************************************************************************
332 * stdcarr_low_insert_shift: This function first determines if an
333 * insertion will require a reallocation. If reallocation isn't
334 * needed, it calls the specified array shift function. If
335 * reallocation is called for, it does it and copies the values from
336 * carr to the new array while creating the open space requested. This
337 * function returns a pointer to the beginning of the insertion region
338 * through itp on success.
339 ***********************************************************************************************/
340
stdcarr_low_insert_shift(stdcarr * carr,char ** itp,stdsize delta,stdsize new_size,stdbool shift_right)341 STDINLINE static stdcode stdcarr_low_insert_shift(stdcarr *carr, char **itp, stdsize delta,
342 stdsize new_size, stdbool shift_right)
343 {
344 stdcode ret = STDESUCCESS;
345
346 if (delta == 0) { /* no-op */
347 goto stdcarr_low_insert_shift_end;
348 }
349
350 /* delta != 0 -> new_size >= 1 */
351
352 if (new_size <= stdcarr_high_capacity(carr)) { /* current table is big enough */
353
354 if (shift_right) {
355 stdcarr_low_insert_shift_right(carr, *itp, delta, new_size);
356
357 } else {
358 stdcarr_low_insert_shift_left(carr, *itp, delta, new_size);
359 *itp = stdcarr_low_backward(*itp, delta, carr->base, carr->endbase);
360 }
361
362 } else if ((carr->opts & STDCARR_OPTS_NO_AUTO_GROW) == 0) { /* auto-growth allowed */
363 stdsize new_cap = (new_size << 1); /* new_cap > 0 */
364 stdsize asize;
365 char * mem;
366 char * tmp;
367
368 new_cap = STDMAX(new_cap, STDCARR_MIN_AUTO_ALLOC);
369 asize = new_cap * carr->vsize;
370
371 if ((mem = (char*) malloc(asize)) == NULL) {
372 ret = STDENOMEM;
373 goto stdcarr_low_insert_shift_end;
374 }
375
376 if (carr->base != NULL) {
377 tmp = *itp;
378 *itp = stdcarr_low_copy_to_buf(mem, carr, carr->begin, tmp); /* copy [begin, it) */
379 stdcarr_low_copy_to_buf(*itp + delta, carr, tmp, carr->end); /* insert space and copy [it, end) */
380 free(carr->base); /* free old array */
381
382 } else {
383 *itp = mem;
384 }
385
386 carr->base = mem;
387 carr->endbase = mem + asize;
388 carr->begin = mem;
389 carr->end = mem + new_size * carr->vsize;
390 carr->cap = new_cap;
391 carr->size = new_size;
392
393 } else { /* auto-growth disallowed */
394 ret = STDEACCES;
395 goto stdcarr_low_insert_shift_end;
396 }
397
398 stdcarr_low_insert_shift_end:
399 return ret;
400 }
401
402 /************************************************************************************************
403 * stdcarr_low_erase_shift: This function determines if an erasure
404 * will require a reallocation or not. If reallocation isn't needed,
405 * it calls the specified array shift function. If reallocation is
406 * called for, it does it and copies the values to the new carray
407 * while deleting the proper elements. The boolean parameter
408 * shift_right indicates whether 'itp' points to the beginning of the
409 * erase sequence or to one past the end of the erase sequence. This
410 * parameter also determines whether we erase_shift_right or
411 * erase_shift_left.
412 ***********************************************************************************************/
413
stdcarr_low_erase_shift(stdcarr * carr,char ** itp,stdsize delta,stdsize new_size,stdbool shift_right)414 STDINLINE static void stdcarr_low_erase_shift(stdcarr *carr, char **itp, stdsize delta,
415 stdsize new_size, stdbool shift_right)
416 {
417 if (delta == 0) { /* no-op */
418 return;
419 }
420
421 /* delta != 0 -> carr->size >= 1 && carr->cap > carr->size */
422
423 if ((carr->opts & STDCARR_OPTS_NO_AUTO_SHRINK) != 0 || /* no shrinking wanted */
424 new_size > stdcarr_low_capacity(carr) || /* no shrinking necessary */
425 carr->cap == STDCARR_MIN_AUTO_ALLOC) { /* already at min alloc size */
426
427 /* label used for alloc failures from below */
428 stdcarr_low_erase_shift_fail:
429
430 if (shift_right) {
431 stdcarr_low_erase_shift_right(carr, *itp, delta, new_size);
432 *itp = stdcarr_low_forward(*itp, delta, carr->base, carr->endbase);
433
434 } else {
435 stdcarr_low_erase_shift_left(carr, *itp, delta, new_size);
436 }
437
438 } else { /* need+allowed to shrink */
439 stdsize new_cap = (new_size << 1);
440 stdsize asize;
441 char * mem;
442 char * tmp;
443 char * tmp2;
444
445 new_cap = STDMAX(new_cap, STDCARR_MIN_AUTO_ALLOC);
446 asize = new_cap * carr->vsize;
447
448 if (asize != 0) {
449
450 if ((mem = (char*) malloc(asize)) == NULL) {
451 goto stdcarr_low_erase_shift_fail; /* fallback to no realloc pathway */
452 }
453
454 if (shift_right) {
455 tmp = stdcarr_low_forward(*itp, delta, carr->base, carr->endbase);
456 *itp = stdcarr_low_copy_to_buf(mem, carr, carr->begin, *itp); /* copy [begin, it) */
457 stdcarr_low_copy_to_buf(*itp, carr, tmp, carr->end); /* copy [it + delta, end) */
458
459 } else {
460 tmp = *itp;
461 tmp2 = stdcarr_low_backward(*itp, delta, carr->base, carr->endbase);
462 *itp = stdcarr_low_copy_to_buf(mem, carr, carr->begin, tmp2); /* copy [begin, it - delta) */
463 stdcarr_low_copy_to_buf(*itp, carr, tmp, carr->end); /* copy [it, end) */
464 }
465
466 } else {
467 mem = NULL;
468 *itp = NULL;
469 }
470
471 if (carr->base != NULL) {
472 free(carr->base);
473 }
474
475 carr->base = mem;
476 carr->endbase = mem + asize;
477 carr->begin = mem;
478 carr->end = mem + new_size * carr->vsize;
479 carr->cap = new_cap;
480 carr->size = new_size;
481 }
482 }
483
484 /************************************************************************************************
485 * stdcarr_construct: Construct an initially empty circular array.
486 ***********************************************************************************************/
487
stdcarr_construct(stdcarr * carr,stdsize vsize,stduint8 opts)488 STDINLINE stdcode stdcarr_construct(stdcarr *carr, stdsize vsize, stduint8 opts)
489 {
490 stdcode ret = STDESUCCESS;
491
492 if (vsize == 0 || (opts & ~(STDCARR_OPTS_NO_AUTO_GROW | STDCARR_OPTS_NO_AUTO_SHRINK)) != 0) {
493 ret = STDEINVAL;
494 goto stdcarr_construct_fail;
495 }
496
497 carr->base = NULL;
498 carr->endbase = NULL;
499 carr->begin = NULL;
500 carr->end = NULL;
501 carr->cap = 0;
502 carr->size = 0;
503 carr->vsize = vsize;
504 carr->opts = opts;
505
506 goto stdcarr_construct_end;
507
508 /* error handling and return */
509
510 stdcarr_construct_fail:
511 carr->vsize = 0; /* make STDCARR_IS_LEGAL(carr) false */
512
513 stdcarr_construct_end:
514 return ret;
515 }
516
517 /************************************************************************************************
518 * stdcarr_copy_construct: Construct a copy of an array.
519 ***********************************************************************************************/
520
stdcarr_copy_construct(stdcarr * dst,const stdcarr * src)521 STDINLINE stdcode stdcarr_copy_construct(stdcarr *dst, const stdcarr *src)
522 {
523 stdcode ret = STDESUCCESS;
524
525 STDSAFETY_CHECK(STDCARR_IS_LEGAL(src));
526
527 *dst = *src;
528
529 if (src->base != NULL) {
530 stdsize asize = src->vsize * src->cap;
531
532 if ((dst->base = (char*) malloc(asize)) == NULL) {
533 ret = STDENOMEM;
534 goto stdcarr_copy_construct_fail;
535 }
536
537 dst->endbase = dst->base + asize;
538 dst->begin = dst->base;
539 dst->end = stdcarr_low_copy_to_buf(dst->base, src, src->begin, src->end);
540 }
541
542 goto stdcarr_copy_construct_end;
543
544 /* error handling and return */
545
546 stdcarr_copy_construct_fail:
547 dst->vsize = 0; /* make STDCARR_IS_LEGAL(dst) false */
548
549 stdcarr_copy_construct_end:
550 return ret;
551 }
552
553 /************************************************************************************************
554 * stdcarr_destruct: Reclaim a circular array's resources and invalidate it.
555 ***********************************************************************************************/
556
stdcarr_destruct(stdcarr * carr)557 STDINLINE void stdcarr_destruct(stdcarr *carr)
558 {
559 STDSAFETY_CHECK(STDCARR_IS_LEGAL(carr));
560
561 if (carr->base != NULL) {
562 free(carr->base);
563 carr->base = NULL;
564 }
565
566 carr->vsize = 0; /* make STDCARR_IS_LEGAL(carr) false */
567 }
568
569 /************************************************************************************************
570 * stdcarr_set_eq: Set 'dst' to have the same contents as 'src.'
571 ***********************************************************************************************/
572
stdcarr_set_eq(stdcarr * dst,stdcarr * src)573 STDINLINE stdcode stdcarr_set_eq(stdcarr *dst, stdcarr *src)
574 {
575 stdcode ret = STDESUCCESS;
576
577 STDSAFETY_CHECK(STDCARR_IS_LEGAL(dst) && STDCARR_IS_LEGAL(src) && dst->vsize == src->vsize);
578
579 if (dst == src) {
580 goto stdcarr_set_eq_end;
581 }
582
583 if ((ret = stdcarr_resize(dst, src->size)) != STDESUCCESS) {
584 goto stdcarr_set_eq_end;
585 }
586
587 dst->begin = dst->base;
588 dst->end = stdcarr_low_copy_to_buf(dst->begin, src, src->begin, src->end);
589
590 stdcarr_set_eq_end:
591 return ret;
592 }
593
594 /************************************************************************************************
595 * stdcarr_swap: Make 'carr1' reference 'carr2's sequence and vice versa.
596 ***********************************************************************************************/
597
stdcarr_swap(stdcarr * carr1,stdcarr * carr2)598 STDINLINE void stdcarr_swap(stdcarr *carr1, stdcarr *carr2)
599 {
600 stdcarr cpy;
601
602 STDSAFETY_CHECK(STDCARR_IS_LEGAL(carr1) && STDCARR_IS_LEGAL(carr2));
603
604 STDSWAP(*carr1, *carr2, cpy);
605 }
606
607 /************************************************************************************************
608 * stdcarr_begin: Get an iterator to the beginning of a circular array.
609 ***********************************************************************************************/
610
stdcarr_begin(const stdcarr * carr,stdit * it)611 STDINLINE stdit *stdcarr_begin(const stdcarr *carr, stdit *it)
612 {
613 STDSAFETY_CHECK(STDCARR_IS_LEGAL(carr));
614
615 it->type_id = STDCARR_IT_ID;
616 it->impl.carr.val = (char*) carr->begin;
617 it->impl.carr.base = (char*) carr->base;
618 it->impl.carr.endbase = (char*) carr->endbase;
619 it->impl.carr.begin = (char*) carr->begin;
620 it->impl.carr.end = (char*) carr->end;
621 it->impl.carr.vsize = carr->vsize;
622
623 return it;
624 }
625
626 /************************************************************************************************
627 * stdcarr_last: Get an iterator to the last entry of a circular array.
628 ***********************************************************************************************/
629
stdcarr_last(const stdcarr * carr,stdit * it)630 STDINLINE stdit *stdcarr_last(const stdcarr *carr, stdit *it)
631 {
632 STDBOUNDS_CHECK(carr->size != 0);
633
634 return stdcarr_it_prev(stdcarr_end(carr, it));
635 }
636
637 /************************************************************************************************
638 * stdcarr_end: Get an iterator to the sentinel end entry of a circular array.
639 ***********************************************************************************************/
640
stdcarr_end(const stdcarr * carr,stdit * it)641 STDINLINE stdit *stdcarr_end(const stdcarr *carr, stdit *it)
642 {
643 STDSAFETY_CHECK(STDCARR_IS_LEGAL(carr));
644
645 it->type_id = STDCARR_IT_ID;
646 it->impl.carr.val = (char*) carr->end;
647 it->impl.carr.base = (char*) carr->base;
648 it->impl.carr.endbase = (char*) carr->endbase;
649 it->impl.carr.begin = (char*) carr->begin;
650 it->impl.carr.end = (char*) carr->end;
651 it->impl.carr.vsize = carr->vsize;
652
653 return it;
654 }
655
656 /************************************************************************************************
657 * stdcarr_get: Get an iterator to the 'elem_num'th entry in a circular array.
658 ***********************************************************************************************/
659
stdcarr_get(const stdcarr * carr,stdit * it,stdsize elem_num)660 STDINLINE stdit *stdcarr_get(const stdcarr *carr, stdit *it, stdsize elem_num)
661 {
662 STDBOUNDS_CHECK(elem_num <= carr->size);
663
664 return stdcarr_it_advance(stdcarr_begin(carr, it), elem_num);
665 }
666
667 /************************************************************************************************
668 * stdcarr_is_begin: Return whether or not an iterator references the begin of an array.
669 ***********************************************************************************************/
670
stdcarr_is_begin(const stdcarr * carr,const stdit * it)671 STDINLINE stdbool stdcarr_is_begin(const stdcarr *carr, const stdit *it)
672 {
673 STDSAFETY_CHECK(STDCARR_IS_LEGAL(carr) && STDIT_CARR_IS_LEGAL(it) && STDCARR_IT_IS_LEGAL(carr, &it->impl.carr));
674
675 return it->impl.carr.val == carr->begin;
676 }
677
678 /************************************************************************************************
679 * stdcarr_is_end: Return whether or not an iterator references the end of an array.
680 ***********************************************************************************************/
681
stdcarr_is_end(const stdcarr * carr,const stdit * it)682 STDINLINE stdbool stdcarr_is_end(const stdcarr *carr, const stdit *it)
683 {
684 STDSAFETY_CHECK(STDCARR_IS_LEGAL(carr) && STDIT_CARR_IS_LEGAL(it) && STDCARR_IT_IS_LEGAL(carr, &it->impl.carr));
685
686 return it->impl.carr.val == carr->end;
687 }
688
689 /************************************************************************************************
690 * stdcarr_rank: Returns the 0-based rank of an iterator.
691 ***********************************************************************************************/
692
stdcarr_rank(const stdcarr * carr,const stdit * it)693 STDINLINE stdsize stdcarr_rank(const stdcarr *carr, const stdit *it)
694 {
695 stdsize rank;
696
697 STDSAFETY_CHECK(STDCARR_IS_LEGAL(carr) && STDIT_CARR_IS_LEGAL(it) && STDCARR_IT_IS_LEGAL(carr, &it->impl.carr));
698
699 if (it->impl.carr.val >= carr->begin) {
700 rank = (stdsize) (it->impl.carr.val - carr->begin) / carr->vsize;
701
702 } else {
703 rank = (stdsize) ((carr->endbase - carr->begin) + (it->impl.carr.val - carr->base)) / carr->vsize;
704 }
705
706 return rank;
707 }
708
709 /************************************************************************************************
710 * stdcarr_size: Return the number of elements in an array.
711 ***********************************************************************************************/
712
stdcarr_size(const stdcarr * carr)713 STDINLINE stdsize stdcarr_size(const stdcarr *carr)
714 {
715 STDSAFETY_CHECK(STDCARR_IS_LEGAL(carr));
716
717 return carr->size;
718 }
719
720 /************************************************************************************************
721 * stdcarr_empty: Return whether or not an array's size is zero.
722 ***********************************************************************************************/
723
stdcarr_empty(const stdcarr * carr)724 STDINLINE stdbool stdcarr_empty(const stdcarr *carr)
725 {
726 STDSAFETY_CHECK(STDCARR_IS_LEGAL(carr));
727
728 return carr->size == 0;
729 }
730
731 /************************************************************************************************
732 * stdcarr_high_capacity: Return the size beyond which 'carr' will
733 * (try to) grow.
734 ***********************************************************************************************/
735
stdcarr_high_capacity(const stdcarr * carr)736 STDINLINE stdsize stdcarr_high_capacity(const stdcarr *carr)
737 {
738 STDSAFETY_CHECK(STDCARR_IS_LEGAL(carr));
739
740 return (carr->cap != 0 ? carr->cap - 1 : 0); /* -1 for unusable sentinel position */
741 }
742
743 /************************************************************************************************
744 * stdcarr_low_capacity: Return the size at (or below) which 'carr'
745 * will (try to) shrink.
746 ***********************************************************************************************/
747
stdcarr_low_capacity(const stdcarr * carr)748 STDINLINE stdsize stdcarr_low_capacity(const stdcarr *carr)
749 {
750 STDSAFETY_CHECK(STDCARR_IS_LEGAL(carr));
751
752 return (carr->cap >> 2);
753 }
754
755 /************************************************************************************************
756 * stdcarr_max_size: Return the theoretical maximum number of elements 'carr' could hold.
757 ***********************************************************************************************/
758
stdcarr_max_size(const stdcarr * carr)759 STDINLINE stdsize stdcarr_max_size(const stdcarr *carr)
760 {
761 STDSAFETY_CHECK(STDCARR_IS_LEGAL(carr));
762
763 return STDSIZE_MAX / carr->vsize;
764 }
765
766 /************************************************************************************************
767 * stdcarr_val_size: Return the size in bytes of the values 'carr' contains.
768 ***********************************************************************************************/
769
stdcarr_val_size(const stdcarr * carr)770 STDINLINE stdsize stdcarr_val_size(const stdcarr *carr)
771 {
772 STDSAFETY_CHECK(STDCARR_IS_LEGAL(carr));
773
774 return carr->vsize;
775 }
776
777 /************************************************************************************************
778 * stdcarr_resize: Resize an array to contain 'num_elems' elements.
779 ***********************************************************************************************/
780
stdcarr_resize(stdcarr * carr,stdsize num_elems)781 STDINLINE stdcode stdcarr_resize(stdcarr *carr, stdsize num_elems)
782 {
783 stdcode ret = STDESUCCESS;
784 char * ptr = carr->end;
785
786 STDSAFETY_CHECK(STDCARR_IS_LEGAL(carr));
787
788 if (num_elems > carr->size) {
789 ret = stdcarr_low_insert_shift(carr, &ptr, (num_elems - carr->size) * carr->vsize, num_elems, STDTRUE);
790
791 } else if (num_elems < carr->size) {
792 stdcarr_low_erase_shift(carr, &ptr, (carr->size - num_elems) * carr->vsize, num_elems, STDFALSE);
793 }
794
795 return ret;
796 }
797
798 /************************************************************************************************
799 * stdcarr_clear: Set the size of 'carr' to zero.
800 ***********************************************************************************************/
801
stdcarr_clear(stdcarr * carr)802 STDINLINE void stdcarr_clear(stdcarr *carr)
803 {
804 stdcarr_resize(carr, 0);
805 }
806
807 /************************************************************************************************
808 * stdcarr_set_capacity: Set the capacity of 'carr' to num_elems.
809 * Ignores all auto-allocation considerations.
810 ***********************************************************************************************/
811
stdcarr_set_capacity(stdcarr * carr,stdsize num_elems)812 STDINLINE stdcode stdcarr_set_capacity(stdcarr *carr, stdsize num_elems)
813 {
814 stdcode ret = STDESUCCESS;
815
816 if (num_elems != stdcarr_high_capacity(carr)) {
817
818 if (num_elems != 0) {
819 stdsize new_cap = num_elems + 1; /* +1 for sentinel end position */
820 stdsize asize = new_cap * carr->vsize;
821 char * mem;
822
823 /* alloc table */
824
825 if ((mem = (char*) malloc(asize)) == NULL) {
826 ret = STDENOMEM;
827 goto stdcarr_set_capacity_end;
828 }
829
830 /* truncate if requested capacity is smaller than size */
831
832 if (num_elems < carr->size) {
833 carr->end = stdcarr_low_forward(carr->begin, num_elems * carr->vsize, carr->base, carr->endbase);
834 carr->size = num_elems;
835 }
836
837 /* copy to new table */
838
839 stdcarr_low_copy_to_buf(mem, carr, carr->begin, carr->end);
840
841 /* free old table */
842
843 if (carr->base != NULL) {
844 free(carr->base);
845 }
846
847 carr->base = mem;
848 carr->endbase = mem + asize;
849 carr->begin = mem;
850 carr->end = mem + carr->size * carr->vsize;
851 carr->cap = new_cap;
852
853 } else {
854
855 if (carr->base != NULL) {
856 free(carr->base);
857 }
858
859 carr->base = NULL;
860 carr->endbase = NULL;
861 carr->begin = NULL;
862 carr->end = NULL;
863 carr->cap = 0;
864 carr->size = 0;
865 }
866 }
867
868 stdcarr_set_capacity_end:
869 return ret;
870 }
871
872 /************************************************************************************************
873 * stdcarr_reserve: Ensures 'carr' can contain 'num_elems' elements
874 * without any additional reallocations. Ignores all auto allocation
875 * considerations.
876 ***********************************************************************************************/
877
stdcarr_reserve(stdcarr * carr,stdsize num_elems)878 STDINLINE stdcode stdcarr_reserve(stdcarr *carr, stdsize num_elems)
879 {
880 stdcode ret = STDESUCCESS;
881
882 if (num_elems > stdcarr_high_capacity(carr)) {
883 ret = stdcarr_set_capacity(carr, num_elems);
884 }
885
886 return ret;
887 }
888
889 /************************************************************************************************
890 * stdcarr_shrink_fit: Sets 'carr's capacity to 'carr's size. Ignores
891 * all auto allocation considerations.
892 ***********************************************************************************************/
893
stdcarr_shrink_fit(stdcarr * carr)894 STDINLINE stdcode stdcarr_shrink_fit(stdcarr *carr)
895 {
896 return stdcarr_set_capacity(carr, carr->size);
897 }
898
899 /************************************************************************************************
900 * stdcarr_push_front: Push a copy of 'val' onto the beginning of
901 * 'carr.'
902 ***********************************************************************************************/
903
stdcarr_push_front(stdcarr * carr,const void * val)904 STDINLINE stdcode stdcarr_push_front(stdcarr *carr, const void *val)
905 {
906 stdit it;
907
908 return stdcarr_insert(carr, stdcarr_begin(carr, &it), val);
909 }
910
911 /************************************************************************************************
912 * stdcarr_push_front_n: Push copies of the 'num_push' values in
913 * 'vals' onto the beginning of 'carr.'
914 ***********************************************************************************************/
915
stdcarr_push_front_n(stdcarr * carr,const void * vals,stdsize num_push)916 STDINLINE stdcode stdcarr_push_front_n(stdcarr *carr, const void *vals, stdsize num_push)
917 {
918 stdit it;
919
920 return stdcarr_insert_n(carr, stdcarr_begin(carr, &it), vals, num_push);
921 }
922
923 /************************************************************************************************
924 * stdcarr_push_front_seq: Push a sequence of elements onto the
925 * beginning of 'carr.'
926 ***********************************************************************************************/
927
stdcarr_push_front_seq(stdcarr * carr,const stdit * b,const stdit * e)928 STDINLINE stdcode stdcarr_push_front_seq(stdcarr *carr, const stdit *b, const stdit *e)
929 {
930 stdit it;
931
932 return stdcarr_insert_seq(carr, stdcarr_begin(carr, &it), b, e);
933 }
934
935 /************************************************************************************************
936 * stdcarr_push_front_seq_n: Push a sequence of elements onto the
937 * beginning of 'carr.'
938 ***********************************************************************************************/
939
stdcarr_push_front_seq_n(stdcarr * carr,const stdit * b,stdsize num_push)940 STDINLINE stdcode stdcarr_push_front_seq_n(stdcarr *carr, const stdit *b, stdsize num_push)
941 {
942 stdit it;
943
944 return stdcarr_insert_seq_n(carr, stdcarr_begin(carr, &it), b, num_push);
945 }
946
947 /************************************************************************************************
948 * stdcarr_push_front_rep: Push 'num_push' copies of 'val' onto
949 * the beginning of 'carr.'
950 ***********************************************************************************************/
951
stdcarr_push_front_rep(stdcarr * carr,const void * val,stdsize num_times)952 STDINLINE stdcode stdcarr_push_front_rep(stdcarr *carr, const void *val, stdsize num_times)
953 {
954 stdit it;
955
956 return stdcarr_insert_rep(carr, stdcarr_begin(carr, &it), val, num_times);
957 }
958
959 /************************************************************************************************
960 * stdcarr_pop_front: Pop an element off of the beginning of an array.
961 ***********************************************************************************************/
962
stdcarr_pop_front(stdcarr * carr)963 STDINLINE void stdcarr_pop_front(stdcarr *carr)
964 {
965 stdcarr_pop_front_n(carr, 1);
966 }
967
968 /************************************************************************************************
969 * stdcarr_pop_front_n: Pop multiple elements off of the beginning of
970 * an array.
971 ***********************************************************************************************/
972
stdcarr_pop_front_n(stdcarr * carr,stdsize num_pop)973 STDINLINE void stdcarr_pop_front_n(stdcarr *carr, stdsize num_pop)
974 {
975 char * begin_ptr = carr->begin;
976
977 STDSAFETY_CHECK(STDCARR_IS_LEGAL(carr));
978 STDBOUNDS_CHECK(num_pop <= carr->size);
979
980 stdcarr_low_erase_shift(carr, &begin_ptr, num_pop * carr->vsize, carr->size - num_pop, STDTRUE);
981 }
982
983 /************************************************************************************************
984 * stdcarr_push_back: Push a copy of 'val' onto the end of 'carr.'
985 ***********************************************************************************************/
986
stdcarr_push_back(stdcarr * carr,const void * val)987 STDINLINE stdcode stdcarr_push_back(stdcarr *carr, const void *val)
988 {
989 stdit it;
990
991 return stdcarr_insert(carr, stdcarr_end(carr, &it), val);
992 }
993
994 /************************************************************************************************
995 * stdcarr_push_back_n: Push copies of the 'num_push' values in 'vals'
996 * onto the end of 'carr.'
997 ***********************************************************************************************/
998
stdcarr_push_back_n(stdcarr * carr,const void * vals,stdsize num_push)999 STDINLINE stdcode stdcarr_push_back_n(stdcarr *carr, const void *vals, stdsize num_push)
1000 {
1001 stdit it;
1002
1003 return stdcarr_insert_n(carr, stdcarr_end(carr, &it), vals, num_push);
1004 }
1005
1006 /************************************************************************************************
1007 * stdcarr_push_back_seq: Push a sequence of elements onto the
1008 * beginning of 'carr.'
1009 ***********************************************************************************************/
1010
stdcarr_push_back_seq(stdcarr * carr,const stdit * b,const stdit * e)1011 STDINLINE stdcode stdcarr_push_back_seq(stdcarr *carr, const stdit *b, const stdit *e)
1012 {
1013 stdit it;
1014
1015 return stdcarr_insert_seq(carr, stdcarr_end(carr, &it), b, e);
1016 }
1017
1018 /************************************************************************************************
1019 * stdcarr_push_back_seq_n: Push a sequence of elements onto the
1020 * beginning of 'carr.'
1021 ***********************************************************************************************/
1022
stdcarr_push_back_seq_n(stdcarr * carr,const stdit * b,stdsize num_push)1023 STDINLINE stdcode stdcarr_push_back_seq_n(stdcarr *carr, const stdit *b, stdsize num_push)
1024 {
1025 stdit it;
1026
1027 return stdcarr_insert_seq_n(carr, stdcarr_end(carr, &it), b, num_push);
1028 }
1029
1030 /************************************************************************************************
1031 * stdcarr_push_back_rep: Push 'num_push' copies of 'val' onto the end
1032 * of 'carr.'
1033 ***********************************************************************************************/
1034
stdcarr_push_back_rep(stdcarr * carr,const void * val,stdsize num_times)1035 STDINLINE stdcode stdcarr_push_back_rep(stdcarr *carr, const void *val, stdsize num_times)
1036 {
1037 stdit it;
1038
1039 return stdcarr_insert_rep(carr, stdcarr_end(carr, &it), val, num_times);
1040 }
1041
1042 /************************************************************************************************
1043 * stdcarr_pop_back: Pop an element off of the end of an array.
1044 ***********************************************************************************************/
1045
stdcarr_pop_back(stdcarr * carr)1046 STDINLINE void stdcarr_pop_back(stdcarr *carr)
1047 {
1048 stdcarr_pop_back_n(carr, 1);
1049 }
1050
1051 /************************************************************************************************
1052 * stdcarr_pop_back_n: Pop multiple elements off of the end of an
1053 * array.
1054 ***********************************************************************************************/
1055
stdcarr_pop_back_n(stdcarr * carr,stdsize num_pop)1056 STDINLINE void stdcarr_pop_back_n(stdcarr *carr, stdsize num_pop)
1057 {
1058 char * end_ptr = carr->end;
1059
1060 STDSAFETY_CHECK(STDCARR_IS_LEGAL(carr));
1061 STDBOUNDS_CHECK(num_pop <= carr->size);
1062
1063 stdcarr_low_erase_shift(carr, &end_ptr, num_pop * carr->vsize, carr->size - num_pop, STDFALSE);
1064 }
1065
1066 /************************************************************************************************
1067 * stdcarr_insert: Insert a copy of 'val' into 'carr' before 'it.'
1068 ***********************************************************************************************/
1069
stdcarr_insert(stdcarr * carr,stdit * it,const void * val)1070 STDINLINE stdcode stdcarr_insert(stdcarr *carr, stdit *it, const void *val)
1071 {
1072 return stdcarr_insert_n(carr, it, val, 1);
1073 }
1074
1075 /************************************************************************************************
1076 * stdcarr_insert_n: Insert copies of the 'num_insert' elements in
1077 * 'vals' into 'carr' before 'it.'
1078 ***********************************************************************************************/
1079
stdcarr_insert_n(stdcarr * carr,stdit * it,const void * vals,stdsize num_insert)1080 STDINLINE stdcode stdcarr_insert_n(stdcarr *carr, stdit *it, const void *vals, stdsize num_insert)
1081 {
1082 stdcode ret;
1083 stdsize diff;
1084 stdsize delta;
1085 stdbool shift_right;
1086
1087 STDSAFETY_CHECK(STDCARR_IS_LEGAL(carr) && STDIT_CARR_IS_LEGAL(it) && STDCARR_IT_IS_LEGAL(carr, &it->impl.carr));
1088
1089 delta = num_insert * carr->vsize;
1090
1091 /* compute whether it is roughly cheaper to shift right or left if we don't realloc */
1092
1093 shift_right = STDCARR_INS_SHIFT_RIGHT(carr, it->impl.carr.val);
1094
1095 /* make room for the insertion */
1096
1097 if ((ret = stdcarr_low_insert_shift(carr, &it->impl.carr.val, delta,
1098 carr->size + num_insert, shift_right)) != STDESUCCESS) {
1099 goto stdcarr_insert_n_end;
1100 }
1101
1102 /* copy the elements */
1103
1104 diff = (stdsize) (carr->endbase - it->impl.carr.val); /* open space b4 wrap around */
1105
1106 if (diff >= delta) { /* vals fits in open space b4 wrap around */
1107 memcpy(it->impl.carr.val, vals, delta);
1108
1109 } else { /* wrap data around */
1110 memcpy(it->impl.carr.val, vals, diff);
1111 memcpy(carr->base, (char*) vals + diff, (stdsize) (delta - diff));
1112 }
1113
1114 stdcarr_insert_n_end:
1115 return ret;
1116 }
1117
1118 /************************************************************************************************
1119 * stdcarr_insert_seq: Insert a sequence of elements into 'carr' before
1120 * 'it.'
1121 ***********************************************************************************************/
1122
stdcarr_insert_seq(stdcarr * carr,stdit * it,const stdit * b,const stdit * e)1123 STDINLINE stdcode stdcarr_insert_seq(stdcarr *carr, stdit *it, const stdit *b, const stdit *e)
1124 {
1125 stdcode ret;
1126 stdssize num_insert;
1127
1128 if ((num_insert = stdit_distance(b, e)) < 0) { /* calc how many elements in [b, e) */
1129 ret = STDEINVAL;
1130 goto stdcarr_insert_seq_end;
1131 }
1132
1133 ret = stdcarr_insert_seq_n(carr, it, b, num_insert);
1134
1135 stdcarr_insert_seq_end:
1136 return ret;
1137 }
1138
1139 /************************************************************************************************
1140 * stdcarr_insert_seq_n: Insert a sequence of elements into 'carr' before
1141 * 'it.'
1142 ***********************************************************************************************/
1143
stdcarr_insert_seq_n(stdcarr * carr,stdit * it,const stdit * b,stdsize num_insert)1144 STDINLINE stdcode stdcarr_insert_seq_n(stdcarr *carr, stdit *it, const stdit *b, stdsize num_insert)
1145 {
1146 stdcode ret;
1147 stdsize delta;
1148 stdbool shift_right;
1149 char * dst_it;
1150 stdit src_it;
1151
1152 STDSAFETY_CHECK(STDCARR_IS_LEGAL(carr) && STDIT_CARR_IS_LEGAL(it) && STDCARR_IT_IS_LEGAL(carr, &it->impl.carr));
1153
1154 delta = num_insert * carr->vsize;
1155
1156 /* compute whether it is roughly cheaper to shift right or left if we don't realloc */
1157
1158 shift_right = STDCARR_INS_SHIFT_RIGHT(carr, it->impl.carr.val);
1159
1160 /* make room for the insertion */
1161
1162 if ((ret = stdcarr_low_insert_shift(carr, &it->impl.carr.val, delta,
1163 carr->size + num_insert, shift_right)) != STDESUCCESS) {
1164 goto stdcarr_insert_seq_n_end;
1165 }
1166
1167 /* copy the elements */
1168
1169 dst_it = it->impl.carr.val;
1170 src_it = *b;
1171
1172 while (num_insert-- != 0) {
1173 memcpy(dst_it, stdit_val(&src_it), carr->vsize);
1174
1175 dst_it = stdcarr_low_forward(dst_it, carr->vsize, carr->base, carr->endbase);
1176 stdit_next(&src_it);
1177 }
1178
1179 stdcarr_insert_seq_n_end:
1180 return ret;
1181 }
1182
1183 /************************************************************************************************
1184 * stdcarr_insert_rep: Insert 'num_times' copies of 'val' into 'carr' before 'it.'
1185 ***********************************************************************************************/
1186
stdcarr_insert_rep(stdcarr * carr,stdit * it,const void * val,stdsize num_times)1187 STDINLINE stdcode stdcarr_insert_rep(stdcarr *carr, stdit *it, const void *val, stdsize num_times)
1188 {
1189 stdcode ret;
1190 stdsize delta;
1191 stdbool shift_right;
1192 char * dst_it;
1193
1194 STDSAFETY_CHECK(STDCARR_IS_LEGAL(carr) && STDIT_CARR_IS_LEGAL(it) && STDCARR_IT_IS_LEGAL(carr, &it->impl.carr));
1195
1196 delta = num_times * carr->vsize;
1197
1198 /* compute whether it is roughly cheaper to shift right or left if we don't realloc */
1199
1200 shift_right = STDCARR_INS_SHIFT_RIGHT(carr, it->impl.carr.val);
1201
1202 /* make room for the insertion */
1203
1204 if ((ret = stdcarr_low_insert_shift(carr, &it->impl.carr.val, delta,
1205 carr->size + num_times, shift_right)) != STDESUCCESS) {
1206 goto stdcarr_insert_rep_end;
1207 }
1208
1209 /* copy the elements */
1210
1211 dst_it = it->impl.carr.val;
1212
1213 while (num_times-- != 0) {
1214 memcpy(dst_it, val, carr->vsize);
1215
1216 dst_it = stdcarr_low_forward(dst_it, carr->vsize, carr->base, carr->endbase);
1217 }
1218
1219 stdcarr_insert_rep_end:
1220 return ret;
1221 }
1222
1223 /************************************************************************************************
1224 * stdcarr_erase: Erase the element pointed at by 'it' from 'carr.'
1225 ***********************************************************************************************/
1226
stdcarr_erase(stdcarr * carr,stdit * it)1227 STDINLINE void stdcarr_erase(stdcarr *carr, stdit *it)
1228 {
1229 stdcarr_erase_n(carr, it, 1);
1230 }
1231
1232 /************************************************************************************************
1233 * stdcarr_erase_n: Erase 'num_erase' elements from 'carr' starting at
1234 * 'it.'
1235 ***********************************************************************************************/
1236
stdcarr_erase_n(stdcarr * carr,stdit * it,stdsize num_erase)1237 STDINLINE void stdcarr_erase_n(stdcarr *carr, stdit *it, stdsize num_erase)
1238 {
1239 stdsize delta;
1240 stdbool shift_right;
1241
1242 STDSAFETY_CHECK(STDCARR_IS_LEGAL(carr) && STDIT_CARR_IS_LEGAL(it) && STDCARR_IT_IS_LEGAL(carr, &it->impl.carr));
1243
1244 #ifdef STDBOUNDS_CHECKS
1245 {
1246 stdit c_end;
1247
1248 stdcarr_end(carr, &c_end);
1249 STDBOUNDS_CHECK((stdsize) stdcarr_it_cmp(&c_end, it) >= num_erase);
1250 }
1251 #endif
1252
1253 delta = num_erase * carr->vsize;
1254
1255 /* determine whether it is roughly cheaper to shift right or left if we don't realloc */
1256
1257 shift_right = STDCARR_ERS_SHIFT_RIGHT(carr, it->impl.carr.val, num_erase);
1258
1259 /* if we are shifting left, advance 'it' to point to end of erasure */
1260
1261 if (!shift_right) {
1262 it->impl.carr.val = stdcarr_low_forward(it->impl.carr.val, delta, carr->base, carr->endbase);
1263 }
1264
1265 stdcarr_low_erase_shift(carr, &it->impl.carr.val, delta, carr->size - num_erase, shift_right);
1266 }
1267
1268 /************************************************************************************************
1269 * stdcarr_erase_seq: Erase a sequence of elements from 'carr.'
1270 ***********************************************************************************************/
1271
stdcarr_erase_seq(stdcarr * carr,stdit * b,stdit * e)1272 STDINLINE void stdcarr_erase_seq(stdcarr *carr, stdit *b, stdit *e)
1273 {
1274 stdssize diff = stdcarr_it_cmp(e, b);
1275
1276 STDSAFETY_CHECK(diff >= 0);
1277
1278 stdcarr_erase_n(carr, b, diff);
1279 *e = *b;
1280 }
1281
1282 /************************************************************************************************
1283 * stdcarr_get_opts: Get the options of an array.
1284 ***********************************************************************************************/
1285
stdcarr_get_opts(const stdcarr * carr)1286 STDINLINE stduint8 stdcarr_get_opts(const stdcarr *carr)
1287 {
1288 STDSAFETY_CHECK(STDCARR_IS_LEGAL(carr));
1289
1290 return carr->opts;
1291 }
1292
1293 /************************************************************************************************
1294 * stdcarr_set_opts: Set the options of an array.
1295 ***********************************************************************************************/
1296
stdcarr_set_opts(stdcarr * carr,stduint8 opts)1297 STDINLINE stdcode stdcarr_set_opts(stdcarr *carr, stduint8 opts)
1298 {
1299 stdcode ret = STDESUCCESS;
1300
1301 STDSAFETY_CHECK(STDCARR_IS_LEGAL(carr));
1302
1303 if ((opts & ~(STDCARR_OPTS_NO_AUTO_GROW | STDCARR_OPTS_NO_AUTO_SHRINK)) != 0) {
1304 ret = STDEINVAL;
1305 goto stdcarr_set_opts_end;
1306 }
1307
1308 carr->opts = opts;
1309
1310 stdcarr_set_opts_end:
1311 return ret;
1312 }
1313
1314 /************************************************************************************************
1315 * stdcarr_it_val: Get a pointer to the element to which 'it' refers.
1316 ***********************************************************************************************/
1317
stdcarr_it_val(const stdit * it)1318 STDINLINE void *stdcarr_it_val(const stdit *it)
1319 {
1320 STDSAFETY_CHECK(STDIT_CARR_IS_LEGAL(it));
1321
1322 return it->impl.carr.val;
1323 }
1324
1325 /************************************************************************************************
1326 * stdcarr_it_val_size: Return the size in bytes of the value type
1327 * 'it' references.
1328 ***********************************************************************************************/
1329
stdcarr_it_val_size(const stdit * it)1330 STDINLINE stdsize stdcarr_it_val_size(const stdit *it)
1331 {
1332 STDSAFETY_CHECK(STDIT_CARR_IS_LEGAL(it));
1333
1334 return it->impl.carr.vsize;
1335 }
1336
1337 /************************************************************************************************
1338 * stdcarr_it_eq: Compare two iterators for equality (refer to same element).
1339 ***********************************************************************************************/
1340
stdcarr_it_eq(const stdit * it1,const stdit * it2)1341 STDINLINE stdbool stdcarr_it_eq(const stdit *it1, const stdit *it2)
1342 {
1343 STDSAFETY_CHECK(STDIT_CARR_IS_LEGAL(it1) && STDIT_CARR_IS_LEGAL(it2) &&
1344 it1->impl.carr.base == it2->impl.carr.base &&
1345 it1->impl.carr.endbase == it2->impl.carr.endbase &&
1346 it1->impl.carr.begin == it2->impl.carr.begin &&
1347 it1->impl.carr.end == it2->impl.carr.end &&
1348 it1->impl.carr.vsize == it2->impl.carr.vsize);
1349
1350 return it1->impl.carr.val == it2->impl.carr.val;
1351 }
1352
1353 /************************************************************************************************
1354 * stdcarr_it_cmp: Compare two iterators for rank difference.
1355 ***********************************************************************************************/
1356
stdcarr_it_cmp(const stdit * it_gen1,const stdit * it_gen2)1357 STDINLINE stdssize stdcarr_it_cmp(const stdit *it_gen1, const stdit *it_gen2)
1358 {
1359 stdssize ret;
1360 const stdcarr_it * it1 = &it_gen1->impl.carr;
1361 const stdcarr_it * it2 = &it_gen2->impl.carr;
1362
1363 STDSAFETY_CHECK(STDIT_CARR_IS_LEGAL(it_gen1) && STDIT_CARR_IS_LEGAL(it_gen2) &&
1364 it1->base == it2->base &&
1365 it1->endbase == it2->endbase &&
1366 it1->begin == it2->begin &&
1367 it1->end == it2->end &&
1368 it1->vsize == it2->vsize);
1369
1370 if (it1->val >= it1->begin) {
1371 ret = (it2->val >= it1->begin ? it1->val - it2->val : (it1->val - it1->endbase) + (it1->base - it2->val));
1372
1373 } else {
1374 ret = (it2->val < it1->begin ? it1->val - it2->val : (it1->endbase - it2->val) + (it1->val - it1->base));
1375 }
1376
1377 return ret / it1->vsize;
1378 }
1379
1380 /************************************************************************************************
1381 * stdcarr_it_next: Advance 'it' by one position towards end.
1382 ***********************************************************************************************/
1383
stdcarr_it_next(stdit * it)1384 STDINLINE stdit *stdcarr_it_next(stdit *it)
1385 {
1386 STDSAFETY_CHECK(STDIT_CARR_IS_LEGAL(it));
1387 STDBOUNDS_CHECK(it->impl.carr.val != it->impl.carr.end);
1388
1389 it->impl.carr.val = stdcarr_low_forward(it->impl.carr.val, it->impl.carr.vsize,
1390 it->impl.carr.base, it->impl.carr.endbase);
1391
1392 return it;
1393 }
1394
1395 /************************************************************************************************
1396 * stdcarr_it_advance: Advance 'it' by 'num_advance' positions towards end.
1397 ***********************************************************************************************/
1398
stdcarr_it_advance(stdit * it,stdsize num_advance)1399 STDINLINE stdit *stdcarr_it_advance(stdit *it, stdsize num_advance)
1400 {
1401 STDSAFETY_CHECK(STDIT_CARR_IS_LEGAL(it));
1402 STDBOUNDS_CHECK(it->impl.carr.val <= it->impl.carr.end ?
1403 (stdsize) (it->impl.carr.end - it->impl.carr.val) <= num_advance * it->impl.carr.vsize :
1404 (stdsize) (it->impl.carr.endbase - it->impl.carr.val) + (it->impl.carr.end - it->impl.carr.base) <= num_advance * it->impl.carr.vsize);
1405
1406 it->impl.carr.val = stdcarr_low_forward(it->impl.carr.val, it->impl.carr.vsize * num_advance,
1407 it->impl.carr.base, it->impl.carr.endbase);
1408
1409 return it;
1410 }
1411
1412
1413 /************************************************************************************************
1414 * stdcarr_it_prev: Advance 'it' by one position towards begin.
1415 ***********************************************************************************************/
1416
stdcarr_it_prev(stdit * it)1417 STDINLINE stdit *stdcarr_it_prev(stdit *it)
1418 {
1419 STDSAFETY_CHECK(STDIT_CARR_IS_LEGAL(it));
1420 STDBOUNDS_CHECK(it->impl.carr.val != it->impl.carr.begin);
1421
1422 it->impl.carr.val = stdcarr_low_backward(it->impl.carr.val, it->impl.carr.vsize,
1423 it->impl.carr.base, it->impl.carr.endbase);
1424
1425 return it;
1426 }
1427
1428 /************************************************************************************************
1429 * stdcarr_it_retreat: Advance 'it' by 'num_retreat' positions towards begin.
1430 ***********************************************************************************************/
1431
stdcarr_it_retreat(stdit * it,stdsize num_retreat)1432 STDINLINE stdit *stdcarr_it_retreat(stdit *it, stdsize num_retreat)
1433 {
1434 STDSAFETY_CHECK(STDIT_CARR_IS_LEGAL(it));
1435 STDBOUNDS_CHECK(it->impl.carr.val >= it->impl.carr.begin ?
1436 (stdsize) (it->impl.carr.val - it->impl.carr.begin) <= num_retreat * it->impl.carr.vsize :
1437 (stdsize) (it->impl.carr.val - it->impl.carr.base) + (it->impl.carr.endbase - it->impl.carr.begin) <= num_retreat * it->impl.carr.vsize);
1438
1439 it->impl.carr.val = stdcarr_low_backward(it->impl.carr.val, it->impl.carr.vsize * num_retreat,
1440 it->impl.carr.base, it->impl.carr.endbase);
1441
1442 return it;
1443 }
1444
1445 /************************************************************************************************
1446 * stdcarr_it_offset: Advance 'it' by 'offset' positions towards end.
1447 ***********************************************************************************************/
1448
stdcarr_it_offset(stdit * it,stdssize offset)1449 STDINLINE stdit *stdcarr_it_offset(stdit *it, stdssize offset)
1450 {
1451 return (offset >= 0 ? stdcarr_it_advance(it, (stdsize) offset) : stdcarr_it_retreat(it, (stdsize) -offset));
1452 }
1453
1454 #ifdef __cplusplus
1455 }
1456 #endif
1457