/ externals / zycore / examples / 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  /**
 28   * @file
 29   * Demonstrates the `ZyanVector` implementation.
 30   */
 31  
 32  #include <inttypes.h>
 33  #include <stdio.h>
 34  #include <time.h>
 35  #include <Zycore/Allocator.h>
 36  #include <Zycore/Defines.h>
 37  #include <Zycore/LibC.h>
 38  #include <Zycore/Types.h>
 39  #include <Zycore/Vector.h>
 40  
 41  /* ============================================================================================== */
 42  /* Enums and types                                                                                */
 43  /* ============================================================================================== */
 44  
 45  /**
 46   * Defines the `TestStruct` struct that represents a single element in the vector.
 47   */
 48  typedef struct TestStruct_
 49  {
 50      ZyanU32 u32;
 51      ZyanU64 u64;
 52      float f;
 53  } TestStruct;
 54  
 55  /* ============================================================================================== */
 56  /* Helper functions                                                                               */
 57  /* ============================================================================================== */
 58  
 59  /**
 60   * Initializes the given `TestStruct` struct.
 61   *
 62   * @param   data    A pointer to the `TestStruct` struct.
 63   * @param   n       The number to initialize the struct with.
 64   */
 65  static void InitTestdata(TestStruct* data, ZyanU32 n)
 66  {
 67      ZYAN_ASSERT(data);
 68  
 69      data->u32 = n;
 70      data->u64 = n;
 71      data->f   = (float)n;
 72  }
 73  
 74  /* ============================================================================================== */
 75  /* Tests                                                                                          */
 76  /* ============================================================================================== */
 77  
 78  /* ---------------------------------------------------------------------------------------------- */
 79  /* Basic tests                                                                                    */
 80  /* ---------------------------------------------------------------------------------------------- */
 81  
 82  /**
 83   * Performs some basic test on the given `ZyanVector` instance.
 84   *
 85   * @param   vector  A pointer to the `ZyanVector` instance.
 86   *
 87   * @return  A zyan status code.
 88   */
 89  static ZyanStatus PerformBasicTests(ZyanVector* vector)
 90  {
 91      ZYAN_ASSERT(vector);
 92  
 93      static       TestStruct  e_v;
 94      static const TestStruct* e_p;
 95  
 96      // Insert `20` elements. The vector automatically manages its size
 97      for (ZyanU32 i = 0; i < 20; ++i)
 98      {
 99          InitTestdata(&e_v, i);
100          ZYAN_CHECK(ZyanVectorPushBack(vector, &e_v));
101          printf("i=%d cap=%" PRIuPTR, i, vector->capacity);
102      }
103  
104      // Remove elements `#05..#09`
105      ZYAN_CHECK(ZyanVectorDeleteRange(vector, 5, 5));
106  
107      // Insert a new element at index `#05`
108      InitTestdata(&e_v, 12345678);
109      ZYAN_CHECK(ZyanVectorInsert(vector, 5, &e_v));
110  
111      // Change value of element `#15`
112      InitTestdata(&e_v, 87654321);
113      ZYAN_CHECK(ZyanVectorSet(vector, 10, &e_v));
114  
115      // Print `u64` of all vector elements
116      ZyanUSize value;
117      ZYAN_CHECK(ZyanVectorGetSize(vector, &value));
118      puts("ELEMENTS");
119      for (ZyanUSize i = 0;  i < value; ++i)
120      {
121          ZYAN_CHECK(ZyanVectorGetPointer(vector, i, (const void**)&e_p));
122          printf("  Element #%02" PRIuPTR ": %08" PRIu64 "\n", i, e_p->u64);
123      }
124  
125      // Print infos
126      puts("INFO");
127      printf("  Size       : %08" PRIuPTR "\n", value);
128      ZYAN_CHECK(ZyanVectorGetCapacity(vector, &value));
129      printf("  Capacity   : %08" PRIuPTR "\n\n", value);
130  
131      return ZYAN_STATUS_SUCCESS;
132  }
133  
134  /**
135   * A dummy comparison function for the `TestStruct` that uses the `u32` field as key
136   * value.
137   *
138   * @param   left    A pointer to the first element.
139   * @param   right   A pointer to the second element.
140   *
141   * @return  Returns values in the following range:
142   *          `left == right -> result == 0`
143   *          `left <  right -> result  < 0`
144   *          `left >  right -> result  > 0`
145   */
146  static ZyanI32 TestDataComparison(const TestStruct* left, const TestStruct* right)
147  {
148      ZYAN_ASSERT(left);
149      ZYAN_ASSERT(right);
150  
151      if (left->u32 < right->u32)
152      {
153          return -1;
154      }
155      if (left->u32 > right->u32)
156      {
157          return  1;
158      }
159      return 0;
160  }
161  
162  /**
163   * Tests the binary-search functionality of the given `ZyanVector` instance.
164   *
165   * @param   vector  A pointer to the `ZyanVector` instance.
166   *
167   * @return  A zyan status code.
168   */
169  static ZyanStatus PerformBinarySearchTest(ZyanVector* vector)
170  {
171      ZYAN_ASSERT(vector);
172  
173      static       TestStruct  e_v;
174      static const TestStruct* e_p;
175  
176      ZyanUSize value;
177      ZYAN_CHECK(ZyanVectorGetCapacity(vector, &value));
178  
179      // Create a sorted test vector
180      for (ZyanUSize i = 0; i < value; ++i)
181      {
182          const ZyanU32 n = rand() % 100;
183          InitTestdata(&e_v, n);
184  
185          ZyanUSize found_index;
186          ZYAN_CHECK(ZyanVectorBinarySearch(vector, &e_v, &found_index,
187              (ZyanComparison)&TestDataComparison));
188          ZYAN_CHECK(ZyanVectorInsert(vector, found_index, &e_v));
189      }
190  
191      // Print `u32` of all vector elements
192      ZYAN_CHECK(ZyanVectorGetSize(vector, &value));
193      puts("ELEMENTS");
194      for (ZyanUSize i = 0;  i < value; ++i)
195      {
196          ZYAN_CHECK(ZyanVectorGetPointer(vector, i, (const void**)&e_p));
197          printf("  Element #%02" PRIuPTR ": %08" PRIu32 "\n", i, e_p->u32);
198      }
199  
200      return ZYAN_STATUS_SUCCESS;
201  }
202  
203  /**
204   * Performs basic tests on a vector that dynamically manages memory.
205   *
206   * @return  A zyan status code.
207   */
208  static ZyanStatus TestDynamic(void)
209  {
210      // Initialize vector with a base capacity of `10` elements
211      ZyanVector vector;
212      ZYAN_CHECK(ZyanVectorInit(&vector, sizeof(TestStruct), 10, ZYAN_NULL));
213  
214      ZYAN_CHECK(PerformBasicTests(&vector));
215      ZYAN_CHECK(ZyanVectorClear(&vector));
216      ZYAN_CHECK(ZyanVectorReserve(&vector, 20));
217      ZYAN_CHECK(PerformBinarySearchTest(&vector));
218  
219      // Cleanup
220      return ZyanVectorDestroy(&vector);
221  }
222  
223  /**
224   * Performs basic tests on a vector that uses a static buffer.
225   *
226   * @return  A zyan status code.
227   */
228  static ZyanStatus TestStatic(void)
229  {
230      static TestStruct buffer[20];
231  
232      // Initialize vector to use a static buffer with a total capacity of `20` elements.
233      ZyanVector vector;
234      ZYAN_CHECK(ZyanVectorInitCustomBuffer(&vector, sizeof(TestStruct), buffer,
235          ZYAN_ARRAY_LENGTH(buffer), ZYAN_NULL));
236  
237      // Compare elements
238      ZyanUSize size;
239      ZYAN_CHECK(ZyanVectorGetSize(&vector, &size));
240      for (ZyanUSize i = 0;  i < size; ++i)
241      {
242          static TestStruct* element;
243          ZYAN_CHECK(ZyanVectorGetPointer(&vector, i, (const void**)&element));
244          if (element->u64 != buffer[i].u64)
245          {
246              return ZYAN_STATUS_INVALID_OPERATION;
247          }
248      }
249  
250      ZYAN_CHECK(PerformBasicTests(&vector));
251      ZYAN_CHECK(ZyanVectorClear(&vector));
252      ZYAN_CHECK(PerformBinarySearchTest(&vector));
253  
254      // Cleanup
255      return ZyanVectorDestroy(&vector);
256  }
257  
258  /* ---------------------------------------------------------------------------------------------- */
259  /* Custom allocator                                                                               */
260  /* ---------------------------------------------------------------------------------------------- */
261  
262  static ZyanStatus AllocatorAllocate(ZyanAllocator* allocator, void** p, ZyanUSize element_size,
263      ZyanUSize n)
264  {
265      ZYAN_ASSERT(allocator);
266      ZYAN_ASSERT(p);
267      ZYAN_ASSERT(element_size);
268      ZYAN_ASSERT(n);
269  
270      ZYAN_UNUSED(allocator);
271  
272      *p = ZYAN_MALLOC(element_size * n);
273      if (!*p)
274      {
275          return ZYAN_STATUS_NOT_ENOUGH_MEMORY;
276      }
277  
278      return ZYAN_STATUS_SUCCESS;
279  }
280  
281  static ZyanStatus AllocatorReallocate(ZyanAllocator* allocator, void** p, ZyanUSize element_size,
282      ZyanUSize n)
283  {
284      ZYAN_ASSERT(allocator);
285      ZYAN_ASSERT(p);
286      ZYAN_ASSERT(element_size);
287      ZYAN_ASSERT(n);
288  
289      ZYAN_UNUSED(allocator);
290  
291      void* const x = ZYAN_REALLOC(*p, element_size * n);
292      if (!x)
293      {
294          return ZYAN_STATUS_NOT_ENOUGH_MEMORY;
295      }
296      *p = x;
297  
298      return ZYAN_STATUS_SUCCESS;
299  }
300  
301  static ZyanStatus AllocatorDeallocate(ZyanAllocator* allocator, void* p, ZyanUSize element_size,
302      ZyanUSize n)
303  {
304      ZYAN_ASSERT(allocator);
305      ZYAN_ASSERT(p);
306      ZYAN_ASSERT(element_size);
307      ZYAN_ASSERT(n);
308  
309      ZYAN_UNUSED(allocator);
310      ZYAN_UNUSED(element_size);
311      ZYAN_UNUSED(n);
312  
313      ZYAN_FREE(p);
314  
315      return ZYAN_STATUS_SUCCESS;
316  }
317  
318  /* ---------------------------------------------------------------------------------------------- */
319  
320  /**
321   * Performs basic tests on a vector that dynamically manages memory using a custom
322   * allocator and modified growth-factor/shrink-threshold.
323   *
324   * @return  A zyan status code.
325   */
326  static ZyanStatus TestAllocator(void)
327  {
328      ZyanAllocator allocator;
329      ZYAN_CHECK(ZyanAllocatorInit(&allocator, &AllocatorAllocate, &AllocatorReallocate,
330          &AllocatorDeallocate));
331  
332      // Initialize vector with a base capacity of `10` elements. Growth-factor is set to 10 and
333      // dynamic shrinking is disabled
334      ZyanVector vector;
335      ZYAN_CHECK(ZyanVectorInitEx(&vector, sizeof(TestStruct), 5, ZYAN_NULL, &allocator,
336          10, 0));
337  
338      static TestStruct  e_v;
339  
340      // Insert `10` elements. The vector automatically manages its size
341      for (ZyanU32 i = 0; i < 10; ++i)
342      {
343          InitTestdata(&e_v, i);
344          ZYAN_CHECK(ZyanVectorPushBack(&vector, &e_v));
345      }
346  
347      // Check capacity
348      ZyanUSize value;
349      ZYAN_CHECK(ZyanVectorGetCapacity(&vector, &value));
350      if (value != 60) // (5 + 1) * 10.0f
351      {
352          return ZYAN_STATUS_INVALID_OPERATION;
353      }
354  
355      // Remove all elements
356      ZYAN_CHECK(ZyanVectorClear(&vector));
357  
358      // Print infos
359      puts("INFO");
360      ZYAN_CHECK(ZyanVectorGetSize(&vector, &value));
361      printf("  Size       : %08" PRIuPTR "\n", value);
362      ZYAN_CHECK(ZyanVectorGetCapacity(&vector, &value));
363      printf("  Capacity   : %08" PRIuPTR "\n\n", value);
364  
365      // Cleanup
366      return ZyanVectorDestroy(&vector);
367  }
368  
369  /* ---------------------------------------------------------------------------------------------- */
370  
371  /* ============================================================================================== */
372  /* Entry point                                                                                    */
373  /* ============================================================================================== */
374  
375  int main()
376  {
377      time_t t;
378      srand((unsigned)time(&t));
379  
380      if (!ZYAN_SUCCESS(TestDynamic()))
381      {
382          return EXIT_FAILURE;
383      }
384      if (!ZYAN_SUCCESS(TestStatic()))
385      {
386          return EXIT_FAILURE;
387      }
388      if (!ZYAN_SUCCESS(TestAllocator()))
389      {
390          return EXIT_FAILURE;
391      }
392  
393      return EXIT_SUCCESS;
394  }
395  
396  /* ============================================================================================== */