qLibc
qvector.c
Go to the documentation of this file.
1/******************************************************************************
2 * qLibc
3 *
4 * Copyright (c) 2010-2015 Seungyoung Kim.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright notice,
11 * this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright notice,
13 * this list of conditions and the following disclaimer in the documentation
14 * and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 *****************************************************************************/
28/* This code is written and updated by following people and released under
29 * the same license as above qLibc license.
30 * Copyright (c) 2015 Zhenjiang Xie - https://github.com/Charles0429
31 *****************************************************************************/
32
33/**
34 * @file qvector.c Vector container implementation.
35 *
36 * qvector container is a vector container implementation
37 * qvector provides uniformly named methods to add, get, pop and remove an
38 * element at the beginning and end of the vector.
39 *
40 * @code
41 * [Conceptional Data Structure Diagram]
42 *
43 * DATA [ C ][ B ][ A ]
44 * (positive index) 0 1 2
45 * (negative index) -3 -2 -1
46 *
47 * @encode
48 *
49 * @code
50 * //create a vector
51 * qvector_t *vector = qvector(QVECTOR_THREADSAFE, 3, sizeof(int));
52 *
53 * //insert elements
54 * vector->addlast(vector, 100);
55 * vector->addlast(vector, 101);
56 * vector->addlast(vector, 102);
57 *
58 * //get
59 * void *e1 = vector->getfirst(vector, true); //malloced
60 * void *e3 = vector->getlast(vector, false); //not malloced
61 * (...omit...)
62 * free(e1);
63 *
64 * //pop (get and remove)
65 * void *e2 = vector->popat(vector, 1); //get malloced copy
66 * (...omit...)
67 * free(e2);
68 *
69 * //debug output
70 * vector->debug(vector, stdout, true);
71 *
72 * //remove all the elements
73 * vector->clear(vector);
74 *
75 * //free vector object
76 * vector->free(vector);
77 * @endcode
78 */
79
80#include <stdio.h>
81#include <string.h>
82#include <errno.h>
83#include <stdbool.h>
84#include "qinternal.h"
85#include "containers/qvector.h"
86
87#ifndef _DOXGEN_SKIP
88
89static void *get_at(qvector_t *vector, int index, bool newmem);
90static bool remove_at(qvector_t *vector, int index);
91
92#endif
93
94/**
95 * Create new qvector_t container
96 *
97 * @param max max number of elements
98 * @param objsize size of each element
99 * @param options combination of initialization options.
100 *
101 * @return a pointer of malloced qvector_t container, otherwise returns NULL
102 * @retval errno will be set in error condition.
103 * - ENOMEM : Memory allocation failure.
104 * - EINVAL : Invalid argument.
105 *
106 * @code
107 * qvector_t *vector = qvector(10, sizeof(int), 0);
108 * @endcode
109 *
110 * @note
111 * Available options:
112 * - QVECTOR_THREADSAFE - make it thread-safe.
113 * - QVECTOR_RESIZE_DOUBLE - double the size when vector is full
114 * - QVECTOR_RESIZE_LINEAR - add the size with initial num when vector is full
115 * - QVECTOR_RESIZE_EXACT - add up as much as needed
116 */
117qvector_t *qvector(size_t max, size_t objsize, int options) {
118 if (objsize == 0) {
119 errno = EINVAL;
120 return NULL;
121 }
122
123 qvector_t *vector = (qvector_t *)calloc(1, sizeof(qvector_t));
124 if (vector == NULL) {
125 errno = ENOMEM;
126 return NULL;
127 }
128
129 if (max == 0) {
130 vector->data = NULL;
131 vector->num = 0;
132 vector->max = 0;
133 vector->objsize = objsize;
134 } else {
135 void *data = malloc(max * objsize);
136 if (data == NULL) {
137 free(vector);
138 errno = ENOMEM;
139 return NULL;
140 }
141
142 vector->data = data;
143 vector->num = 0;
144 vector->objsize = objsize;
145 vector->max = max;
146 }
147
148 //handle options
149 if (options & QVECTOR_THREADSAFE) {
150 Q_MUTEX_NEW(vector->qmutex, true);
151 if (vector->qmutex == NULL) {
152 free(vector);
153 errno = ENOMEM;
154 return NULL;
155 }
156 }
157
158 vector->options = 0;
159 if (options & QVECTOR_RESIZE_DOUBLE) {
160 vector->options |= QVECTOR_RESIZE_DOUBLE;
161 } else if (options & QVECTOR_RESIZE_LINEAR) {
162 vector->options |= QVECTOR_RESIZE_LINEAR;
163 if (max == 0) {
164 vector->initnum = 1;
165 } else {
166 vector->initnum = max;
167 }
168 } else {
169 vector->options |= QVECTOR_RESIZE_EXACT;
170 }
171
172 //member methods
173 vector->addfirst = qvector_addfirst;
174 vector->addlast = qvector_addlast;
175 vector->addat = qvector_addat;
176
177 vector->getfirst = qvector_getfirst;
178 vector->getlast = qvector_getlast;
179 vector->getat = qvector_getat;
180
181 vector->setfirst = qvector_setfirst;
182 vector->setlast = qvector_setlast;
183 vector->setat = qvector_setat;
184
185 vector->popfirst = qvector_popfirst;
186 vector->poplast = qvector_poplast;
187 vector->popat = qvector_popat;
188
189 vector->removefirst = qvector_removefirst;
190 vector->removelast = qvector_removelast;
191 vector->removeat = qvector_removeat;
192
193 vector->size = qvector_size;
194 vector->resize = qvector_resize;
195
196 vector->toarray = qvector_toarray;
197
198 vector->lock = qvector_lock;
199 vector->unlock = qvector_unlock;
200
201 vector->clear = qvector_clear;
202 vector->debug = qvector_debug;
203 vector->free = qvector_free;
204
205 vector->reverse = qvector_reverse;
206 vector->getnext = qvector_getnext;
207
208 return vector;
209}
210
211/**
212 * qvector->addfirst(): Insert a element at the beginning of this vector.
213 *
214 * @param vector qvector_t container pointer.
215 * @param data a pointer which points data memory
216 *
217 * @return true if successful, otherwise returns false.
218 * @retval errno will be set in error condition.
219 *
220 * - EINVAL : Invalid argument.
221 * - ENOMEM : Memory allocation failure.
222 *
223 * @code
224 * //create a sample object.
225 * struct my_obj obj;
226 *
227 * //create a vector and add the sample object.
228 * qvector_t *vector = qvector(0, 1, sizeof(struct my_obj));
229 * vector->addfirst(vector, &obj);
230 *
231 * @endcode
232 */
233bool qvector_addfirst(qvector_t *vector, const void *data) {
234 return vector->addat(vector, 0, data);
235}
236
237/**
238 * qvector->addlast(): Insert a element at the end of this vector.
239 *
240 * @param vector qvector_t container pointer.
241 * @param data a pointer which points data memory
242 *
243 * @return true if successful, otherwise returns false.
244 * @retval errno will be set in error condition.
245 *
246 * - EINVAL : Invalid argument.
247 * - ENOMEM : Memory allocation failure.
248 *
249 * @code
250 * //create a sample object.
251 * struct my_obj obj;
252 *
253 * //create a vector and add the sample object.
254 * qvector_t *vector = qvector(0, 1, sizeof(struct my_obj));
255 * vector->addlast(vector, &obj);
256 *
257 * @endcode
258 */
259bool qvector_addlast(qvector_t *vector, const void *data) {
260 return vector->addat(vector, vector->num, data);
261}
262
263/**
264 * qvector->addat(): Inserts a element at the specified position in this
265 * vector.
266 *
267 * @param vector qvector_t container pointer
268 * @param index index at which the specified element is to be inserted
269 * @param data a pointer which points data memory
270 *
271 * @return true if successful, otherwise returns false.
272 * @retval errno will be set in errno condition.
273 *
274 * - ERANGE : Index out of range.
275 * - EINVAL : Invalid argument.
276 * - ENOMEM : Memory allocation failure.
277 *
278 * @code
279 * first last new
280 * Array [ A ][ B ][ C ]?==?[ ]
281 * (positive index) 0 1 2 3
282 * (negative index) -3 -2 -1
283 *
284 * @encode
285 *
286 * @code
287 * qvector_t *vector = qvector();
288 * vector->addat(vector, 0, &data); //same as addfirst().
289 * vector->addat(vector, 0, &data); //same as addlast().
290 *
291 * @encode
292 *
293 * @note
294 * Index starts from 0.
295 */
296bool qvector_addat(qvector_t *vector, int index, const void *data) {
297 //check arguments
298 if (data == NULL) {
299 errno = EINVAL;
300 return false;
301 }
302
303 //check index
304 if (index < 0) {
305 index += vector->num;
306 }
307 if (index > vector->num) {
308 errno = ERANGE;
309 return false;
310 }
311
312 vector->lock(vector);
313
314 //check whether the vector is full
315 if (vector->num >= vector->max) {
316 size_t newmax = vector->max + 1;
317 if (vector->options & QVECTOR_RESIZE_DOUBLE) {
318 newmax = (vector->max + 1) * 2;
319 } else if (vector->options & QVECTOR_RESIZE_LINEAR) {
320 newmax = vector->max + vector->initnum;
321 } else {
322 newmax = vector->max + 1;
323 }
324 bool result = vector->resize(vector, newmax);
325 if (result == false)
326 {
327 vector->unlock(vector);
328 errno = ENOMEM;
329 return false;
330 }
331 }
332
333 //shift data from index...(num - 1) to index + 1...num
334 int i;
335 for (i = vector->num; i > index; i--) {
336 void *dst = (unsigned char *)vector->data + vector->objsize * i;
337 void *src = (unsigned char *)vector->data + vector->objsize * (i - 1);
338
339 memcpy(dst, src, vector->objsize);
340 }
341
342 void *add = (unsigned char *)vector->data + index * vector->objsize;
343 memcpy(add, data, vector->objsize);
344 vector->num++;
345
346 vector->unlock(vector);
347 return true;
348}
349
350/**
351 * qvector->getfirst(): Returns the first element in this vector.
352 *
353 * @param vector qvector_t container pointer.
354 * @param newmem whether or not to allocate memory for the element.
355 *
356 * @return a pointer of element, otherwise returns NULL.
357 * @retval errno will be set in error condition.
358 * - ENOENT : Vector is empty.
359 * - ENOMEM : Memory allocation failure.
360 *
361 * @code
362 * size_t size;
363 * void *data = vector->getfirst(vector, true);
364 * if (data != NULL) {
365 * (...omit...)
366 * free(data);
367 * }
368 *
369 * @endcode
370 */
371void *qvector_getfirst(qvector_t *vector, bool newmem) {
372 return vector->getat(vector, 0, newmem);
373}
374
375/**
376 * qvector->getlast(): Returns the last element in this vector.
377 *
378 * @param vector qvector_t container pointer.
379 * @param newmem whether or not to allocate memory for the element.
380 *
381 * @return a pointer of element, otherwise returns NULL.
382 * @retval errno will be set in error condition.
383 * - ENOENT : Vector is empty.
384 * - ENOMEM : Memory alocation failure.
385 *
386 * @code
387 * void *data = vector->getlast(vector, true);
388 * if (data != NULL) {
389 * (...omit...)
390 * free(data);
391 * }
392 *
393 * @endcode
394 */
395void *qvector_getlast(qvector_t *vector, bool newmem) {
396 return vector->getat(vector, -1, newmem);
397}
398
399/**
400 * qvector->getat(): Returns the element at the specified position in this
401 * vector.
402 *
403 * @param vector qvector_t container pointer.
404 * @param index index at which the specified element is to access.
405 * @param newmem whether or not to allocate memory for the element.
406 *
407 * @return a pointer of element, otherwise returns NULL.
408 * @retval errno will be set in error condition.
409 * - ERANGE : Index out of range.
410 * - ENOMEM : Memory allocation failure.
411 *
412 * @code
413 * first last
414 * Array [ A ][ B ][ C ]
415 * (positive index) 0 1 2
416 * (negative index) -1 -2 -3
417 *
418 * @endcode
419 *
420 * @note
421 * Index starts from 0.
422 */
423void *qvector_getat(qvector_t *vector, int index, bool newmem) {
424 vector->lock(vector);
425 void *data = get_at(vector, index, newmem);
426 vector->unlock(vector);
427
428 return data;
429}
430
431/**
432 * qvector->setfirst(): Set the first element with a new value in this
433 * vector.
434 *
435 * @param vector qvector_t container pointer.
436 * @param data the pointer of new value.
437 *
438 * @returns true if successful, otherwise returns false.
439 * @retval errno will be set in error condition.
440 * - ENOENT : Vector is empty.
441 *
442 * @code
443 *
444 * struct my_obj obj;
445 * //set values to obj;
446 * qvector_t *vector = qvector();
447 * vector->addlast();
448 * vector->setfirst(vector, &obj);
449 *
450 * @endcode
451 */
452bool qvector_setfirst(qvector_t *vector, const void *data) {
453 return vector->setat(vector, 0, data);
454}
455
456/**
457 * qvector->setlast(): Set the last element with a new value in this
458 * vector.
459 *
460 * @param vector qvector_t container pointer.
461 * @param data the pointer of new value.
462 *
463 * @returns true if successful, otherwise returns false.
464 * @retval errno will be set in error condition.
465 * - ENOENT : Vector is empty.
466 *
467 * @code
468 *
469 * struct my_obj obj;
470 * //set values to obj;
471 * qvector_t *vector = qvector();
472 * vector->addlast();
473 * vector->setlast(vector, &obj);
474 *
475 * @endcode
476 */
477bool qvector_setlast(qvector_t *vector, const void *data) {
478 return vector->setat(vector, -1, data);
479}
480
481/**
482 * qvector->setat(): Set new value to the specified position in this
483 * vector.
484 *
485 * @param vector qvector_t container pointer
486 * @param index index at which the specifed element is to set
487 * @param data the pointer of new value to be set
488 *
489 * @return true if successful, otherwise return false.
490 * @retval errno will be set in error condition.
491 * - ERANGE : Index out of range.
492 *
493 * @code
494 *
495 * struct my_obj obj;
496 * //set values to obj;
497 * qvector_t *vector = qvector();
498 * vector->addlast();
499 * vector->setat(vector, 0, &obj);
500 *
501 * @endcode
502 */
503bool qvector_setat(qvector_t *vector, int index, const void *data) {
504 vector->lock(vector);
505 void *old_data = get_at(vector, index, false);
506 if (old_data == NULL) {
507 return false;
508 }
509 memcpy(old_data, data, vector->objsize);
510 vector->unlock(vector);
511
512 return true;
513}
514
515/**
516 * qvector->popfirst(): Returns and remove the first element in this vector.
517 *
518 * @param vector qvector_t container pointer.
519 *
520 * @return a pointer of malloced element, otherwise returns NULL.
521 * @retval errno will be set in error condition.
522 * - ENOENT : Vector is empty.
523 * - ENOMEM : Memory allocation failure.
524 */
525void *qvector_popfirst(qvector_t *vector) {
526 return vector->popat(vector, 0);
527}
528
529/**
530 * qvector->poplast(): Returns the last element of this vector.
531 *
532 * @param vector qvector_t container pointer.
533 *
534 * @return a pointer of malloced element, otherwise returns NULL.
535 * @retval errno will be set in error condition.
536 * - ENOENT : Vector is empty.
537 * - ENOMEM : Memeory allocation failure.
538 */
539void *qvector_poplast(qvector_t *vector) {
540 return vector->popat(vector, -1);
541}
542
543/**
544 * qvector->popat(): Returns and remove the element at specified
545 * position in this vector.
546 *
547 * @param vector qvector_t container pointer.
548 * @param index index at which the specified element is to be poped.
549 *
550 * @return a pointer of malloced element, otherwise returns NULL.
551 * @retval errno will be set in error condition.
552 * - ENOENT : Vector is empty.
553 * - ERANGE : Index out of range.
554 * - ENOMEM : Mmemory allocation failure.
555 *
556 * @code
557 * first last
558 * Array [ A ][ B ][ C ]
559 * (positive index) 1 2 3
560 * (negative index) -1 -2 -3
561 *
562 * @endcode
563 *
564 * @note
565 * Index starts from 0.
566 */
567void *qvector_popat(qvector_t *vector, int index) {
568 vector->lock(vector);
569 void *data = get_at(vector, index, true);
570 if (data == NULL) {
571 return NULL;
572 }
573
574 bool result = remove_at(vector, index);
575 if (result == false) {
576 free(data);
577 vector->unlock(vector);
578 return NULL;
579 }
580 vector->num--;
581
582 vector->unlock(vector);
583 return data;
584}
585
586/**
587 * qvector->removefirst(): Removes the first element in this vector.
588 *
589 * @param vector qvector_t container pointer.
590 *
591 * @return true, otherwise returns false.
592 * @retval errno will be set in error condition.
593 * - ENOENT : Vector is empty.
594 * - ERANGE : Index out of range.
595 */
596bool qvector_removefirst(qvector_t *vector) {
597 return vector->removeat(vector, 0);
598}
599
600/**
601 * qvector->removelast(): Removes the last element in this vector.
602 *
603 * @param vector qvector_t container pointer.
604 *
605 * @return true, otherwise returns false.
606 * @retval errno will be set in error condition.
607 * - ENOENT : Vector is empty.
608 * - ERANGE : Index out of range.
609 */
610bool qvector_removelast(qvector_t *vector) {
611 return vector->removeat(vector, -1);
612}
613
614/**
615 * qvector->removeat(): Removes the element at the specified position in this vector.
616 *
617 * @param vector qvector_t container pointer.
618 * @param index index at which the specified element is to be removed.
619 *
620 * @return true, otherwise returns false.
621 * @retval errno will be set in error condition.
622 * - ENOENT : Vector is empty.
623 * - ERANGE : Index out of range.
624 */
625bool qvector_removeat(qvector_t *vector, int index) {
626 vector->lock(vector);
627 bool result = remove_at(vector, index);
628 if (result) {
629 vector->num--;
630 }
631
632 vector->unlock(vector);
633
634 return result;
635}
636
637/**
638 * qvector->size(): Get the number of elements in this vector.
639 *
640 * @param vector qvector_t container pointer.
641 *
642 * @return the number of elements in this vector.
643 */
644size_t qvector_size(qvector_t *vector) {
645 return vector->num;
646}
647
648/**
649 * qvector->lock(): Enters critical section.
650 *
651 * @param vector qvector_t container pointer.
652 *
653 * @note
654 * From user side, normally locking operation is only needed when traverse all
655 * elements using qvector->getnext().
656 */
657void qvector_lock(qvector_t *vector) {
658 Q_MUTEX_ENTER(vector->qmutex);
659}
660
661/**
662 * qvector->unlock(): Leaves critical section.
663 *
664 * @param vector qvector_t container pointer.
665 */
666void qvector_unlock(qvector_t *vector) {
667 Q_MUTEX_LEAVE(vector->qmutex);
668}
669
670/**
671 * qvector->clear(): Remove all the elemnts in this vector.
672 *
673 * @param vector qvector_t container pointer.
674 */
675void qvector_clear(qvector_t *vector) {
676 vector->lock(vector);
677 vector->num = 0;
678 vector->unlock(vector);
679}
680
681/**
682 * qvector->free(): Free this vector.
683 *
684 * @param vector qvector_t container pointer.
685 */
686void qvector_free(qvector_t *vector) {
687 vector->clear(vector);
688 Q_MUTEX_DESTROY(vector->qmutex);
689
690 if (vector->data != NULL) {
691 free(vector->data);
692 }
693
694 free(vector);
695}
696
697/**
698 * qvector->debug(): Prints out stored elements for debugging purpose.
699 *
700 * @param vector qvector_t container pointer.
701 * @param out output stream FILE descriptor such like stdout, stderr.
702 *
703 * @return true if successful, otherwise returns false.
704 * @retval errno will be set in error condition.
705 * - EIO : Invalid output stream.
706 */
707bool qvector_debug(qvector_t *vector, FILE *out) {
708 if (out == NULL) {
709 errno = EIO;
710 return false;
711 }
712
713 vector->lock(vector);
714 int i;
715 for (i = 0; i < vector->num; i++) {
716 void *data = (unsigned char *)vector->data + i * vector->objsize;
717 fprintf(out, "%d=", i);
718 _q_textout(out, data, vector->objsize, MAX_HUMANOUT);
719 fprintf(out, " (%zu)\n", vector->objsize);
720 }
721 vector->unlock(vector);
722
723 return true;
724}
725
726/**
727 * qvector->resize(): Changes the allocated memory space size.
728 *
729 * @param vector qvector_t container pointer.
730 * @param newsize the new max number of elements.
731 *
732 * @retval errno will be set in error condition.
733 * - ENOMEM : Memory allocation failure.
734 *
735 * @code
736 * //create a sample object.
737 * struct my_obj obj;
738 *
739 * //create a vector which allocates 4 * sizeof(obj) memory
740 * qvector_t *vector = qvector(0, 4, sizeof(struct my_obj));
741 * //expand the memory space of vector to 8 * sizeof(obj)
742 * vector->resize(vector, 8);
743 *
744 * @endcode
745 */
746bool qvector_resize(qvector_t *vector, size_t newmax) {
747 vector->lock(vector);
748
749 if (newmax == 0) {
750 free(vector->data);
751 vector->data = NULL;
752 vector->max = 0;
753 vector->num = 0;
754 vector->objsize = 0;
755
756 vector->unlock(vector);
757 return true;
758 }
759
760 void *newdata = realloc(vector->data, newmax * vector->objsize);
761 if (newdata == NULL) {
762 errno = ENOMEM;
763 vector->unlock(vector);
764 return false;
765 }
766
767 vector->data = newdata;
768 vector->max = newmax;
769 if (vector->num > newmax) {
770 vector->num = newmax;
771 }
772
773 vector->unlock(vector);
774 return true;
775}
776
777/**
778 * qvector->toarray(): Returns an array contains all the elements in this vector.
779 * @param vector qvector_t container pointer.
780 * @param size if size is not NULL, the number of elements will be stored.
781 *
782 * @return a malloced pointer, otherwise return NULL.
783 * @retval errno wil be set in error condition.
784 * - ENOENT : Vector is empty.
785 * - ENOMEM : Memory allocation failure.
786 */
787void *qvector_toarray(qvector_t *vector, size_t *size) {
788 if (vector->num <= 0) {
789 if (size != NULL) {
790 *size = 0;
791 }
792 errno = ENOENT;
793 return NULL;
794 }
795
796 vector->lock(vector);
797
798 void *array = malloc(vector->num * vector->objsize);
799 if (array == NULL) {
800 vector->unlock(vector);
801 errno = ENOMEM;
802 return NULL;
803 }
804
805 memcpy(array, vector->data, vector->num * vector->objsize);
806
807 if (size != NULL) {
808 *size = vector->num;
809 }
810
811 vector->unlock(vector);
812 return array;
813}
814
815/**
816 * qvector->reverse(): Reverse the order of element in this vector.
817 *
818 * @param vector qvector_t container pointer.
819 *
820 * @retval will be set in error condition.
821 * - ENOMEM : Memory allocations failure.
822 */
823void qvector_reverse(qvector_t *vector) {
824 vector->lock(vector);
825
826 if (vector->num <= 1) {
827 vector->unlock(vector);
828 return;
829 }
830
831 int i;
832 int j;
833 void *tmp = malloc(vector->objsize);
834 if (tmp == NULL) {
835 errno = ENOMEM;
836 return;
837 }
838
839 for (i = 0, j = vector->num - 1; i < j; i++, j--) {
840 void *data1 = (unsigned char *)vector->data + i * vector->objsize;
841 void *data2 = (unsigned char *)vector->data + j * vector->objsize;
842
843 memcpy(tmp, data1, vector->objsize);
844 memcpy(data1, data2, vector->objsize);
845 memcpy(data2, tmp, vector->objsize);
846 }
847 free(tmp);
848
849 vector->unlock(vector);
850}
851
852/**
853 * qvector->getnext(): Get next element in this vector.
854 *
855 * @param vector qvector_t container pointer.
856 * @param obj found data will be stored in this structure.
857 * @param newmem whether or not to allocate memory for element.
858 *
859 * @return true if found, otherwise return fasle.
860 * @retval errno will be set in error condition.
861 * - ENOENT : No next element.
862 * - ENOMEM : Memory allocation failure.
863 *
864 * @note
865 * obj should be initialized with 0 by using memset() by the first call.
866 * If newmem flag is true, user should de-allocate obj.data resources.
867 *
868 * @code
869 * qvector_t *vector = qvector();
870 * (...add data into vector...)
871 *
872 * qvector_obj_t obj;
873 * memset((void *)&obj, 0, sizeof(obj));
874 * vector->lock(vector);
875 * while(vector->getnext(vector, &obj, false) == true) {
876 * printf("DATA=%s\n", obj.data);
877 * }
878 * vector->unlock(vector);
879 * @endcode
880 */
881bool qvector_getnext(qvector_t *vector, qvector_obj_t *obj, bool newmem) {
882 if (obj == NULL) {
883 return false;
884 }
885 vector->lock(vector);
886
887 if (obj->index >= vector->num) {
888 errno = ENOENT;
889 obj->data = NULL;
890 vector->unlock(vector);
891 return false;
892 }
893
894 void *data = (unsigned char *)vector->data + (obj->index) * vector->objsize;
895 if (newmem) {
896 void *dump = malloc(vector->objsize);
897 if (dump == NULL ) {
898 errno = ENOMEM;
899 obj->data = NULL;
900 vector->unlock(vector);
901 return false;
902 }
903 memcpy(dump, data, vector->objsize);
904 obj->data = dump;
905 }
906 else
907 {
908 obj->data = data;
909 }
910
911 obj->index++;
912 vector->unlock(vector);
913 return true;
914}
915
916#ifndef _DOXYGEN_SKIP
917
918static void *get_at(qvector_t *vector, int index, bool newmem) {
919 if (index < 0) {
920 index += vector->num;
921 }
922 if (index >= vector->num) {
923 if (vector->num == 0) {
924 errno = ENOENT;
925 return NULL;
926 } else {
927 errno = ERANGE;
928 return NULL;
929 }
930 }
931
932 void *src_data = (unsigned char *)vector->data + index * vector->objsize;
933 if (newmem) {
934 void *dump_data = malloc(vector->objsize);
935 if (dump_data == NULL) {
936 errno = ENOMEM;
937 return NULL;
938 } else {
939 memcpy(dump_data, src_data, vector->objsize);
940 return dump_data;
941 }
942 } else {
943 return src_data;
944 }
945}
946
947static bool remove_at(qvector_t *vector, int index) {
948 if (index < 0) {
949 index += vector->num;
950 }
951 if (index >= vector->num) {
952 if (vector->num == 0) {
953 errno = ENOENT;
954 return false;
955 } else {
956 errno = ERANGE;
957 return false;
958 }
959 }
960
961 int i;
962 for (i = index + 1; i < vector->num; i++) {
963 void *src = (unsigned char *)vector->data + i * vector->objsize;
964 void *dst = (unsigned char *)vector->data + (i - 1) * vector->objsize;
965
966 memcpy(dst, src, vector->objsize);
967 }
968
969 return true;
970}
971
972#endif
bool qvector_addfirst(qvector_t *vector, const void *data)
qvector->addfirst(): Insert a element at the beginning of this vector.
Definition qvector.c:233
bool qvector_removefirst(qvector_t *vector)
qvector->removefirst(): Removes the first element in this vector.
Definition qvector.c:596
void qvector_reverse(qvector_t *vector)
qvector->reverse(): Reverse the order of element in this vector.
Definition qvector.c:823
void * qvector_getat(qvector_t *vector, int index, bool newmem)
qvector->getat(): Returns the element at the specified position in this vector.
Definition qvector.c:423
void * qvector_poplast(qvector_t *vector)
qvector->poplast(): Returns the last element of this vector.
Definition qvector.c:539
bool qvector_debug(qvector_t *vector, FILE *out)
qvector->debug(): Prints out stored elements for debugging purpose.
Definition qvector.c:707
void qvector_lock(qvector_t *vector)
qvector->lock(): Enters critical section.
Definition qvector.c:657
bool qvector_resize(qvector_t *vector, size_t newmax)
qvector->resize(): Changes the allocated memory space size.
Definition qvector.c:746
void * qvector_getfirst(qvector_t *vector, bool newmem)
qvector->addat(): Inserts a element at the specified position in this vector.
Definition qvector.c:371
void * qvector_popfirst(qvector_t *vector)
qvector->popfirst(): Returns and remove the first element in this vector.
Definition qvector.c:525
void * qvector_getlast(qvector_t *vector, bool newmem)
qvector->getlast(): Returns the last element in this vector.
Definition qvector.c:395
void qvector_free(qvector_t *vector)
qvector->free(): Free this vector.
Definition qvector.c:686
void qvector_clear(qvector_t *vector)
qvector->clear(): Remove all the elemnts in this vector.
Definition qvector.c:675
qvector_t * qvector(size_t max, size_t objsize, int options)
Create new qvector_t container.
Definition qvector.c:117
void qvector_unlock(qvector_t *vector)
qvector->unlock(): Leaves critical section.
Definition qvector.c:666
void * qvector_toarray(qvector_t *vector, size_t *size)
qvector->toarray(): Returns an array contains all the elements in this vector.
Definition qvector.c:787
bool qvector_setlast(qvector_t *vector, const void *data)
qvector->setlast(): Set the last element with a new value in this vector.
Definition qvector.c:477
bool qvector_getnext(qvector_t *vector, qvector_obj_t *obj, bool newmem)
qvector->getnext(): Get next element in this vector.
Definition qvector.c:881
bool qvector_setfirst(qvector_t *vector, const void *data)
qvector->setfirst(): Set the first element with a new value in this vector.
Definition qvector.c:452
bool qvector_removelast(qvector_t *vector)
qvector->removelast(): Removes the last element in this vector.
Definition qvector.c:610
bool qvector_removeat(qvector_t *vector, int index)
qvector->removeat(): Removes the element at the specified position in this vector.
Definition qvector.c:625
void * qvector_popat(qvector_t *vector, int index)
qvector->popat(): Returns and remove the element at specified position in this vector.
Definition qvector.c:567
bool qvector_setat(qvector_t *vector, int index, const void *data)
qvector->setat(): Set new value to the specified position in this vector.
Definition qvector.c:503
size_t qvector_size(qvector_t *vector)
qvector->size(): Get the number of elements in this vector.
Definition qvector.c:644
bool qvector_addlast(qvector_t *vector, const void *data)
qvector->addlast(): Insert a element at the end of this vector.
Definition qvector.c:259