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 /* ============================================================================================== */