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