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 
89 static void *get_at(qvector_t *vector, int index, bool newmem);
90 static 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  */
117 qvector_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  */
233 bool 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  */
259 bool 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  */
296 bool 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  */
371 void *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  */
395 void *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  */
423 void *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  */
452 bool 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  */
477 bool 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  */
503 bool 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  */
525 void *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  */
539 void *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  */
567 void *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  */
596 bool 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  */
610 bool 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  */
625 bool 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  */
644 size_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  */
657 void 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  */
666 void 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  */
675 void 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  */
686 void qvector_free(qvector_t *vector) {
687  vector->clear(vector);
688  Q_MUTEX_DESTROY(vector->qmutex);
689 
690  free(vector);
691 }
692 
693 /**
694  * qvector->debug(): Prints out stored elements for debugging purpose.
695  *
696  * @param vector qvector_t container pointer.
697  * @param out output stream FILE descriptor such like stdout, stderr.
698  *
699  * @return true if successful, otherwise returns false.
700  * @retval errno will be set in error condition.
701  * - EIO : Invalid output stream.
702  */
703 bool 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  */
742 bool 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 contains 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 a malloced pointer, otherwise return NULL.
779  * @retval errno wil be set in error condition.
780  * - ENOENT : Vector is empty.
781  * - ENOMEM : Memory allocation failure.
782  */
783 void *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  */
819 void 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 de-allocate 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  */
877 bool 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 
914 static 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 
943 static 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  int i;
958  for (i = index + 1; i < vector->num; i++) {
959  void *src = (unsigned char *)vector->data + i * vector->objsize;
960  void *dst = (unsigned char *)vector->data + (i - 1) * vector->objsize;
961 
962  memcpy(dst, src, vector->objsize);
963  }
964 
965  return true;
966 }
967 
968 #endif
969 
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
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_addfirst(qvector_t *vector, const void *data)
qvector->addfirst(): Insert a element at the beginning of this vector.
Definition: qvector.c:233
qvector_t * qvector(size_t max, size_t objsize, int options)
Create new qvector_t container.
Definition: qvector.c:117
void qvector_clear(qvector_t *vector)
qvector->clear(): Remove all the elemnts in this vector.
Definition: qvector.c:675
void * qvector_toarray(qvector_t *vector, size_t *size)
qvector->toarray(): Returns an array contains all the elements in this vector.
Definition: qvector.c:783
void qvector_free(qvector_t *vector)
qvector->free(): Free this vector.
Definition: qvector.c:686
bool qvector_removeat(qvector_t *vector, int index)
qvector->removeat(): Removes the element at the specified position in this vector.
Definition: qvector.c:625
bool qvector_resize(qvector_t *vector, size_t newmax)
qvector->resize(): Changes the allocated memory space size.
Definition: qvector.c:742
bool qvector_removefirst(qvector_t *vector)
qvector->removefirst(): Removes the first element in this vector.
Definition: qvector.c:596
void qvector_unlock(qvector_t *vector)
qvector->unlock(): Leaves critical section.
Definition: qvector.c:666
void * qvector_getlast(qvector_t *vector, bool newmem)
qvector->getlast(): Returns the last element in this vector.
Definition: qvector.c:395
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
size_t qvector_size(qvector_t *vector)
qvector->size(): Get the number of elements in this vector.
Definition: qvector.c:644
bool qvector_debug(qvector_t *vector, FILE *out)
qvector->debug(): Prints out stored elements for debugging purpose.
Definition: qvector.c:703
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
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
bool qvector_removelast(qvector_t *vector)
qvector->removelast(): Removes the last element in this vector.
Definition: qvector.c:610
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_poplast(qvector_t *vector)
qvector->poplast(): Returns the last element of this vector.
Definition: qvector.c:539
void qvector_lock(qvector_t *vector)
qvector->lock(): Enters critical section.
Definition: qvector.c:657
bool qvector_addlast(qvector_t *vector, const void *data)
qvector->addlast(): Insert a element at the end of this vector.
Definition: qvector.c:259
bool qvector_getnext(qvector_t *vector, qvector_obj_t *obj, bool newmem)
qvector->getnext(): Get next element in this vector.
Definition: qvector.c:877
void * qvector_popfirst(qvector_t *vector)
qvector->popfirst(): Returns and remove the first element in this vector.
Definition: qvector.c:525
void qvector_reverse(qvector_t *vector)
qvector->reverse(): Reverse the order of element in this vector.
Definition: qvector.c:819