| /* |
| * list_utils.h |
| * |
| * Utility definitions for the Memory Interface for TI OMAP processors. |
| * |
| * Copyright (C) 2009-2011 Texas Instruments, Inc. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * |
| * * Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * |
| * * Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * * Neither the name of Texas Instruments Incorporated nor the names of |
| * its contributors may be used to endorse or promote products derived |
| * from this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
| * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
| * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
| * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; |
| * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
| * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR |
| * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, |
| * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #ifndef _LIST_UTILS_H_ |
| #define _LIST_UTILS_H_ |
| |
| /* |
| |
| DLIST macros facilitate double-linked lists in a generic fashion. |
| |
| - Double-linked lists simplify list manipulations, so they are preferred to |
| single-linked lists. |
| |
| - Having a double-linked list with a separate header allow accessing the |
| last element of the list easily, so this is also preferred to a double |
| linked list that uses NULL pointers at its ends. |
| |
| Therefore, the following is required: a list info structure (separate from |
| the element structure, although the info structure can be a member of the |
| element structure). The info structure must contain (at least) the |
| following 3 members: |
| |
| *next, *last: as pointers to the info structure. These are the next and |
| previous elements in the list. |
| *me: as a pointer to the element structure. This is how we get to the |
| element itself, as next and last points to another info structure. |
| |
| The list element structure __MAY__ contain the info structure as a member, |
| or a pointer to the info structure if it is desired to be kept separately. |
| In such cases macros are provided to add the elements directly to the list, |
| and automatically set up the info structure fields correctly. You can also |
| iterate through the elements of the list using a pointer to the elements |
| itself, as the list structure can be obtained for each element. |
| |
| Otherwise, macros are provided to manipulate list info structures and |
| link them in any shape or form into double linked lists. This allows |
| having NULL values as members of such lists. |
| |
| :NOTE: If you use a macro with a field argument, you must not have NULL |
| elements because the field of any element must be/point to the list |
| info structure |
| |
| DZLIST macros |
| |
| Having the list info structure separate from the element structure also |
| allows to link elements into many separate lists (with separate info |
| structure fields/pointers). However, for cases where only a single list |
| is desired, a set of easy macros are also provided. |
| |
| These macros combine the element and list structures. These macros |
| require the following 2 members in each element structure: |
| |
| *next, *last: as pointers to the element structure. These are the next and |
| previous elements in the list. |
| |
| :NOTE: In case of the DZLIST-s, the head of the list must be an element |
| structure, where only the next and last members are used. */ |
| |
| /* |
| Usage: |
| |
| DLIST macros are designed for preallocating the list info structures, e.g. in |
| an array. This is why most macros take a list info structure, and not a |
| pointer to a list info structure. |
| |
| Basic linked list consists of element structure and list info structure |
| |
| struct elem { |
| int data; |
| } *elA, *elB; |
| struct list { |
| struct elem *me; |
| struct list *last, *next; |
| } head, *inA, *inB, *in; |
| |
| DLIST_INIT(head); // initialization -> () |
| DLIST_IS_EMPTY(head) == TRUE; // emptiness check |
| |
| // add element at beginning of list -> (1) |
| elA = NEW(struct elem); |
| elA->data = 1; |
| inA = NEW(struct list); |
| DLIST_ADD_AFTER(head, elA, *inA); |
| |
| // add before an element -> (2, 1) |
| elB = NEW(struct elem); |
| elB->data = 2; |
| inB = NEW(struct list); |
| DLIST_ADD_BEFORE(*inA, elB, *inB); |
| |
| // move an element to another position or another list -> (1, 2) |
| DLIST_MOVE_BEFORE(head, *inB); |
| |
| // works even if the position is the same -> (1, 2) |
| DLIST_MOVE_BEFORE(head, *inB); |
| |
| // get first and last elements |
| DLIST_FIRST(head) == elA; |
| DLIST_LAST(head) == elB; |
| |
| // loop through elements |
| DLIST_LOOP(head, in) { |
| P("%d", in->me->data); |
| } |
| |
| // remove element -> (2) |
| DLIST_REMOVE(*inA); |
| FREE(elA); |
| FREE(inA); |
| |
| // delete list |
| DLIST_SAFE_LOOP(head, in, inA) { |
| DLIST_REMOVE(*in); |
| FREE(in->me); |
| FREE(in); |
| } |
| |
| You can combine the element and list info structures to create an easy list, |
| but you still need to specify both element and info structure while adding |
| elements. |
| |
| struct elem { |
| int data; |
| struct elem *me, *last, *next; |
| } head, *el, *elA, *elB; |
| |
| DLIST_INIT(head); // initialization -> () |
| DLIST_IS_EMPTY(head) == TRUE; // emptiness check |
| |
| // add element at beginning of list -> (1) |
| elA = NEW(struct elem); |
| elA->data = 1; |
| DLIST_ADD_AFTER(head, elA, *elA); |
| |
| // add before an element -> (2, 1) |
| elB = NEW(struct elem); |
| elB->data = 2; |
| DLIST_ADD_BEFORE(*elA, elB, *elB); |
| |
| // move an element to another position or another list -> (1, 2) |
| DLIST_MOVE_BEFORE(head, *elB); |
| |
| // works even if the position is the same -> (1, 2) |
| DLIST_MOVE_BEFORE(head, *elB); |
| |
| // get first and last elements |
| DLIST_FIRST(head) == elA; |
| DLIST_LAST(head) == elB; |
| |
| // loop through elements |
| DLIST_LOOP(head, el) { |
| P("%d", el->data); |
| } |
| |
| // remove element -> (2) |
| DLIST_REMOVE(*elA); |
| FREE(elA); |
| |
| // delete list |
| DLIST_SAFE_LOOP(head, el, elA) { |
| DLIST_REMOVE(*el); |
| FREE(el); |
| } |
| |
| Or, you can use a DZLIST. |
| |
| struct elem { |
| int data; |
| struct elem *last, *next; |
| } head, *el, *elA, *elB; |
| |
| DZLIST_INIT(head); // initialization -> () |
| DZLIST_IS_EMPTY(head) == TRUE; // emptiness check |
| |
| // add element at beginning of list -> (1) |
| elA = NEW(struct elem); |
| elA->data = 1; |
| DZLIST_ADD_AFTER(head, *elA); |
| |
| // add before an element -> (2, 1) |
| elB = NEW(struct elem); |
| elB->data = 2; |
| DZLIST_ADD_BEFORE(*elA, *elB); |
| |
| // move an element to another position or another list -> (1, 2) |
| DZLIST_MOVE_BEFORE(head, *elB); |
| |
| // works even if the position is the same -> (1, 2) |
| DZLIST_MOVE_BEFORE(head, *elB); |
| |
| // get first and last elements |
| DZLIST_FIRST(head) == elA; |
| DZLIST_LAST(head) == elB; |
| |
| // loop through elements |
| DZLIST_LOOP(head, el) { |
| P("%d", el->data); |
| } |
| |
| // remove element -> (2) |
| DZLIST_REMOVE(*elA); |
| FREE(elA); |
| |
| // delete list |
| DZLIST_SAFE_LOOP(head, el, elA) { |
| DZLIST_REMOVE(*el); |
| FREE(el); |
| } |
| |
| A better way to get to the list structure from the element structure is to |
| enclose a pointer the list structure in the element structure. This allows |
| getting to the next/previous element from the element itself. |
| |
| struct elem; |
| struct list { |
| struct elem *me; |
| struct list *last, *next; |
| } head, *inA, *inB, *in; |
| struct elem { |
| int data; |
| struct list *list_data; |
| } *elA, *elB, *el; |
| |
| // or |
| |
| struct elem { |
| int data; |
| struct list { |
| struct elem *me; |
| struct list *last, *next; |
| } *list_data; |
| } *elA, *elB, *el; |
| struct list head, *inA, *inB, *in; |
| |
| DLIST_INIT(head); // initialization -> () |
| DLIST_IS_EMPTY(head) == TRUE; // emptiness check |
| |
| // add element at beginning of list -> (1) |
| elA = NEW(struct elem); |
| elA->data = 1; |
| inA = NEW(struct list); |
| DLIST_PADD_AFTER(head, elA, inA, list_data); |
| |
| // add before an element -> (2, 1) |
| elB = NEW(struct elem); |
| elB->data = 2; |
| inB = NEW(struct list); |
| DLIST_PADD_BEFORE(*elA, elB, inB, list_data); |
| |
| // move an element to another position or another list -> (1, 2) |
| DLIST_MOVE_BEFORE(head, *inB); |
| |
| // works even if the position is the same -> (1, 2) |
| DLIST_MOVE_BEFORE(head, *inB); |
| |
| // get first and last elements |
| DLIST_FIRST(head) == elA; |
| DLIST_LAST(head) == elB; |
| |
| // loop through elements |
| DLIST_LOOP(head, in) { |
| P("%d", in->me->data); |
| } |
| DLIST_PLOOP(head, el, list_data) { |
| P("%d", el->data); |
| } |
| |
| // remove element |
| DLIST_REMOVE(*inA); |
| FREE(inA); |
| FREE(elA); |
| |
| // delete list |
| DLIST_SAFE_PLOOP(head, el, elA, list_data) { |
| DLIST_REMOVE(*el->list_data); |
| FREE(el->list_data); |
| FREE(el); |
| } |
| |
| Lastly, you can include the list data in the element structure itself. |
| |
| struct elem { |
| int data; |
| struct list { |
| struct list *last, *next; |
| struct elem *me; |
| } list_data; |
| } *elA, *elB, *el; |
| struct list head, *in; |
| |
| DLIST_INIT(head); // initialization -> () |
| DLIST_IS_EMPTY(head) == TRUE; // emptiness check |
| |
| // add element at beginning of list -> (1) |
| elA = NEW(struct elem); |
| elA->data = 1; |
| DLIST_MADD_AFTER(head, elA, list_data); |
| |
| // add before an element -> (2, 1) |
| elB = NEW(struct elem); |
| elB->data = 2; |
| DLIST_PADD_BEFORE(elA->list_data, elB, list_data); |
| |
| // move an element to another position or another list -> (1, 2) |
| DLIST_MOVE_BEFORE(head, elB->list_data); |
| |
| // works even if the position is the same -> (1, 2) |
| DLIST_MOVE_BEFORE(head, elB->list_data); |
| |
| // get first and last elements |
| DLIST_FIRST(head) == elA; |
| DLIST_LAST(head) == elB; |
| |
| // loop through elements |
| DLIST_LOOP(head, in) { |
| P("%d", in->me->data); |
| } |
| DLIST_MLOOP(head, el, list_data) { |
| P("%d", el->data); |
| } |
| |
| // remove element |
| DLIST_REMOVE(elA->list_data); |
| FREE(elA); |
| |
| // delete list |
| DLIST_SAFE_MLOOP(head, el, elA, list_data) { |
| DLIST_REMOVE(el->list_data); |
| FREE(el); |
| } |
| |
| */ |
| |
| /* -- internal (generic direction) macros -- */ |
| #define DLIST_move__(base, info, next, last) \ |
| ((info).last = &base)->next = ((info).next = (base).next)->last = &(info) |
| #define DLIST_padd__(base, pInfo, pElem, pField, next, last) \ |
| ((pInfo)->last = &base)->next = ((pInfo)->next = (base).next)->last = \ |
| pElem->pField = pInfo |
| #define DLIST_loop__(head, pInfo, next) \ |
| for (pInfo=(head).next; pInfo != &(head); pInfo = (pInfo)->next) |
| #define DLIST_ploop__(head, pElem, pField, next) \ |
| for (pElem=(head).next->me; pElem; pElem = (pElem)->pField->next->me) |
| #define DLIST_mloop__(head, pElem, mField, next) \ |
| for (pElem=(head).next->me; pElem; pElem = (pElem)->mField.next->me) |
| #define DLIST_safe_loop__(head, pInfo, pInfo_safe, next) \ |
| for (pInfo=(head).next; pInfo != &(head); pInfo = pInfo_safe) \ |
| if ((pInfo_safe = (pInfo)->next) || 1) |
| #define DLIST_safe_ploop__(head, pElem, pElem_safe, pField, next) \ |
| for (pElem=(head).next->me; pElem; pElem = pElem_safe) \ |
| if ((pElem_safe = (pElem)->pField->next->me) || 1) |
| #define DLIST_safe_mloop__(head, pElem, pElem_safe, mField, next) \ |
| for (pElem=(head).next->me; pElem; pElem = pElem_safe) \ |
| if ((pElem_safe = (pElem)->mField.next->me) || 1) |
| |
| #define DLIST_IS_EMPTY(head) ((head).next == &(head)) |
| |
| /* Adds the element (referred to by the info structure) before/or after another |
| element (or list header) (base). */ |
| |
| #define DLIST_ADD_AFTER(base, pElem, info) \ |
| (DLIST_move__(base, info, next, last))->me = pElem |
| #define DLIST_ADD_BEFORE(base, pElem, info) \ |
| (DLIST_move__(base, info, last, next))->me = pElem |
| |
| /* Adds the element (referred to by pElem pointer) along with its info |
| structure (referred to by pInfo pointer) before/or after an element or |
| list header (base). It also sets up the list structure header to point to |
| the element as well as the element's field to point back to the list info |
| structure. */ |
| #define DLIST_PADD_BEFORE(base, pElem, pInfo, pField) \ |
| (DLIST_padd__(base, pInfo, pElem, pField, last, next))->me = pElem |
| #define DLIST_PADD_AFTER(base, pElem, pInfo, pField) \ |
| (DLIST_padd__(base, pInfo, pElem, pField, next, last))->me = pElem |
| |
| /* Adds the element (referred to by pElem pointer) before/or after an element or |
| list header (base). It also sets up the list structure header (which is a |
| member of the element's structure) to point to the element. */ |
| #define DLIST_MADD_BEFORE(base, pElem, mField) \ |
| (DLIST_move__(base, pElem->mField, last, next))->me = pElem |
| #define DLIST_MADD_AFTER(base, pElem, mField) \ |
| (DLIST_move__(base, pElem->mField, next, last))->me = pElem |
| |
| /* Removes the element (referred to by the info structure) from its current |
| list. This requires that the element is a part of a list. |
| |
| :NOTE: the info structure will still think that it belongs to the list it |
| used to belong to. However, the old list will not contain this element any |
| longer. You want to discard the info/element after this call. Otherwise, |
| you can use one of the MOVE macros to also add the item to another list, |
| or another place in the same list. */ |
| #define DLIST_REMOVE(info) ((info).last->next = (info).next)->last = (info).last |
| |
| /* Initializes the list header (to an empty list) */ |
| #define DLIST_INIT(head) \ |
| do { (head).me = NULL; (head).next = (head).last = &(head); } while(0) |
| |
| /* These functions move an element (referred to by the info structure) before |
| or after another element (or the list head). |
| :NOTE: This logic also works for moving an element after/before itself. */ |
| #define DLIST_MOVE_AFTER(base, info) \ |
| do { DLIST_REMOVE(info); DLIST_move__(base, info, next, last); } while(0) |
| #define DLIST_MOVE_BEFORE(base, info) \ |
| do { DLIST_REMOVE(info); DLIST_move__(base, info, last, next); } while(0) |
| |
| /* Loops behave syntactically as a for() statement. They traverse the loop |
| variable from the 1st to the last element (or in the opposite direction in |
| case of RLOOP). There are 3 flavors of loops depending on the type of the |
| loop variable. |
| |
| DLIST_LOOP's loop variable is a pointer to the list info structure. You can |
| get to the element by using the 'me' member. Nonetheless, this loop |
| construct allows having NULL elements in the list. |
| |
| DLIST_MLOOP's loop variable is a pointer to a list element. mField is the |
| field of the element containing the list info structure. Naturally, this |
| list cannot have NULL elements. |
| |
| DLIST_PLOOP's loop variable is also a pointer to a list element. Use this |
| construct if the element contains a pointer to the list info structure |
| instead of embedding it directly into the element structure. |
| |
| */ |
| #define DLIST_LOOP(head, pInfo) DLIST_loop__(head, pInfo, next) |
| #define DLIST_RLOOP(head, pInfo) DLIST_loop__(head, pInfo, last) |
| #define DLIST_MLOOP(head, pElem, mField) \ |
| DLIST_mloop__(head, pElem, mField, next) |
| #define DLIST_RMLOOP(head, pElem, mField) \ |
| DLIST_mloop__(head, pElem, mField, last) |
| #define DLIST_PLOOP(head, pElem, pField) \ |
| DLIST_ploop__(head, pElem, pField, next) |
| #define DLIST_RPLOOP(head, pElem, pField) \ |
| DLIST_ploop__(head, pElem, pField, last) |
| |
| /* Safe loops are like ordinary loops, but they allow removal of the current |
| element from the list. They require an extra loop variable that holds the |
| value of the next element in case the current element is moved/removed. */ |
| #define DLIST_SAFE_LOOP(head, pInfo, pInfo_safe) \ |
| DLIST_safe_loop__(head, pInfo, pInfo_safe, next) |
| #define DLIST_SAFE_RLOOP(head, pInfo, pInfo_safe) \ |
| DLIST_safe_loop__(head, pInfo, pInfo_safe, last) |
| #define DLIST_SAFE_MLOOP(head, pElem, pElem_safe, mField) \ |
| DLIST_safe_mloop__(head, pElem, pElem_safe, mField, next) |
| #define DLIST_SAFE_RMLOOP(head, pElem, pElem_safe, mField) \ |
| DLIST_safe_mloop__(head, pElem, pElem_safe, mField, last) |
| #define DLIST_SAFE_PLOOP(head, pElem, pElem_safe, pField) \ |
| DLIST_safe_ploop__(head, pElem, pElem_safe, pField, next) |
| #define DLIST_SAFE_RPLOOP(head, pElem, pElem_safe, pField) \ |
| DLIST_safe_ploop__(head, pElem, pElem_safe, pField, last) |
| |
| /* returns the first element of a list */ |
| #define DLIST_FIRST(head) (head).next->me |
| /* returns the last element of a list */ |
| #define DLIST_LAST(head) (head).last->me |
| |
| |
| /* DZLIST equivalent API - provided so arguments are specified */ |
| #define DZLIST_INIT(head) do { (head).next = (head).last = &(head); } while(0) |
| #define DZLIST_IS_EMPTY(head) DLIST_IS_EMPTY(head) |
| #define DZLIST_FIRST(head) (head).next |
| #define DZLIST_LAST(head) (head).last |
| |
| #define DZLIST_ADD_AFTER(base, elem) DLIST_move__(base, elem, next, last) |
| #define DZLIST_ADD_BEFORE(base, elem) DLIST_move__(base, elem, last, next) |
| |
| #define DZLIST_REMOVE(elem) DLIST_REMOVE(elem) |
| |
| #define DZLIST_MOVE_AFTER(base, elem) DLIST_MOVE_AFTER(base, elem) |
| #define DZLIST_MOVE_BEFORE(base, elem) DLIST_MOVE_BEFORE(base, elem) |
| |
| #define DZLIST_LOOP(head, pElem) DLIST_LOOP(head, pElem) |
| #define DZLIST_RLOOP(head, pElem) DLIST_RLOOP(head, pElem) |
| #define DZLIST_SAFE_LOOP(head, pElem, pElem_safe) \ |
| DLIST_SAFE_LOOP(head, pElem, pElem_safe) |
| #define DZLIST_SAFE_RLOOP(head, pElem, pElem_safe) \ |
| DLIST_SAFE_RLOOP(head, pElem, pElem_safe) |
| |
| #endif |
| |