/ externals / zycore / src / Vector.c
Vector.c
  1  /***************************************************************************************************
  2  
  3    Zyan Core Library (Zycore-C)
  4  
  5    Original Author : Florian Bernd
  6  
  7   * Permission is hereby granted, free of charge, to any person obtaining a copy
  8   * of this software and associated documentation files (the "Software"), to deal
  9   * in the Software without restriction, including without limitation the rights
 10   * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 11   * copies of the Software, and to permit persons to whom the Software is
 12   * furnished to do so, subject to the following conditions:
 13   *
 14   * The above copyright notice and this permission notice shall be included in all
 15   * copies or substantial portions of the Software.
 16   *
 17   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 18   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 19   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 20   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 21   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 22   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 23   * SOFTWARE.
 24  
 25  ***************************************************************************************************/
 26  
 27  #include <Zycore/LibC.h>
 28  #include <Zycore/Vector.h>
 29  
 30  /* ============================================================================================== */
 31  /* Internal macros                                                                                */
 32  /* ============================================================================================== */
 33  
 34  /**
 35   * Checks, if the passed vector should grow.
 36   *
 37   * @param   size        The desired size of the vector.
 38   * @param   capacity    The current capacity of the vector.
 39   *
 40   * @return  `ZYAN_TRUE`, if the vector should grow or `ZYAN_FALSE`, if not.
 41   */
 42  #define ZYCORE_VECTOR_SHOULD_GROW(size, capacity) \
 43      ((size) > (capacity))
 44  
 45  /**
 46   * Checks, if the passed vector should shrink.
 47   *
 48   * @param   size        The desired size of the vector.
 49   * @param   capacity    The current capacity of the vector.
 50   * @param   threshold   The shrink threshold.
 51   *
 52   * @return  `ZYAN_TRUE`, if the vector should shrink or `ZYAN_FALSE`, if not.
 53   */
 54  #define ZYCORE_VECTOR_SHOULD_SHRINK(size, capacity, threshold) \
 55      (((threshold) != 0) && ((size) * (threshold) < (capacity)))
 56  
 57  /**
 58   * Returns the offset of the element at the given `index`.
 59   *
 60   * @param   vector  A pointer to the `ZyanVector` instance.
 61   * @param   index   The element index.
 62   *
 63   * @return  The offset of the element at the given `index`.
 64   */
 65  #define ZYCORE_VECTOR_OFFSET(vector, index) \
 66      ((void*)((ZyanU8*)(vector)->data + ((index) * (vector)->element_size)))
 67  
 68  /* ============================================================================================== */
 69  /* Internal functions                                                                             */
 70  /* ============================================================================================== */
 71  
 72  /* ---------------------------------------------------------------------------------------------- */
 73  /* Helper functions                                                                               */
 74  /* ---------------------------------------------------------------------------------------------- */
 75  
 76  /**
 77   * Reallocates the internal buffer of the vector.
 78   *
 79   * @param   vector      A pointer to the `ZyanVector` instance.
 80   * @param   capacity    The new capacity.
 81   *
 82   * @return  A zyan status code.
 83   */
 84  static ZyanStatus ZyanVectorReallocate(ZyanVector* vector, ZyanUSize capacity)
 85  {
 86      ZYAN_ASSERT(vector);
 87      ZYAN_ASSERT(vector->capacity >= ZYAN_VECTOR_MIN_CAPACITY);
 88      ZYAN_ASSERT(vector->element_size);
 89      ZYAN_ASSERT(vector->data);
 90  
 91      if (!vector->allocator)
 92      {
 93          if (vector->capacity < capacity)
 94          {
 95              return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE;
 96          }
 97          return ZYAN_STATUS_SUCCESS;
 98      }
 99  
100      ZYAN_ASSERT(vector->allocator);
101      ZYAN_ASSERT(vector->allocator->reallocate);
102  
103      if (capacity < ZYAN_VECTOR_MIN_CAPACITY)
104      {
105          if (vector->capacity > ZYAN_VECTOR_MIN_CAPACITY)
106          {
107              capacity = ZYAN_VECTOR_MIN_CAPACITY;
108          } else
109          {
110              return ZYAN_STATUS_SUCCESS;
111          }
112      }
113  
114      vector->capacity = capacity;
115      ZYAN_CHECK(vector->allocator->reallocate(vector->allocator, &vector->data,
116          vector->element_size, vector->capacity));
117  
118      return ZYAN_STATUS_SUCCESS;
119  }
120  
121  /**
122   * Shifts all elements starting at the specified `index` by the amount of `count` to the left.
123   *
124   * @param   vector  A pointer to the `ZyanVector` instance.
125   * @param   index   The start index.
126   * @param   count   The amount of shift operations.
127   *
128   * @return  A zyan status code.
129   */
130  static ZyanStatus ZyanVectorShiftLeft(ZyanVector* vector, ZyanUSize index, ZyanUSize count)
131  {
132      ZYAN_ASSERT(vector);
133      ZYAN_ASSERT(vector->element_size);
134      ZYAN_ASSERT(vector->data);
135      ZYAN_ASSERT(count > 0);
136      //ZYAN_ASSERT((ZyanISize)count - (ZyanISize)index + 1 >= 0);
137  
138      const void* const source = ZYCORE_VECTOR_OFFSET(vector, index + count);
139      void* const dest         = ZYCORE_VECTOR_OFFSET(vector, index);
140      const ZyanUSize size     = (vector->size - index - count) * vector->element_size;
141      ZYAN_MEMMOVE(dest, source, size);
142  
143      return ZYAN_STATUS_SUCCESS;
144  }
145  
146  /**
147   * Shifts all elements starting at the specified `index` by the amount of `count` to the right.
148   *
149   * @param   vector  A pointer to the `ZyanVector` instance.
150   * @param   index   The start index.
151   * @param   count   The amount of shift operations.
152   *
153   * @return  A zyan status code.
154   */
155  static ZyanStatus ZyanVectorShiftRight(ZyanVector* vector, ZyanUSize index, ZyanUSize count)
156  {
157      ZYAN_ASSERT(vector);
158      ZYAN_ASSERT(vector->element_size);
159      ZYAN_ASSERT(vector->data);
160      ZYAN_ASSERT(count > 0);
161      ZYAN_ASSERT(vector->size + count <= vector->capacity);
162  
163      const void* const source = ZYCORE_VECTOR_OFFSET(vector, index);
164      void* const dest         = ZYCORE_VECTOR_OFFSET(vector, index + count);
165      const ZyanUSize size     = (vector->size - index) * vector->element_size;
166      ZYAN_MEMMOVE(dest, source, size);
167  
168      return ZYAN_STATUS_SUCCESS;
169  }
170  
171  /* ---------------------------------------------------------------------------------------------- */
172  
173  /* ============================================================================================== */
174  /* Exported functions                                                                             */
175  /* ============================================================================================== */
176  
177  /* ---------------------------------------------------------------------------------------------- */
178  /* Constructor and destructor                                                                     */
179  /* ---------------------------------------------------------------------------------------------- */
180  
181  #ifndef ZYAN_NO_LIBC
182  
183  ZyanStatus ZyanVectorInit(ZyanVector* vector, ZyanUSize element_size, ZyanUSize capacity,
184      ZyanMemberProcedure destructor)
185  {
186      return ZyanVectorInitEx(vector, element_size, capacity, destructor, ZyanAllocatorDefault(),
187          ZYAN_VECTOR_DEFAULT_GROWTH_FACTOR, ZYAN_VECTOR_DEFAULT_SHRINK_THRESHOLD);
188  }
189  
190  #endif // ZYAN_NO_LIBC
191  
192  ZyanStatus ZyanVectorInitEx(ZyanVector* vector, ZyanUSize element_size, ZyanUSize capacity,
193      ZyanMemberProcedure destructor, ZyanAllocator* allocator, ZyanU8 growth_factor,
194      ZyanU8 shrink_threshold)
195  {
196      if (!vector || !element_size || !allocator || (growth_factor < 1))
197      {
198          return ZYAN_STATUS_INVALID_ARGUMENT;
199      }
200  
201      ZYAN_ASSERT(allocator->allocate);
202  
203      vector->allocator        = allocator;
204      vector->growth_factor    = growth_factor;
205      vector->shrink_threshold = shrink_threshold;
206      vector->size             = 0;
207      vector->capacity         = ZYAN_MAX(ZYAN_VECTOR_MIN_CAPACITY, capacity);
208      vector->element_size     = element_size;
209      vector->destructor       = destructor;
210      vector->data             = ZYAN_NULL;
211  
212      return allocator->allocate(vector->allocator, &vector->data, vector->element_size,
213          vector->capacity);
214  }
215  
216  ZyanStatus ZyanVectorInitCustomBuffer(ZyanVector* vector, ZyanUSize element_size,
217      void* buffer, ZyanUSize capacity, ZyanMemberProcedure destructor)
218  {
219      if (!vector || !element_size || !buffer || !capacity)
220      {
221          return ZYAN_STATUS_INVALID_ARGUMENT;
222      }
223  
224      vector->allocator        = ZYAN_NULL;
225      vector->growth_factor    = 1;
226      vector->shrink_threshold = 0;
227      vector->size             = 0;
228      vector->capacity         = capacity;
229      vector->element_size     = element_size;
230      vector->destructor       = destructor;
231      vector->data             = buffer;
232  
233      return ZYAN_STATUS_SUCCESS;
234  }
235  
236  ZyanStatus ZyanVectorDestroy(ZyanVector* vector)
237  {
238      if (!vector)
239      {
240          return ZYAN_STATUS_INVALID_ARGUMENT;
241      }
242  
243      ZYAN_ASSERT(vector->element_size);
244      ZYAN_ASSERT(vector->data);
245  
246      if (vector->destructor)
247      {
248          for (ZyanUSize i = 0; i < vector->size; ++i)
249          {
250              vector->destructor(ZYCORE_VECTOR_OFFSET(vector, i));
251          }
252      }
253  
254      if (vector->allocator && vector->capacity)
255      {
256          ZYAN_ASSERT(vector->allocator->deallocate);
257          ZYAN_CHECK(vector->allocator->deallocate(vector->allocator, vector->data,
258              vector->element_size, vector->capacity));
259      }
260  
261      vector->data = ZYAN_NULL;
262      return ZYAN_STATUS_SUCCESS;
263  }
264  
265  /* ---------------------------------------------------------------------------------------------- */
266  /* Duplication                                                                                    */
267  /* ---------------------------------------------------------------------------------------------- */
268  
269  #ifndef ZYAN_NO_LIBC
270  
271  ZyanStatus ZyanVectorDuplicate(ZyanVector* destination, const ZyanVector* source,
272      ZyanUSize capacity)
273  {
274      return ZyanVectorDuplicateEx(destination, source, capacity, ZyanAllocatorDefault(),
275          ZYAN_VECTOR_DEFAULT_GROWTH_FACTOR, ZYAN_VECTOR_DEFAULT_SHRINK_THRESHOLD);
276  }
277  
278  #endif // ZYAN_NO_LIBC
279  
280  ZyanStatus ZyanVectorDuplicateEx(ZyanVector* destination, const ZyanVector* source,
281      ZyanUSize capacity, ZyanAllocator* allocator, ZyanU8 growth_factor, ZyanU8 shrink_threshold)
282  {
283      if (!source)
284      {
285          return ZYAN_STATUS_INVALID_ARGUMENT;
286      }
287  
288      const ZyanUSize len = source->size;
289  
290      capacity = ZYAN_MAX(capacity, len);
291      ZYAN_CHECK(ZyanVectorInitEx(destination, source->element_size, capacity, source->destructor,
292          allocator, growth_factor, shrink_threshold));
293      ZYAN_ASSERT(destination->capacity >= len);
294  
295      ZYAN_MEMCPY(destination->data, source->data, len * source->element_size);
296      destination->size = len;
297  
298      return ZYAN_STATUS_SUCCESS;
299  }
300  
301  ZyanStatus ZyanVectorDuplicateCustomBuffer(ZyanVector* destination, const ZyanVector* source,
302      void* buffer, ZyanUSize capacity)
303  {
304      if (!source)
305      {
306          return ZYAN_STATUS_INVALID_ARGUMENT;
307      }
308  
309      const ZyanUSize len = source->size;
310  
311      if (capacity < len)
312      {
313          return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE;
314      }
315  
316      ZYAN_CHECK(ZyanVectorInitCustomBuffer(destination, source->element_size, buffer, capacity,
317          source->destructor));
318      ZYAN_ASSERT(destination->capacity >= len);
319  
320      ZYAN_MEMCPY(destination->data, source->data, len * source->element_size);
321      destination->size = len;
322  
323      return ZYAN_STATUS_SUCCESS;
324  }
325  
326  /* ---------------------------------------------------------------------------------------------- */
327  /* Element access                                                                                 */
328  /* ---------------------------------------------------------------------------------------------- */
329  
330  const void* ZyanVectorGet(const ZyanVector* vector, ZyanUSize index)
331  {
332      if (!vector || (index >= vector->size))
333      {
334          return ZYAN_NULL;
335      }
336  
337      ZYAN_ASSERT(vector->element_size);
338      ZYAN_ASSERT(vector->data);
339  
340      return ZYCORE_VECTOR_OFFSET(vector, index);
341  }
342  
343  void* ZyanVectorGetMutable(const ZyanVector* vector, ZyanUSize index)
344  {
345      if (!vector || (index >= vector->size))
346      {
347          return ZYAN_NULL;
348      }
349  
350      ZYAN_ASSERT(vector->element_size);
351      ZYAN_ASSERT(vector->data);
352  
353      return ZYCORE_VECTOR_OFFSET(vector, index);
354  }
355  
356  ZyanStatus ZyanVectorGetPointer(const ZyanVector* vector, ZyanUSize index, const void** value)
357  {
358      if (!vector || !value)
359      {
360          return ZYAN_STATUS_INVALID_ARGUMENT;
361      }
362      if (index >= vector->size)
363      {
364          return ZYAN_STATUS_OUT_OF_RANGE;
365      }
366  
367      ZYAN_ASSERT(vector->element_size);
368      ZYAN_ASSERT(vector->data);
369  
370      *value = (const void*)ZYCORE_VECTOR_OFFSET(vector, index);
371  
372      return ZYAN_STATUS_SUCCESS;
373  }
374  
375  ZyanStatus ZyanVectorGetPointerMutable(const ZyanVector* vector, ZyanUSize index, void** value)
376  {
377      if (!vector || !value)
378      {
379          return ZYAN_STATUS_INVALID_ARGUMENT;
380      }
381      if (index >= vector->size)
382      {
383          return ZYAN_STATUS_OUT_OF_RANGE;
384      }
385  
386      ZYAN_ASSERT(vector->element_size);
387      ZYAN_ASSERT(vector->data);
388  
389      *value = ZYCORE_VECTOR_OFFSET(vector, index);
390  
391      return ZYAN_STATUS_SUCCESS;
392  }
393  
394  ZyanStatus ZyanVectorSet(ZyanVector* vector, ZyanUSize index, const void* value)
395  {
396      if (!vector || !value)
397      {
398          return ZYAN_STATUS_INVALID_ARGUMENT;
399      }
400      if (index >= vector->size)
401      {
402          return ZYAN_STATUS_OUT_OF_RANGE;
403      }
404  
405      ZYAN_ASSERT(vector->element_size);
406      ZYAN_ASSERT(vector->data);
407  
408      void* const offset = ZYCORE_VECTOR_OFFSET(vector, index);
409      if (vector->destructor)
410      {
411          vector->destructor(offset);
412      }
413      ZYAN_MEMCPY(offset, value, vector->element_size);
414  
415      return ZYAN_STATUS_SUCCESS;
416  }
417  
418  /* ---------------------------------------------------------------------------------------------- */
419  /* Insertion                                                                                      */
420  /* ---------------------------------------------------------------------------------------------- */
421  
422  ZyanStatus ZyanVectorPushBack(ZyanVector* vector, const void* element)
423  {
424      if (!vector || !element)
425      {
426          return ZYAN_STATUS_INVALID_ARGUMENT;
427      }
428  
429      ZYAN_ASSERT(vector->element_size);
430      ZYAN_ASSERT(vector->data);
431  
432      if (ZYCORE_VECTOR_SHOULD_GROW(vector->size + 1, vector->capacity))
433      {
434          ZYAN_CHECK(ZyanVectorReallocate(vector,
435              ZYAN_MAX(1, (ZyanUSize)((vector->size + 1) * vector->growth_factor))));
436      }
437  
438      void* const offset = ZYCORE_VECTOR_OFFSET(vector, vector->size);
439      ZYAN_MEMCPY(offset, element, vector->element_size);
440  
441      ++vector->size;
442  
443      return ZYAN_STATUS_SUCCESS;
444  }
445  
446  ZyanStatus ZyanVectorInsert(ZyanVector* vector, ZyanUSize index, const void* element)
447  {
448      return ZyanVectorInsertRange(vector, index, element, 1);
449  }
450  
451  ZyanStatus ZyanVectorInsertRange(ZyanVector* vector, ZyanUSize index, const void* elements,
452      ZyanUSize count)
453  {
454      if (!vector || !elements || !count)
455      {
456          return ZYAN_STATUS_INVALID_ARGUMENT;
457      }
458      if (index > vector->size)
459      {
460          return ZYAN_STATUS_OUT_OF_RANGE;
461      }
462  
463      ZYAN_ASSERT(vector->element_size);
464      ZYAN_ASSERT(vector->data);
465  
466      if (ZYCORE_VECTOR_SHOULD_GROW(vector->size + count, vector->capacity))
467      {
468          ZYAN_CHECK(ZyanVectorReallocate(vector,
469              ZYAN_MAX(1, (ZyanUSize)((vector->size + count) * vector->growth_factor))));
470      }
471  
472      if (index < vector->size)
473      {
474          ZYAN_CHECK(ZyanVectorShiftRight(vector, index, count));
475      }
476  
477      void* const offset = ZYCORE_VECTOR_OFFSET(vector, index);
478      ZYAN_MEMCPY(offset, elements, count * vector->element_size);
479      vector->size += count;
480  
481      return ZYAN_STATUS_SUCCESS;
482  }
483  
484  ZyanStatus ZyanVectorEmplace(ZyanVector* vector, void** element, ZyanMemberFunction constructor)
485  {
486      if (!vector)
487      {
488          return ZYAN_STATUS_INVALID_ARGUMENT;
489      }
490  
491      return ZyanVectorEmplaceEx(vector, vector->size, element, constructor);
492  }
493  
494  ZyanStatus ZyanVectorEmplaceEx(ZyanVector* vector, ZyanUSize index, void** element,
495      ZyanMemberFunction constructor)
496  {
497      if (!vector)
498      {
499          return ZYAN_STATUS_INVALID_ARGUMENT;
500      }
501      if (index > vector->size)
502      {
503          return ZYAN_STATUS_OUT_OF_RANGE;
504      }
505  
506      ZYAN_ASSERT(vector->element_size);
507      ZYAN_ASSERT(vector->data);
508  
509      if (ZYCORE_VECTOR_SHOULD_GROW(vector->size + 1, vector->capacity))
510      {
511          ZYAN_CHECK(ZyanVectorReallocate(vector,
512              ZYAN_MAX(1, (ZyanUSize)((vector->size + 1) * vector->growth_factor))));
513      }
514  
515      if (index < vector->size)
516      {
517          ZYAN_CHECK(ZyanVectorShiftRight(vector, index, 1));
518      }
519  
520      *element = ZYCORE_VECTOR_OFFSET(vector, index);
521      if (constructor)
522      {
523          ZYAN_CHECK(constructor(*element));
524      }
525  
526      ++vector->size;
527  
528      return ZYAN_STATUS_SUCCESS;
529  }
530  
531  /* ---------------------------------------------------------------------------------------------- */
532  /* Utils                                                                                          */
533  /* ---------------------------------------------------------------------------------------------- */
534  
535  ZyanStatus ZyanVectorSwapElements(ZyanVector* vector, ZyanUSize index_first, ZyanUSize index_second)
536  {
537      if (!vector)
538      {
539          return ZYAN_STATUS_INVALID_ARGUMENT;
540      }
541      if ((index_first >= vector->size) || (index_second >= vector->size))
542      {
543          return ZYAN_STATUS_OUT_OF_RANGE;
544      }
545  
546      if (vector->size == vector->capacity)
547      {
548          return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE;
549      }
550  
551      ZYAN_ASSERT(vector->element_size);
552      ZYAN_ASSERT(vector->data);
553  
554      ZyanU64* const t = ZYCORE_VECTOR_OFFSET(vector, vector->size);
555      ZyanU64* const a = ZYCORE_VECTOR_OFFSET(vector, index_first);
556      ZyanU64* const b = ZYCORE_VECTOR_OFFSET(vector, index_second);
557      ZYAN_MEMCPY(t, a, vector->element_size);
558      ZYAN_MEMCPY(a, b, vector->element_size);
559      ZYAN_MEMCPY(b, t, vector->element_size);
560  
561      return ZYAN_STATUS_SUCCESS;
562  }
563  
564  /* ---------------------------------------------------------------------------------------------- */
565  /* Deletion                                                                                       */
566  /* ---------------------------------------------------------------------------------------------- */
567  
568  ZyanStatus ZyanVectorDelete(ZyanVector* vector, ZyanUSize index)
569  {
570      return ZyanVectorDeleteRange(vector, index, 1);
571  }
572  
573  ZyanStatus ZyanVectorDeleteRange(ZyanVector* vector, ZyanUSize index, ZyanUSize count)
574  {
575      if (!vector || !count)
576      {
577          return ZYAN_STATUS_INVALID_ARGUMENT;
578      }
579      if (index + count > vector->size)
580      {
581          return ZYAN_STATUS_OUT_OF_RANGE;
582      }
583  
584      if (vector->destructor)
585      {
586          for (ZyanUSize i = index; i < index + count; ++i)
587          {
588              vector->destructor(ZYCORE_VECTOR_OFFSET(vector, i));
589          }
590      }
591  
592      if (index + count < vector->size)
593      {
594          ZYAN_CHECK(ZyanVectorShiftLeft(vector, index, count));
595      }
596  
597      vector->size -= count;
598      if (ZYCORE_VECTOR_SHOULD_SHRINK(vector->size, vector->capacity, vector->shrink_threshold))
599      {
600          return ZyanVectorReallocate(vector,
601              ZYAN_MAX(1, (ZyanUSize)(vector->size * vector->growth_factor)));
602      }
603  
604      return ZYAN_STATUS_SUCCESS;
605  }
606  
607  ZyanStatus ZyanVectorPopBack(ZyanVector* vector)
608  {
609      if (!vector)
610      {
611          return ZYAN_STATUS_INVALID_ARGUMENT;
612      }
613      if (vector->size == 0)
614      {
615          return ZYAN_STATUS_OUT_OF_RANGE;
616      }
617  
618      if (vector->destructor)
619      {
620           vector->destructor(ZYCORE_VECTOR_OFFSET(vector, vector->size - 1));
621      }
622  
623      --vector->size;
624      if (ZYCORE_VECTOR_SHOULD_SHRINK(vector->size, vector->capacity, vector->shrink_threshold))
625      {
626          return ZyanVectorReallocate(vector,
627              ZYAN_MAX(1, (ZyanUSize)(vector->size * vector->growth_factor)));
628      }
629  
630      return ZYAN_STATUS_SUCCESS;
631  }
632  
633  ZyanStatus ZyanVectorClear(ZyanVector* vector)
634  {
635      return ZyanVectorResizeEx(vector, 0, ZYAN_NULL);
636  }
637  
638  /* ---------------------------------------------------------------------------------------------- */
639  /* Searching                                                                                      */
640  /* ---------------------------------------------------------------------------------------------- */
641  
642  ZyanStatus ZyanVectorFind(const ZyanVector* vector, const void* element, ZyanISize* found_index,
643      ZyanEqualityComparison comparison)
644  {
645      if (!vector)
646      {
647          return ZYAN_STATUS_INVALID_ARGUMENT;
648      }
649  
650      return ZyanVectorFindEx(vector, element, found_index, comparison, 0, vector->size);
651  }
652  
653  ZyanStatus ZyanVectorFindEx(const ZyanVector* vector, const void* element, ZyanISize* found_index,
654      ZyanEqualityComparison comparison, ZyanUSize index, ZyanUSize count)
655  {
656      if (!vector)
657      {
658          return ZYAN_STATUS_INVALID_ARGUMENT;
659      }
660      if ((index + count > vector->size) || (index == vector->size))
661      {
662          return ZYAN_STATUS_OUT_OF_RANGE;
663      }
664  
665      if (!count)
666      {
667          *found_index = -1;
668          return ZYAN_STATUS_FALSE;
669      }
670  
671      ZYAN_ASSERT(vector->element_size);
672      ZYAN_ASSERT(vector->data);
673  
674      for (ZyanUSize i = index; i < index + count; ++i)
675      {
676          if (comparison(ZYCORE_VECTOR_OFFSET(vector, i), element))
677          {
678              *found_index = i;
679              return ZYAN_STATUS_TRUE;
680          }
681      }
682  
683      *found_index = -1;
684      return ZYAN_STATUS_FALSE;
685  }
686  
687  ZyanStatus ZyanVectorBinarySearch(const ZyanVector* vector, const void* element,
688      ZyanUSize* found_index, ZyanComparison comparison)
689  {
690      if (!vector)
691      {
692          return ZYAN_STATUS_INVALID_ARGUMENT;
693      }
694  
695      return ZyanVectorBinarySearchEx(vector, element, found_index, comparison, 0, vector->size);
696  }
697  
698  ZyanStatus ZyanVectorBinarySearchEx(const ZyanVector* vector, const void* element,
699      ZyanUSize* found_index, ZyanComparison comparison, ZyanUSize index, ZyanUSize count)
700  {
701      if (!vector)
702      {
703          return ZYAN_STATUS_INVALID_ARGUMENT;
704      }
705      if (((index >= vector->size) && (count > 0)) || (index + count > vector->size))
706      {
707          return ZYAN_STATUS_OUT_OF_RANGE;
708      }
709  
710      if (!count)
711      {
712          *found_index = index;
713          return ZYAN_STATUS_FALSE;
714      }
715  
716      ZYAN_ASSERT(vector->element_size);
717      ZYAN_ASSERT(vector->data);
718  
719      ZyanStatus status = ZYAN_STATUS_FALSE;
720      ZyanISize l = index;
721      ZyanISize h = index + count - 1;
722      while (l <= h)
723      {
724          const ZyanUSize mid = l + ((h - l) >> 1);
725          const ZyanI32 cmp = comparison(ZYCORE_VECTOR_OFFSET(vector, mid), element);
726          if (cmp < 0)
727          {
728              l = mid + 1;
729          } else
730          {
731              h = mid - 1;
732              if (cmp == 0)
733              {
734                  status = ZYAN_STATUS_TRUE;
735              }
736          }
737      }
738  
739      *found_index = l;
740      return status;
741  }
742  
743  /* ---------------------------------------------------------------------------------------------- */
744  /* Memory management                                                                              */
745  /* ---------------------------------------------------------------------------------------------- */
746  
747  ZyanStatus ZyanVectorResize(ZyanVector* vector, ZyanUSize size)
748  {
749      return ZyanVectorResizeEx(vector, size, ZYAN_NULL);
750  }
751  
752  ZyanStatus ZyanVectorResizeEx(ZyanVector* vector, ZyanUSize size, const void* initializer)
753  {
754      if (!vector)
755      {
756          return ZYAN_STATUS_INVALID_ARGUMENT;
757      }
758      if (size == vector->size)
759      {
760          return ZYAN_STATUS_SUCCESS;
761      }
762  
763      if (vector->destructor && (size < vector->size))
764      {
765          for (ZyanUSize i = size; i < vector->size; ++i)
766          {
767              vector->destructor(ZYCORE_VECTOR_OFFSET(vector, i));
768          }
769      }
770  
771      if (ZYCORE_VECTOR_SHOULD_GROW(size, vector->capacity) ||
772          ZYCORE_VECTOR_SHOULD_SHRINK(size, vector->capacity, vector->shrink_threshold))
773      {
774          ZYAN_ASSERT(vector->growth_factor >= 1);
775          ZYAN_CHECK(ZyanVectorReallocate(vector, (ZyanUSize)(size * vector->growth_factor)));
776      }
777  
778      if (initializer && (size > vector->size))
779      {
780          for (ZyanUSize i = vector->size; i < size; ++i)
781          {
782              ZYAN_MEMCPY(ZYCORE_VECTOR_OFFSET(vector, i), initializer, vector->element_size);
783          }
784      }
785  
786      vector->size = size;
787  
788      return ZYAN_STATUS_SUCCESS;
789  }
790  
791  ZyanStatus ZyanVectorReserve(ZyanVector* vector, ZyanUSize capacity)
792  {
793      if (!vector)
794      {
795          return ZYAN_STATUS_INVALID_ARGUMENT;
796      }
797  
798      if (capacity > vector->capacity)
799      {
800          ZYAN_CHECK(ZyanVectorReallocate(vector, capacity));
801      }
802  
803      return ZYAN_STATUS_SUCCESS;
804  }
805  
806  ZyanStatus ZyanVectorShrinkToFit(ZyanVector* vector)
807  {
808      if (!vector)
809      {
810          return ZYAN_STATUS_INVALID_ARGUMENT;
811      }
812  
813      return ZyanVectorReallocate(vector, vector->size);
814  }
815  
816  /* ---------------------------------------------------------------------------------------------- */
817  /* Information                                                                                    */
818  /* ---------------------------------------------------------------------------------------------- */
819  
820  ZyanStatus ZyanVectorGetCapacity(const ZyanVector* vector, ZyanUSize* capacity)
821  {
822      if (!vector)
823      {
824          return ZYAN_STATUS_INVALID_ARGUMENT;
825      }
826  
827      *capacity = vector->capacity;
828  
829      return ZYAN_STATUS_SUCCESS;
830  }
831  
832  ZyanStatus ZyanVectorGetSize(const ZyanVector* vector, ZyanUSize* size)
833  {
834      if (!vector)
835      {
836          return ZYAN_STATUS_INVALID_ARGUMENT;
837      }
838  
839      *size = vector->size;
840  
841      return ZYAN_STATUS_SUCCESS;
842  }
843  
844  /* ---------------------------------------------------------------------------------------------- */
845  
846  /* ============================================================================================== */