github.com/256dpi/max-go@v0.7.0/lib/max/ext_linklist.h (about) 1 #ifndef _EXT_LINKLIST_H_ 2 #define _EXT_LINKLIST_H_ 3 4 #include "ext_prefix.h" 5 #include "ext_atomic.h" 6 #include "ext_mess.h" 7 8 #if C74_PRAGMA_STRUCT_PACKPUSH 9 #pragma pack(push, 2) 10 #elif C74_PRAGMA_STRUCT_PACK 11 #pragma pack(2) 12 #endif 13 14 /** A linklist element. This struct is provided for debugging convenience, 15 but should be considered opaque and is subject to change without notice. 16 17 @ingroup linklist 18 @see t_linklist 19 */ 20 typedef struct _llelem 21 { 22 t_object *thing; 23 struct _llelem *next; 24 struct _llelem *prev; 25 long flags; 26 long marked; 27 } t_llelem; 28 29 30 /** The linklist object. This struct is provided for debugging convenience, 31 but should be considered opaque and is subject to change without notice. 32 33 @ingroup linklist 34 @see t_llelem 35 */ 36 typedef struct _linklist 37 { 38 t_object ob; 39 long count; 40 t_llelem *head; 41 t_llelem *tail; 42 long readonly; 43 void *lock; 44 t_llelem *cache; 45 long flags; 46 t_llelem *pending; // used to help prevent accessing deleted elements during complex list traversal (methodall, etc) 47 t_uint32_atomic iterating; 48 long sweep; 49 long locktype; 50 } t_linklist; 51 52 #if C74_PRAGMA_STRUCT_PACKPUSH 53 #pragma pack(pop) 54 #elif C74_PRAGMA_STRUCT_PACK 55 #pragma pack() 56 #endif 57 58 enum { 59 LINKLIST_PRUNE_CHUCK = 0x00000001L // chucks object rather than deletes it in linklist_prune 60 }; 61 62 /** 63 Comparison function pointer type. 64 65 Methods that require a comparison function pointer to be passed in use this type. 66 It should return <code>true</code> or <code>false</code> depending on the outcome of the 67 comparison of the two linklist items passed in as arguments. 68 69 @ingroup datastore 70 @see linklist_match() 71 @see hashtab_findfirst() 72 @see indexmap_sort() 73 */ 74 typedef long (*t_cmpfn)(void *, void *); 75 76 BEGIN_USING_C_LINKAGE 77 78 /** 79 Create a new linklist object. 80 You can free the linklist by calling object_free() on the linklist's pointer, 81 or by using linklist_chuck(). 82 83 @ingroup linklist 84 @return Pointer to the new linklist object. 85 86 @see object_free() 87 @see linklist_chuck() 88 */ 89 t_linklist *linklist_new(void); 90 91 92 /** 93 Free a linklist, but don't free the items it contains. 94 95 The linklist can contain a variety of different types of data. 96 By default, the linklist assumes that all items are max objects with a valid 97 #t_object header. 98 99 You can alter the linklist's notion of what it contains by using the 100 linklist_flags() method. 101 102 When you free the linklist by calling object_free() it then tries to free all of the items it contains. 103 If the linklist is storing a custom type of data, or should otherwise not free the data it contains, 104 then call linklist_chuck() to free the object instead of object_free(). 105 106 @ingroup linklist 107 @param x The linklist object to be freed. 108 @see object_free 109 */ 110 void linklist_chuck(t_linklist *x); 111 112 113 /** 114 Return the number of items in a linklist object. 115 116 @ingroup linklist 117 118 @param x The linklist instance. 119 @return The number of items in the linklist object. 120 */ 121 t_atom_long linklist_getsize(t_linklist *x); 122 123 124 /** 125 Return the item stored in a linklist at a specified index. 126 127 @ingroup linklist 128 129 @param x The linklist instance. 130 @param index The index in the linklist to fetch. Indices are zero-based. 131 @return The item from the linklist stored at index. 132 If there is no item at the index, <code>NULL</code> is returned 133 */ 134 void *linklist_getindex(t_linklist *x, long index); 135 136 137 // private 138 t_llelem *linklist_index2ptr(t_linklist *x, long index); 139 140 141 // private 142 long linklist_ptr2index(t_linklist *x, t_llelem *p); 143 144 145 /** 146 Return an item's index, given the item itself. 147 148 @ingroup linklist 149 150 @param x The linklist instance. 151 @param p The item pointer to search for in the linklist. 152 @return The index of the item given in the linklist. 153 If the item is not in the linklist #MAX_ERR_GENERIC is returned. 154 */ 155 t_atom_long linklist_objptr2index(t_linklist *x, void *p); 156 157 158 /** 159 Add an item to the end of the list. 160 161 @ingroup linklist 162 163 @param x The linklist instance. 164 @param o The item pointer to append to the linked-list. 165 @return The updated size of the linklist after appending the new item, or -1 if the append failed. 166 */ 167 t_atom_long linklist_append(t_linklist *x, void *o); 168 169 170 /** Insert an item into the list at the specified index. 171 @ingroup linklist 172 @param x The linklist instance. 173 @param o The item pointer to insert. 174 @param index The index at which to insert. Index 0 is the head of the list. 175 @return The index of the item in the linklist, or -1 if the insert failed. 176 */ 177 t_atom_long linklist_insertindex(t_linklist *x, void *o, long index); 178 179 180 /** Insert an item into the list, keeping the list sorted according to a specified comparison function. 181 @ingroup linklist 182 @param x The linklist instance. 183 @param o The item pointer to insert. 184 @param cmpfn A comparison function by which the list should be sorted. 185 @return The index of the new item in the linklist, or -1 if the insert failed. 186 */ 187 long linklist_insert_sorted(t_linklist *x, void *o, long cmpfn(void *, void *)); 188 189 190 /** 191 Insert an item into the list after another specified item. 192 193 @ingroup linklist 194 195 @param x The linklist instance. 196 @param o The item pointer to insert. 197 @param objptr The item pointer after which to insert in the list. 198 199 @return An opaque linklist element. 200 */ 201 t_llelem *linklist_insertafterobjptr(t_linklist *x, void *o, void *objptr); // inserts object o after objptr 202 203 204 /** 205 Insert an item into the list before another specified item. 206 207 @ingroup linklist 208 209 @param x The linklist instance. 210 @param o The item pointer to insert. 211 @param objptr The item pointer before which to insert in the list. 212 213 @return An opaque linklist element. 214 */ 215 t_llelem *linklist_insertbeforeobjptr(t_linklist *x, void *o, void *objptr); // inserts object o before objptr 216 217 218 /** 219 Move an existing item in the list to a position after another specified item in the list. 220 221 @ingroup linklist 222 223 @param x The linklist instance. 224 @param o The item pointer to insert. 225 @param objptr The item pointer after which to move o in the list. 226 227 @return An opaque linklist element. 228 */ 229 t_llelem *linklist_moveafterobjptr(t_linklist *x, void *o, void *objptr); // move existing object o after objptr 230 231 232 /** 233 Move an existing item in the list to a position before another specified item in the list. 234 235 @ingroup linklist 236 237 @param x The linklist instance. 238 @param o The item pointer to insert. 239 @param objptr The item pointer before which to move o in the list. 240 241 @return An opaque linklist element. 242 */ 243 t_llelem *linklist_movebeforeobjptr(t_linklist *x, void *o, void *objptr); // move existing object o before objptr 244 245 246 // private 247 t_llelem *linklist_insertptr(t_linklist *x, void *o, t_llelem *p); //inserts before ptr 248 249 250 /** 251 Remove the item from the list at the specified index and free it. 252 253 The linklist can contain a variety of different types of data. 254 By default, the linklist assumes that all items are max objects with a valid 255 #t_object header. Thus by default, it frees items by calling object_free() on them. 256 257 You can alter the linklist's notion of what it contains by using the 258 linklist_flags() method. 259 260 If you wish to remove an item from the linklist and free it yourself, then you 261 should use linklist_chuckptr(). 262 263 @ingroup linklist 264 265 @param x The linklist instance. 266 @param index The index of the item to delete. 267 @return Returns the index number of the item delted, or -1 if the operation failed. 268 269 @see linklist_chuckindex 270 @see linklist_chuckobject 271 */ 272 t_atom_long linklist_deleteindex(t_linklist *x, long index); 273 274 275 /** 276 Remove the item from the list at the specified index. 277 278 You are responsible for freeing any memory associated with the item that is 279 removed from the linklist. 280 281 @ingroup linklist 282 283 @param x The linklist instance. 284 @param index The index of the item to remove. 285 @return Returns #MAX_ERR_NONE on successful removal, otherwise returns #MAX_ERR_GENERIC 286 287 @see linklist_deleteindex 288 @see linklist_chuckobject 289 */ 290 long linklist_chuckindex(t_linklist *x, long index); 291 292 293 /** 294 Remove the specified item from the list. 295 296 You are responsible for freeing any memory associated with the item that is 297 removed from the linklist. 298 299 @ingroup linklist 300 301 @param x The linklist instance. 302 @param o The pointer to the item to remove. 303 304 @see linklist_deleteindex 305 @see linklist_chuckindex 306 @see linklist_deleteobject 307 */ 308 long linklist_chuckobject(t_linklist *x, void *o); 309 310 311 /** 312 Delete the specified item from the list. 313 314 The object is removed from the list and deleted. 315 The deletion is done with respect to any flags passed to linklist_flags. 316 317 @ingroup linklist 318 319 @param x The linklist instance. 320 @param o The pointer to the item to delete. 321 322 @see linklist_deleteindex 323 @see linklist_chuckindex 324 @see linklist_chuckobject 325 */ 326 long linklist_deleteobject(t_linklist *x, void *o); 327 328 // private 329 long linklist_deleteptr(t_linklist *x, t_llelem *p); 330 331 332 // private 333 long linklist_chuckptr(t_linklist *x, t_llelem *p); //like delete, but don't free it 334 335 336 /** 337 Remove and free all items in the list. 338 339 Freeing items in the list is subject to the same rules as linklist_deleteindex(). 340 You can alter the linklist's notion of what it contains, and thus how items are freed, 341 by using the linklist_flags() method. 342 343 @ingroup linklist 344 @param x The linklist instance. 345 */ 346 void linklist_clear(t_linklist *x); 347 348 349 // private 350 long linklist_insertnodeindex(t_linklist *x, t_llelem *p, long index); 351 352 // private 353 t_llelem *linklist_insertnodeptr(t_linklist *x, t_llelem *p1, t_llelem *p2); 354 355 // private 356 long linklist_appendnode(t_linklist *x, t_llelem *p); 357 358 // private 359 t_llelem *linklistelem_new(void); 360 361 // private 362 void linklistelem_free(t_linklist *x, t_llelem *elem); 363 364 365 /** 366 Retrieve linklist items as an array of pointers. 367 368 @ingroup linklist 369 370 @param x The linklist instance. 371 @param a The address of the first pointer in the array to fill. 372 @param max The number of pointers in the array. 373 @return The number of items from the list actually returned in the array. 374 */ 375 t_atom_long linklist_makearray(t_linklist *x, void **a, long max); 376 377 378 /** 379 Reverse the order of items in the linked-list. 380 381 @ingroup linklist 382 @param x The linklist instance. 383 */ 384 void linklist_reverse(t_linklist *x); 385 386 387 /** 388 Rotate items in the linked list in circular fashion. 389 390 @ingroup linklist 391 @param x The linklist instance. 392 @param i The number of positions in the list to shift items. 393 */ 394 void linklist_rotate(t_linklist *x, long i); 395 396 397 /** 398 Randomize the order of items in the linked-list. 399 400 @ingroup linklist 401 @param x The linklist instance. 402 */ 403 void linklist_shuffle(t_linklist *x); 404 405 406 /** 407 Swap the position of two items in the linked-list, specified by index. 408 409 @ingroup linklist 410 @param x The linklist instance. 411 @param a The index of the first item to swap. 412 @param b The index of the second item to swap. 413 */ 414 void linklist_swap(t_linklist *x, long a, long b); 415 416 417 /** 418 Search the linked list for the first item meeting defined criteria. 419 The items in the list are traversed, calling a specified comparison function on each 420 until the comparison function returns true. 421 422 @ingroup linklist 423 @param x The linklist instance. 424 @param o The address to pointer that will be set with the matching item. 425 @param cmpfn The function used to determine a match in the list. 426 @param cmpdata An argument to be passed to the #t_cmpfn. 427 This will be passed as the second of the two args to the #t_cmpfn. 428 The first arg will be the linklist item at each iteration in the list. 429 @return The index of the matching item, or -1 if no match is found. 430 431 @remark The following shows how to manually do what linklist_chuckobject() does. 432 @code 433 void *obj; 434 long index; 435 436 index = linklist_findfirst(x, &obj, #linklist_match, o); 437 if(index != -1) 438 linklist_chuckindex(x, index); 439 @endcode 440 441 @see linklist_match 442 @see t_cmpfn 443 @see linklist_findall 444 */ 445 t_atom_long linklist_findfirst(t_linklist *x, void **o, long cmpfn(void *, void *), void *cmpdata); 446 447 448 /** 449 Search the linked list for all items meeting defined criteria. 450 The items in the list are traversed, calling a specified comparison function on each, 451 and returning the matches in another linklist. 452 453 @ingroup linklist 454 @param x The linklist instance. 455 @param out The address to a #t_linklist pointer. 456 You should initialize the pointer to NULL before calling linklist_findall(). 457 A new linklist will be created internally by linklist_findall() and returned here. 458 @param cmpfn The function used to determine a match in the list. 459 @param cmpdata An argument to be passed to the #t_cmpfn. 460 This will be passed as the second of the two args to the #t_cmpfn. 461 The first arg will be the linklist item at each iteration in the list. 462 463 @remark The following example assumes you have a linklist called myLinkList, and #t_cmpfn called 464 myCmpFunction, and some sort of data to match in someCriteria. 465 @code 466 t_linklist *results = NULL; 467 468 linklist_findall(myLinkList, &results, myCmpFunction, (void *)someCriteria); 469 // do something here with the 'results' linklist 470 // then free the results linklist 471 linklist_chuck(results); 472 @endcode 473 474 @see linklist_match 475 @see t_cmpfn 476 @see linklist_findfirst 477 */ 478 void linklist_findall(t_linklist *x, t_linklist **out, long cmpfn(void *, void *), void *cmpdata); 479 480 481 /** 482 Call the named message on every object in the linklist. 483 The linklist_methodall() function requires that all items in the linklist are 484 object instances with a valid t_object header. 485 486 @ingroup linklist 487 @param x The linklist instance. 488 @param s The name of the message to send to the objects. 489 @param ... Any arguments to be sent with the message. 490 491 @remark Internally, this function uses object_method(), meaning that no errors will be 492 posted if the message name does not exist for the object. It also means that 493 messages sent methods with #A_GIMME definitions will need to be given a symbol 494 argument prior to the argc and argv array information. 495 */ 496 void linklist_methodall(t_linklist *x, t_symbol *s, ...); 497 498 #ifdef C74_X64 499 #define linklist_methodall(...) C74_VARFUN(linklist_methodall_imp, __VA_ARGS__) 500 #endif 501 502 void linklist_methodall_imp(void *x, void *sym, void *p1, void *p2, void *p3, void *p4, void *p5, void *p6, void *p7, void *p8); 503 504 505 /** 506 Call the named message on an object specified by index. 507 The item must be an object instance with a valid t_object header. 508 509 @ingroup linklist 510 @param x The linklist instance. 511 @param i The index of the item to which to send the message. 512 @param s The name of the message to send to the objects. 513 @param ... Any arguments to be sent with the message. 514 515 @remark Internally, this function uses object_method(), meaning that no errors will be 516 posted if the message name does not exist for the object. It also means that 517 messages sent methods with #A_GIMME definitions will need to be given a symbol 518 argument prior to the argc and argv array information. 519 */ 520 void *linklist_methodindex(t_linklist *x, t_atom_long i, t_symbol *s, ...); 521 522 #ifdef C74_X64 523 #define linklist_methodindex(...) C74_VARFUN(linklist_methodindex_imp, __VA_ARGS__) 524 #endif 525 526 void *linklist_methodindex_imp(void *x, void *i, void *s, void *p1, void *p2, void *p3, void *p4, void *p5, void *p6, void *p7); // 10 arg varfun, so we lose an arg 527 528 529 /** 530 Sort the linked list. 531 The items in the list are ordered using a #t_cmpfn function that is passed in as an argument. 532 533 @ingroup linklist 534 @param x The linklist instance. 535 @param cmpfn The function used to sort the list. 536 537 @remark The following is example is a real-world example of sorting a linklist of symbols alphabetically 538 by first letter only. First the cmpfn is defined, then it is used in a different function 539 by linklist_sort(). 540 @code 541 long myAlphabeticalCmpfn(void *a, void *b) 542 { 543 t_symbol *s1 = (t_symbol *)a; 544 t_symbol *s2 = (t_symbol *)b; 545 546 if(s1->s_name[0] < s2->s_name[0]) 547 return true; 548 else 549 return false; 550 } 551 552 void mySortMethod(t_myobj *x) 553 { 554 // the linklist was already created and filled with items previously 555 linklist_sort(x->myLinkList, myAlphabeticalCmpfn); 556 } 557 @endcode 558 */ 559 void linklist_sort(t_linklist *x, long cmpfn(void *, void *)); 560 561 562 /** 563 Call the specified function for every item in the linklist. 564 565 @ingroup linklist 566 @param x The linklist instance. 567 @param fun The function to call, specified as function pointer cast to a Max #method. 568 @param arg An argument that you would like to pass to the function being called. 569 570 @remark The linklist_funall() method will call your function for every item in the list. 571 It will pass both a pointer to the item in the list, and any argument that you 572 provide. The following example shows a function that could be called by linklist_funall(). 573 @code 574 void myFun(t_object *myObj, void *myArg) 575 { 576 // do something with myObj and myArg here 577 // myObj is the item in the linklist 578 } 579 @endcode 580 */ 581 void linklist_funall(t_linklist *x, method fun, void *arg); 582 583 584 /** 585 Call the specified function for every item in the linklist. 586 The iteration through the list will halt if the function returns a non-zero value. 587 588 @ingroup linklist 589 @param x The linklist instance. 590 @param fun The function to call, specified as function pointer cast to a Max #method. 591 @param arg An argument that you would like to pass to the function being called. 592 593 @remark The linklist_funall() method will call your function for every item in the list. 594 It will pass both a pointer to the item in the list, and any argument that you 595 provide. The following example shows a function that could be called by linklist_funall(). 596 @code 597 long myFun(t_symbol *myListItemSymbol, void *myArg) 598 { 599 // this function is called by a linklist that contains symbols for its items 600 if(myListItemSymbol == gensym("")){ 601 error("empty symbol -- aborting linklist traversal") 602 return 1; 603 } 604 else{ 605 // do something with the symbol 606 return 0; 607 } 608 } 609 @endcode 610 */ 611 t_atom_long linklist_funall_break(t_linklist *x, method fun, void *arg); 612 613 614 /** 615 Call the specified function for an item specified by index. 616 617 @ingroup linklist 618 @param x The linklist instance. 619 @param i The index of the item to which to send the message. 620 @param fun The function to call, specified as function pointer cast to a Max #method. 621 @param arg An argument that you would like to pass to the function being called. 622 623 @remark The linklist_funindex() method will call your function for an item in the list. 624 It will pass both a pointer to the item in the list, and any argument that you 625 provide. The following example shows a function that could be called by linklist_funindex(). 626 @code 627 void myFun(t_object *myObj, void *myArg) 628 { 629 // do something with myObj and myArg here 630 // myObj is the item in the linklist 631 } 632 @endcode 633 */ 634 void *linklist_funindex(t_linklist *x, long i, method fun, void *arg); 635 636 637 /** 638 Given an item in the list, replace it with a different value. 639 640 @ingroup linklist 641 @param x The linklist instance. 642 @param p An item in the list. 643 @param newp The new value. 644 @return Always returns NULL. 645 */ 646 void *linklist_substitute(t_linklist *x, void *p, void *newp); 647 648 649 /** 650 Given an item in the list, find the next item. 651 This provides an means for walking the list. 652 653 @ingroup linklist 654 @param x The linklist instance. 655 @param p An item in the list. 656 @param next The address of a pointer to set with the next item in the list. 657 */ 658 void *linklist_next(t_linklist *x, void *p, void **next); 659 660 661 /** 662 Given an item in the list, find the previous item. 663 This provides an means for walking the list. 664 665 @ingroup linklist 666 @param x The linklist instance. 667 @param p An item in the list. 668 @param prev The address of a pointer to set with the previous item in the list. 669 */ 670 void *linklist_prev(t_linklist *x, void *p, void **prev); 671 672 673 /** 674 Return the last item (the tail) in the linked-list. 675 676 @ingroup linklist 677 @param x The linklist instance. 678 @param item The address of pointer in which to store the last item in the linked-list. 679 @return always returns NULL 680 */ 681 void *linklist_last(t_linklist *x, void **item); 682 683 684 /** 685 Set the linklist's readonly bit. 686 687 By default the readonly bit is 0, indicating that it is threadsafe for both reading and writing. 688 Setting the readonly bit to 1 will disable the linklist's theadsafety mechanism, increasing 689 performance but at the expense of threadsafe operation. 690 Unless you can guarantee the threading context for a linklist's use, you should leave this set to 0. 691 692 @ingroup linklist 693 @param x The linklist instance. 694 @param readonly A 1 or 0 for setting the readonly bit. 695 */ 696 void linklist_readonly(t_linklist *x, long readonly); 697 698 699 /** 700 Set the linklist's datastore flags. The available flags are enumerated in #e_max_datastore_flags. 701 These flags control the behavior of the linklist, particularly when removing items from the list 702 using functions such as linklist_clear(), linklist_deleteindex(), or when freeing the linklist itself. 703 704 @ingroup linklist 705 @param x The linklist instance. 706 @param flags A valid value from the #e_max_datastore_flags. The default is #OBJ_FLAG_OBJ. 707 */ 708 void linklist_flags(t_linklist *x, long flags); 709 710 711 /** 712 Get the linklist's datastore flags. 713 714 @ingroup linklist 715 @param x The linklist instance. 716 @return The current state of the linklist flags as enumerated in #e_max_datastore_flags. 717 */ 718 t_atom_long linklist_getflags(t_linklist *x); 719 720 721 /** 722 A linklist comparison method that determines if two item pointers are equal. 723 724 @ingroup linklist 725 726 @param a The first item to compare. 727 @param b The second item to compare. 728 @return Returns 1 if the items are equal, otherwise 0. 729 730 @see t_cmpfn 731 */ 732 long linklist_match(void *a, void *b); 733 734 735 END_USING_C_LINKAGE 736 737 #endif // _EXT_LINKLIST_H_ 738