BLI_linklist: Add a new helper to move an item (identified by its current index)...
authorBastien Montagne <montagne29@wanadoo.fr>
Tue, 10 Feb 2015 16:28:55 +0000 (17:28 +0100)
committerBastien Montagne <montagne29@wanadoo.fr>
Tue, 10 Feb 2015 18:20:36 +0000 (19:20 +0100)
source/blender/blenlib/BLI_linklist.h
source/blender/blenlib/intern/BLI_linklist.c

index 2ca363ee7800a94564fbab946fbd0b6f4acb51d2..8dbf7b4a908f8d3e2c44d6e3eb1359cacab0ce35 100644 (file)
@@ -54,6 +54,8 @@ struct LinkNode *BLI_linklist_find(struct LinkNode *list, int index);
 
 void    BLI_linklist_reverse(struct LinkNode **listp);
 
+void    BLI_linklist_move_item(struct LinkNode **listp, int curr_index, int new_index);
+
 void    BLI_linklist_prepend_nlink(struct LinkNode **listp, void *ptr, struct LinkNode *nlink);
 void    BLI_linklist_prepend(struct LinkNode **listp, void *ptr);
 void    BLI_linklist_prepend_arena(struct LinkNode **listp, void *ptr, struct MemArena *ma);
index 6b79cf97e860076a92b49d932ff2f6a18dc6795e..391f3ef77025131e8e09a7c639577fd30fd266c2 100644 (file)
@@ -86,6 +86,77 @@ void BLI_linklist_reverse(LinkNode **listp)
        *listp = rhead;
 }
 
+/**
+ * Move an item from its current position to a new one inside a single-linked list.
+ * Note *listp may be modified.
+ */
+void BLI_linklist_move_item(LinkNode **listp, int curr_index, int new_index)
+{
+       LinkNode *lnk, *lnk_psrc = NULL, *lnk_pdst = NULL;
+       int i;
+
+       if (new_index == curr_index) {
+               return;
+       }
+
+       if (new_index < curr_index) {
+               for (lnk = *listp, i = 0; lnk; lnk = lnk->next, i++) {
+                       if (i == new_index - 1) {
+                               lnk_pdst = lnk;
+                       }
+                       else if (i == curr_index - 1) {
+                               lnk_psrc = lnk;
+                               break;
+                       }
+               }
+
+               if (!(lnk_psrc && lnk_psrc->next && (!lnk_pdst || lnk_pdst->next))) {
+                       /* Invalid indices, abort. */
+                       return;
+               }
+
+               lnk = lnk_psrc->next;
+               lnk_psrc->next = lnk->next;
+               if (lnk_pdst) {
+                       lnk->next = lnk_pdst->next;
+                       lnk_pdst->next = lnk;
+               }
+               else {
+                       /* destination is first element of the list... */
+                       lnk->next = *listp;
+                       *listp = lnk;
+               }
+       }
+       else {
+               for (lnk = *listp, i = 0; lnk; lnk = lnk->next, i++) {
+                       if (i == new_index) {
+                               lnk_pdst = lnk;
+                               break;
+                       }
+                       else if (i == curr_index - 1) {
+                               lnk_psrc = lnk;
+                       }
+               }
+
+               if (!(lnk_pdst && (!lnk_psrc || lnk_psrc->next))) {
+                       /* Invalid indices, abort. */
+                       return;
+               }
+
+               if (lnk_psrc) {
+                       lnk = lnk_psrc->next;
+                       lnk_psrc->next = lnk->next;
+               }
+               else {
+                       /* source is first element of the list... */
+                       lnk = *listp;
+                       *listp = lnk->next;
+               }
+               lnk->next = lnk_pdst->next;
+               lnk_pdst->next = lnk;
+       }
+}
+
 /**
  * A version of prepend that takes the allocated link.
  */