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