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  free(vector->data);
678  vector->data = NULL;
679  vector->num = 0;
680  vector->objsize = 0;
681  vector->max = 0;
682  vector->unlock(vector);
683 }
684 
685 /**
686  * qvector->free(): Free this vector.
687  *
688  * @param vector qvector_t container pointer.
689  */
690 void qvector_free(qvector_t *vector) {
691  vector->clear(vector);
692  Q_MUTEX_DESTROY(vector->qmutex);
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  */
707 bool 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  */
746 bool 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 
770  vector->unlock(vector);
771  return true;
772 }
773 
774 /**
775  * qvector->toarray(): Returns an array contains all the elements in this vector.
776  * @param vector qvector_t container pointer.
777  * @param size if size is not NULL, the number of elements will be stored.
778  *
779  * @return a malloced pointer, otherwise return NULL.
780  * @retval errno wil be set in error condition.
781  * - ENOENT : Vector is empty.
782  * - ENOMEM : Memory allocation failure.
783  */
784 void *qvector_toarray(qvector_t *vector, size_t *size) {
785  if (vector->num <= 0) {
786  if (size != NULL) {
787  *size = 0;
788  }
789  errno = ENOENT;
790  return NULL;
791  }
792 
793  vector->lock(vector);
794 
795  void *array = malloc(vector->num * vector->objsize);
796  if (array == NULL) {
797  vector->unlock(vector);
798  errno = ENOMEM;
799  return NULL;
800  }
801 
802  memcpy(array, vector->data, vector->num * vector->objsize);
803 
804  if (size != NULL) {
805  *size = vector->num;
806  }
807 
808  vector->unlock(vector);
809  return array;
810 }
811 
812 /**
813  * qvector->reverse(): Reverse the order of element in this vector.
814  *
815  * @param vector qvector_t container pointer.
816  *
817  * @retval will be set in error condition.
818  * - ENOMEM : Memory allocations failure.
819  */
820 void qvector_reverse(qvector_t *vector) {
821  vector->lock(vector);
822 
823  if (vector->num <= 1) {
824  vector->unlock(vector);
825  return;
826  }
827 
828  int i;
829  int j;
830  void *tmp = malloc(vector->objsize);
831  if (tmp == NULL) {
832  errno = ENOMEM;
833  return;
834  }
835 
836  for (i = 0, j = vector->num - 1; i < j; i++, j--) {
837  void *data1 = (unsigned char *)vector->data + i * vector->objsize;
838  void *data2 = (unsigned char *)vector->data + j * vector->objsize;
839 
840  memcpy(tmp, data1, vector->objsize);
841  memcpy(data1, data2, vector->objsize);
842  memcpy(data2, tmp, vector->objsize);
843  }
844  free(tmp);
845 
846  vector->unlock(vector);
847 }
848 
849 /**
850  * qvector->getnext(): Get next element in this vector.
851  *
852  * @param vector qvector_t container pointer.
853  * @param obj found data will be stored in this structure.
854  * @param newmem whether or not to allocate memory for element.
855  *
856  * @return true if found, otherwise return fasle.
857  * @retval errno will be set in error condition.
858  * - ENOENT : No next element.
859  * - ENOMEM : Memory allocation failure.
860  *
861  * @note
862  * obj should be initialized with 0 by using memset() by the first call.
863  * If newmem flag is true, user should de-allocate obj.data resources.
864  *
865  * @code
866  * qvector_t *vector = qvector();
867  * (...add data into vector...)
868  *
869  * qvector_obj_t obj;
870  * memset((void *)&obj, 0, sizeof(obj));
871  * vector->lock(vector);
872  * while(vector->getnext(vector, &obj, false) == true) {
873  * printf("DATA=%s\n", obj.data);
874  * }
875  * vector->unlock(vector);
876  * @endcode
877  */
878 bool qvector_getnext(qvector_t *vector, qvector_obj_t *obj, bool newmem) {
879  if (obj == NULL) {
880  return false;
881  }
882  vector->lock(vector);
883 
884  if (obj->index >= vector->num) {
885  errno = ENOENT;
886  obj->data = NULL;
887  vector->unlock(vector);
888  return false;
889  }
890 
891  void *data = (unsigned char *)vector->data + (obj->index) * vector->objsize;
892  if (newmem) {
893  void *dump = malloc(vector->objsize);
894  if (dump == NULL ) {
895  errno = ENOMEM;
896  obj->data = NULL;
897  vector->unlock(vector);
898  return false;
899  }
900  memcpy(dump, data, vector->objsize);
901  obj->data = dump;
902  }
903  else
904  {
905  obj->data = data;
906  }
907 
908  obj->index++;
909  vector->unlock(vector);
910  return true;
911 }
912 
913 #ifndef _DOXYGEN_SKIP
914 
915 static void *get_at(qvector_t *vector, int index, bool newmem) {
916  if (index < 0) {
917  index += vector->num;
918  }
919  if (index >= vector->num) {
920  if (vector->num == 0) {
921  errno = ENOENT;
922  return NULL;
923  } else {
924  errno = ERANGE;
925  return NULL;
926  }
927  }
928 
929  void *src_data = (unsigned char *)vector->data + index * vector->objsize;
930  if (newmem) {
931  void *dump_data = malloc(vector->objsize);
932  if (dump_data == NULL) {
933  errno = ENOMEM;
934  return NULL;
935  } else {
936  memcpy(dump_data, src_data, vector->objsize);
937  return dump_data;
938  }
939  } else {
940  return src_data;
941  }
942 }
943 
944 static bool remove_at(qvector_t *vector, int index) {
945  if (index < 0) {
946  index += vector->num;
947  }
948  if (index >= vector->num) {
949  if (vector->num == 0) {
950  errno = ENOENT;
951  return false;
952  } else {
953  errno = ERANGE;
954  return false;
955  }
956  }
957 
958  int i;
959  for (i = index + 1; i < vector->num; i++) {
960  void *src = (unsigned char *)vector->data + i * vector->objsize;
961  void *dst = (unsigned char *)vector->data + (i - 1) * vector->objsize;
962 
963  memcpy(dst, src, vector->objsize);
964  }
965 
966  return true;
967 }
968 
969 #endif
970 
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:784
void qvector_free(qvector_t *vector)
qvector->free(): Free this vector.
Definition: qvector.c:690
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:746
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:707
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:878
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:820