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/List.h> 29 30 /* ============================================================================================== */ 31 /* Internal macros */ 32 /* ============================================================================================== */ 33 34 /** 35 * Returns a pointer to the data of the given `node`. 36 * 37 * @param node A pointer to the `ZyanNodeData` struct. 38 * 39 * @return A pointer to the data of the given `node`. 40 */ 41 #define ZYCORE_LIST_GET_NODE_DATA(node) \ 42 ((void*)(node + 1)) 43 44 /* ============================================================================================== */ 45 /* Internal functions */ 46 /* ============================================================================================== */ 47 48 /* ---------------------------------------------------------------------------------------------- */ 49 /* Helper functions */ 50 /* ---------------------------------------------------------------------------------------------- */ 51 52 /** 53 * Allocates memory for a new list node. 54 * 55 * @param list A pointer to the `ZyanList` instance. 56 * @param node Receives a pointer to the new `ZyanListNode` struct. 57 * 58 * @return A zyan status code. 59 */ 60 static ZyanStatus ZyanListAllocateNode(ZyanList* list, ZyanListNode** node) 61 { 62 ZYAN_ASSERT(list); 63 ZYAN_ASSERT(node); 64 65 const ZyanBool is_dynamic = (list->allocator != ZYAN_NULL); 66 if (is_dynamic) 67 { 68 ZYAN_ASSERT(list->allocator->allocate); 69 ZYAN_CHECK(list->allocator->allocate(list->allocator, (void**)node, 70 sizeof(ZyanListNode) + list->element_size, 1)); 71 } else 72 { 73 if (list->first_unused) 74 { 75 *node = list->first_unused; 76 list->first_unused = (*node)->next; 77 } else 78 { 79 const ZyanUSize size = list->size * (sizeof(ZyanListNode) + list->element_size); 80 if (size + (sizeof(ZyanListNode) + list->element_size) > list->capacity) 81 { 82 return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE; 83 } 84 85 *node = (ZyanListNode*)((ZyanU8*)list->buffer + size); 86 } 87 } 88 89 return ZYAN_STATUS_SUCCESS; 90 } 91 92 /** 93 * Frees memory of a node. 94 * 95 * @param list A pointer to the `ZyanList` instance. 96 * @param node A pointer to the `ZyanListNode` struct. 97 * 98 * @return A zyan status code. 99 */ 100 static ZyanStatus ZyanListDeallocateNode(ZyanList* list, ZyanListNode* node) 101 { 102 ZYAN_ASSERT(list); 103 ZYAN_ASSERT(node); 104 105 const ZyanBool is_dynamic = (list->allocator != ZYAN_NULL); 106 if (is_dynamic) 107 { 108 ZYAN_ASSERT(list->allocator->deallocate); 109 ZYAN_CHECK(list->allocator->deallocate(list->allocator, (void*)node, 110 sizeof(ZyanListNode) + list->element_size, 1)); 111 } else 112 { 113 node->next = list->first_unused; 114 list->first_unused = node; 115 } 116 117 return ZYAN_STATUS_SUCCESS; 118 } 119 120 /* ---------------------------------------------------------------------------------------------- */ 121 122 /* ============================================================================================== */ 123 /* Exported functions */ 124 /* ============================================================================================== */ 125 126 /* ---------------------------------------------------------------------------------------------- */ 127 /* Constructor and destructor */ 128 /* ---------------------------------------------------------------------------------------------- */ 129 130 #ifndef ZYAN_NO_LIBC 131 132 ZYAN_REQUIRES_LIBC ZyanStatus ZyanListInit(ZyanList* list, ZyanUSize element_size, 133 ZyanMemberProcedure destructor) 134 { 135 return ZyanListInitEx(list, element_size, destructor, ZyanAllocatorDefault()); 136 } 137 138 #endif // ZYAN_NO_LIBC 139 140 ZyanStatus ZyanListInitEx(ZyanList* list, ZyanUSize element_size, ZyanMemberProcedure destructor, 141 ZyanAllocator* allocator) 142 { 143 if (!list || !element_size || !allocator) 144 { 145 return ZYAN_STATUS_INVALID_ARGUMENT; 146 } 147 148 list->allocator = allocator; 149 list->size = 0; 150 list->element_size = element_size; 151 list->destructor = destructor; 152 list->head = ZYAN_NULL; 153 list->tail = ZYAN_NULL; 154 list->buffer = ZYAN_NULL; 155 list->capacity = 0; 156 list->first_unused = ZYAN_NULL; 157 158 return ZYAN_STATUS_SUCCESS; 159 } 160 161 ZyanStatus ZyanListInitCustomBuffer(ZyanList* list, ZyanUSize element_size, 162 ZyanMemberProcedure destructor, void* buffer, ZyanUSize capacity) 163 { 164 if (!list || !element_size || !buffer || !capacity) 165 { 166 return ZYAN_STATUS_INVALID_ARGUMENT; 167 } 168 169 list->allocator = ZYAN_NULL; 170 list->size = 0; 171 list->element_size = element_size; 172 list->destructor = destructor; 173 list->head = ZYAN_NULL; 174 list->tail = ZYAN_NULL; 175 list->buffer = buffer; 176 list->capacity = capacity; 177 list->first_unused = ZYAN_NULL; 178 179 return ZYAN_STATUS_SUCCESS; 180 } 181 182 ZyanStatus ZyanListDestroy(ZyanList* list) 183 { 184 if (!list) 185 { 186 return ZYAN_STATUS_INVALID_ARGUMENT; 187 } 188 189 ZYAN_ASSERT(list->element_size); 190 191 const ZyanBool is_dynamic = (list->allocator != ZYAN_NULL); 192 ZyanListNode* node = (is_dynamic || list->destructor) ? list->head : ZYAN_NULL; 193 while (node) 194 { 195 if (list->destructor) 196 { 197 list->destructor(ZYCORE_LIST_GET_NODE_DATA(node)); 198 } 199 200 ZyanListNode* const next = node->next; 201 202 if (is_dynamic) 203 { 204 ZYAN_CHECK(list->allocator->deallocate(list->allocator, node, 205 sizeof(ZyanListNode) + list->element_size, 1)); 206 } 207 208 node = next; 209 } 210 211 return ZYAN_STATUS_SUCCESS; 212 } 213 214 /* ---------------------------------------------------------------------------------------------- */ 215 /* Duplication */ 216 /* ---------------------------------------------------------------------------------------------- */ 217 218 219 220 /* ---------------------------------------------------------------------------------------------- */ 221 /* Item access */ 222 /* ---------------------------------------------------------------------------------------------- */ 223 224 ZyanStatus ZyanListGetHeadNode(const ZyanList* list, const ZyanListNode** node) 225 { 226 if (!list) 227 { 228 return ZYAN_STATUS_INVALID_ARGUMENT; 229 } 230 231 *node = list->head; 232 233 return ZYAN_STATUS_SUCCESS; 234 } 235 236 ZyanStatus ZyanListGetTailNode(const ZyanList* list, const ZyanListNode** node) 237 { 238 if (!list) 239 { 240 return ZYAN_STATUS_INVALID_ARGUMENT; 241 } 242 243 *node = list->tail; 244 245 return ZYAN_STATUS_SUCCESS; 246 } 247 248 ZyanStatus ZyanListGetPrevNode(const ZyanListNode** node) 249 { 250 if (!node || !*node) 251 { 252 return ZYAN_STATUS_INVALID_ARGUMENT; 253 } 254 255 *node = (*node)->prev; 256 257 return ZYAN_STATUS_SUCCESS; 258 } 259 260 ZyanStatus ZyanListGetNextNode(const ZyanListNode** node) 261 { 262 if (!node || !*node) 263 { 264 return ZYAN_STATUS_INVALID_ARGUMENT; 265 } 266 267 *node = (*node)->next; 268 269 return ZYAN_STATUS_SUCCESS; 270 } 271 272 const void* ZyanListGetNodeData(const ZyanListNode* node) 273 { 274 if (!node) 275 { 276 return ZYAN_NULL; 277 } 278 279 return (const void*)ZYCORE_LIST_GET_NODE_DATA(node); 280 } 281 282 ZyanStatus ZyanListGetNodeDataEx(const ZyanListNode* node, const void** value) 283 { 284 if (!node) 285 { 286 return ZYAN_STATUS_INVALID_ARGUMENT; 287 } 288 289 *value = (const void*)ZYCORE_LIST_GET_NODE_DATA(node); 290 291 return ZYAN_STATUS_SUCCESS; 292 } 293 294 void* ZyanListGetNodeDataMutable(const ZyanListNode* node) 295 { 296 if (!node) 297 { 298 return ZYAN_NULL; 299 } 300 301 return ZYCORE_LIST_GET_NODE_DATA(node); 302 } 303 304 ZyanStatus ZyanListGetNodeDataMutableEx(const ZyanListNode* node, void** value) 305 { 306 if (!node) 307 { 308 return ZYAN_STATUS_INVALID_ARGUMENT; 309 } 310 311 *value = ZYCORE_LIST_GET_NODE_DATA(node); 312 313 return ZYAN_STATUS_SUCCESS; 314 } 315 316 ZyanStatus ZyanListSetNodeData(const ZyanList* list, const ZyanListNode* node, const void* value) 317 { 318 if (!list || !node || !value) 319 { 320 return ZYAN_STATUS_INVALID_ARGUMENT; 321 } 322 323 if (list->destructor) 324 { 325 list->destructor(ZYCORE_LIST_GET_NODE_DATA(node)); 326 } 327 328 ZYAN_ASSERT(list->element_size); 329 ZYAN_MEMCPY(ZYCORE_LIST_GET_NODE_DATA(node), value, list->element_size); 330 331 return ZYAN_STATUS_SUCCESS; 332 } 333 334 /* ---------------------------------------------------------------------------------------------- */ 335 /* Insertion */ 336 /* ---------------------------------------------------------------------------------------------- */ 337 338 ZyanStatus ZyanListPushBack(ZyanList* list, const void* item) 339 { 340 if (!list || !item) 341 { 342 return ZYAN_STATUS_INVALID_ARGUMENT; 343 } 344 345 ZyanListNode* node; 346 ZYAN_CHECK(ZyanListAllocateNode(list, &node)); 347 node->prev = list->tail; 348 node->next = ZYAN_NULL; 349 350 ZYAN_MEMCPY(ZYCORE_LIST_GET_NODE_DATA(node), item, list->element_size); 351 352 if (!list->head) 353 { 354 list->head = node; 355 list->tail = node; 356 } else 357 { 358 list->tail->next = node; 359 list->tail = node; 360 } 361 ++list->size; 362 363 return ZYAN_STATUS_SUCCESS; 364 } 365 366 ZyanStatus ZyanListPushFront(ZyanList* list, const void* item) 367 { 368 if (!list || !item) 369 { 370 return ZYAN_STATUS_INVALID_ARGUMENT; 371 } 372 373 ZyanListNode* node; 374 ZYAN_CHECK(ZyanListAllocateNode(list, &node)); 375 node->prev = ZYAN_NULL; 376 node->next = list->head; 377 378 ZYAN_MEMCPY(ZYCORE_LIST_GET_NODE_DATA(node), item, list->element_size); 379 380 if (!list->head) 381 { 382 list->head = node; 383 list->tail = node; 384 } else 385 { 386 list->head->prev= node; 387 list->head = node; 388 } 389 ++list->size; 390 391 return ZYAN_STATUS_SUCCESS; 392 } 393 394 ZyanStatus ZyanListEmplaceBack(ZyanList* list, void** item, ZyanMemberFunction constructor) 395 { 396 if (!list || !item) 397 { 398 return ZYAN_STATUS_INVALID_ARGUMENT; 399 } 400 401 ZyanListNode* node; 402 ZYAN_CHECK(ZyanListAllocateNode(list, &node)); 403 node->prev = list->tail; 404 node->next = ZYAN_NULL; 405 406 *item = ZYCORE_LIST_GET_NODE_DATA(node); 407 if (constructor) 408 { 409 constructor(*item); 410 } 411 412 if (!list->head) 413 { 414 list->head = node; 415 list->tail = node; 416 } else 417 { 418 list->tail->next = node; 419 list->tail = node; 420 } 421 ++list->size; 422 423 return ZYAN_STATUS_SUCCESS; 424 } 425 426 ZyanStatus ZyanListEmplaceFront(ZyanList* list, void** item, ZyanMemberFunction constructor) 427 { 428 if (!list || !item) 429 { 430 return ZYAN_STATUS_INVALID_ARGUMENT; 431 } 432 433 ZyanListNode* node; 434 ZYAN_CHECK(ZyanListAllocateNode(list, &node)); 435 node->prev = ZYAN_NULL; 436 node->next = list->head; 437 438 *item = ZYCORE_LIST_GET_NODE_DATA(node); 439 if (constructor) 440 { 441 constructor(*item); 442 } 443 444 if (!list->head) 445 { 446 list->head = node; 447 list->tail = node; 448 } else 449 { 450 list->head->prev= node; 451 list->head = node; 452 } 453 ++list->size; 454 455 return ZYAN_STATUS_SUCCESS; 456 } 457 458 /* ---------------------------------------------------------------------------------------------- */ 459 /* Deletion */ 460 /* ---------------------------------------------------------------------------------------------- */ 461 462 ZyanStatus ZyanListPopBack(ZyanList* list) 463 { 464 if (!list) 465 { 466 return ZYAN_STATUS_INVALID_ARGUMENT; 467 } 468 if (!list->tail) 469 { 470 return ZYAN_STATUS_INVALID_OPERATION; 471 } 472 473 ZyanListNode* const node = list->tail; 474 475 if (list->destructor) 476 { 477 list->destructor(ZYCORE_LIST_GET_NODE_DATA(node)); 478 } 479 480 list->tail = node->prev; 481 if (list->tail) 482 { 483 list->tail->next = ZYAN_NULL; 484 } 485 if (list->head == node) 486 { 487 list->head = list->tail; 488 } 489 --list->size; 490 491 return ZyanListDeallocateNode(list, node); 492 } 493 494 ZyanStatus ZyanListPopFront(ZyanList* list) 495 { 496 if (!list) 497 { 498 return ZYAN_STATUS_INVALID_ARGUMENT; 499 } 500 if (!list->head) 501 { 502 return ZYAN_STATUS_INVALID_OPERATION; 503 } 504 505 ZyanListNode* const node = list->head; 506 507 if (list->destructor) 508 { 509 list->destructor(ZYCORE_LIST_GET_NODE_DATA(node)); 510 } 511 512 list->head = node->next; 513 if (list->head) 514 { 515 list->head->prev = ZYAN_NULL; 516 } 517 if (list->tail == node) 518 { 519 list->tail = list->head; 520 } 521 --list->size; 522 523 return ZyanListDeallocateNode(list, node); 524 } 525 526 ZyanStatus ZyanListRemove(ZyanList* list, const ZyanListNode* node) 527 { 528 ZYAN_UNUSED(list); 529 ZYAN_UNUSED(node); 530 return ZYAN_STATUS_SUCCESS; 531 } 532 533 ZyanStatus ZyanListRemoveRange(ZyanList* list, const ZyanListNode* first, const ZyanListNode* last) 534 { 535 ZYAN_UNUSED(list); 536 ZYAN_UNUSED(first); 537 ZYAN_UNUSED(last); 538 return ZYAN_STATUS_SUCCESS; 539 } 540 541 ZyanStatus ZyanListClear(ZyanList* list) 542 { 543 return ZyanListResizeEx(list, 0, ZYAN_NULL); 544 } 545 546 /* ---------------------------------------------------------------------------------------------- */ 547 /* Searching */ 548 /* ---------------------------------------------------------------------------------------------- */ 549 550 551 552 /* ---------------------------------------------------------------------------------------------- */ 553 /* Memory management */ 554 /* ---------------------------------------------------------------------------------------------- */ 555 556 ZyanStatus ZyanListResize(ZyanList* list, ZyanUSize size) 557 { 558 return ZyanListResizeEx(list, size, ZYAN_NULL); 559 } 560 561 ZyanStatus ZyanListResizeEx(ZyanList* list, ZyanUSize size, const void* initializer) 562 { 563 if (!list) 564 { 565 return ZYAN_STATUS_INVALID_ARGUMENT; 566 } 567 if (size == list->size) 568 { 569 return ZYAN_STATUS_SUCCESS; 570 } 571 572 if (size == 0) 573 { 574 const ZyanBool is_dynamic = (list->allocator != ZYAN_NULL); 575 ZyanListNode* node = (is_dynamic || list->destructor) ? list->head : ZYAN_NULL; 576 while (node) 577 { 578 if (list->destructor) 579 { 580 list->destructor(ZYCORE_LIST_GET_NODE_DATA(node)); 581 } 582 583 ZyanListNode* const next = node->next; 584 585 if (is_dynamic) 586 { 587 ZYAN_CHECK(list->allocator->deallocate(list->allocator, node, 588 sizeof(ZyanListNode) + list->element_size, 1)); 589 } 590 591 node = next; 592 } 593 594 list->size = 0; 595 list->head = 0; 596 list->tail = 0; 597 list->first_unused = ZYAN_NULL; 598 599 return ZYAN_STATUS_SUCCESS; 600 } 601 602 if (size > list->size) 603 { 604 ZyanListNode* node; 605 for (ZyanUSize i = list->size; i < size; ++i) 606 { 607 ZYAN_CHECK(ZyanListAllocateNode(list, &node)); 608 node->prev = list->tail; 609 node->next = ZYAN_NULL; 610 611 if (initializer) 612 { 613 ZYAN_MEMCPY(ZYCORE_LIST_GET_NODE_DATA(node), initializer, list->element_size); 614 } 615 616 if (!list->head) 617 { 618 list->head = node; 619 list->tail = node; 620 } else 621 { 622 list->tail->next = node; 623 list->tail = node; 624 } 625 626 // `ZyanListAllocateNode` needs the list size 627 ++list->size; 628 } 629 } else 630 { 631 for (ZyanUSize i = size; i < list->size; ++i) 632 { 633 ZyanListNode* const node = list->tail; 634 635 if (list->destructor) 636 { 637 list->destructor(ZYCORE_LIST_GET_NODE_DATA(node)); 638 } 639 640 list->tail = node->prev; 641 if (list->tail) 642 { 643 list->tail->next = ZYAN_NULL; 644 } 645 646 ZYAN_CHECK(ZyanListDeallocateNode(list, node)); 647 } 648 649 list->size = size; 650 } 651 652 return ZYAN_STATUS_SUCCESS; 653 } 654 655 /* ---------------------------------------------------------------------------------------------- */ 656 /* Information */ 657 /* ---------------------------------------------------------------------------------------------- */ 658 659 ZyanStatus ZyanListGetSize(const ZyanList* list, ZyanUSize* size) 660 { 661 if (!list) 662 { 663 return ZYAN_STATUS_INVALID_ARGUMENT; 664 } 665 666 *size = list->size; 667 668 return ZYAN_STATUS_SUCCESS; 669 } 670 671 /* ---------------------------------------------------------------------------------------------- */ 672 673 /* ============================================================================================== */ 674