/* * M*LIB - Intrusive List module * * Copyright (c) 2017-2023, Patrick Pelissier * All rights reserved. * 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. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS AND 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 MSTARLIB_I_LIST_H #define MSTARLIB_I_LIST_H #include "m-core.h" #include "m-list.h" // For M_L1ST_ITBASE_DEF /* Interface to add to a structure to enable intrusive doubly-linked support. name: name of the intrusive list. type: name of the type of the structure (aka. struct test_s) - not used currently USAGE: typedef struct tmp_str_s { ... ILIST_INTERFACE(tmpstr, struct tmp_str_s); ... } tmp_str_t; */ #define M_ILIST_INTERFACE(name, type) \ struct m_il1st_head_s name /* Define a doubly-linked intrusive list of a given type. The type needs to have ILIST_INTERFACE(). USAGE: ILIST_DEF(name, type [, oplist_of_the_type]) */ #define M_ILIST_DEF(name, ...) \ M_ILIST_DEF_AS(name, M_F(name,_t), M_F(name,_it_t), __VA_ARGS__) /* Define a doubly-linked intrusive list of a given type as the provided type name_t with the iterator named it_t. The type needs to have ILIST_INTERFACE(). USAGE: ILIST_DEF_AS(name, name_t, it_t, type [, oplist_of_the_type]) */ #define M_ILIST_DEF_AS(name, name_t, it_t, ...) \ M_BEGIN_PROTECTED_CODE \ M_IL1ST_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ ((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t, it_t ), \ (name, __VA_ARGS__, name_t, it_t ))) \ M_END_PROTECTED_CODE /* Define the oplist of a doubly-linked instrusive list of type. USAGE: ILIST_OPLIST(name [, oplist_of_the_type]) */ #define M_ILIST_OPLIST(...) \ M_IL1ST_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ ((__VA_ARGS__, M_BASIC_OPLIST), \ (__VA_ARGS__ ))) /*****************************************************************************/ /******************************** INTERNAL ***********************************/ /*****************************************************************************/ /* Define the basic structure to be added in all objects. */ typedef struct m_il1st_head_s { struct m_il1st_head_s *next; struct m_il1st_head_s *prev; } m_il1st_head_ct; /* Indirection call to allow expanding all arguments */ #define M_IL1ST_OPLIST_P1(arg) M_IL1ST_OPLIST_P2 arg /* Validation of the given oplist */ #define M_IL1ST_OPLIST_P2(name, oplist) \ M_IF_OPLIST(oplist)(M_IL1ST_OPLIST_P3, M_IL1ST_OPLIST_FAILURE)(name, oplist) /* Prepare a clean compilation failure */ #define M_IL1ST_OPLIST_FAILURE(name, oplist) \ ((M_LIB_ERROR(ARGUMENT_OF_ILIST_OPLIST_IS_NOT_AN_OPLIST, name, oplist))) /* Define the oplist of an ilist of type */ #define M_IL1ST_OPLIST_P3(name, oplist) \ (INIT(M_F(name, _init)), \ CLEAR(M_F(name, _clear)), \ INIT_MOVE(M_F(name, _init_move)), \ MOVE(M_F(name, _move)), \ NAME(name), \ TYPE(M_F(name,_ct)), \ RESET(M_F(name,_reset)), \ SUBTYPE(M_F(name,_subtype_ct)), \ EMPTY_P(M_F(name,_empty_p)), \ IT_TYPE(M_F(name,_it_ct)), \ IT_FIRST(M_F(name,_it)), \ IT_SET(M_F(name,_it_set)), \ IT_LAST(M_F(name,_it_last)), \ IT_END(M_F(name,_it_end)), \ IT_END_P(M_F(name,_end_p)), \ IT_LAST_P(M_F(name,_last_p)), \ IT_EQUAL_P(M_F(name,_it_equal_p)), \ IT_NEXT(M_F(name,_next)), \ IT_PREVIOUS(M_F(name,_previous)), \ IT_REF(M_F(name,_ref)), \ IT_CREF(M_F(name,_cref)), \ IT_REMOVE(M_F(name,_remove)), \ M_IF_METHOD(NEW, oplist)(IT_INSERT(M_F(name,_insert)),), \ OPLIST(oplist), \ SPLICE_BACK(M_F(name,_splice_back)) \ ) /******************************** INTERNAL ***********************************/ /* Contract respected by all intrusive lists */ #define M_IL1ST_CONTRACT(name, list) do { \ M_ASSERT(list != NULL); \ M_ASSERT(list->name.prev != NULL); \ M_ASSERT(list->name.next != NULL); \ M_ASSERT(list->name.next->prev == &list->name); \ M_ASSERT(list->name.prev->next == &list->name); \ M_ASSERT(!(list->name.prev == &list->name) || list->name.prev == list->name.next); \ } while (0) #define M_IL1ST_NODE_CONTRACT(node) do { \ M_ASSERT((node) != NULL); \ M_ASSERT((node)->prev != NULL); \ M_ASSERT((node)->next != NULL); \ M_ASSERT((node)->next->prev == node); \ M_ASSERT((node)->prev->next == node); \ } while (0) /* Indirection call to allow expanding all arguments */ #define M_IL1ST_DEF_P1(arg) M_ID( M_IL1ST_DEF_P2 arg ) /* Validate the oplist before going further */ #define M_IL1ST_DEF_P2(name, type, oplist, list_t, it_t) \ M_IF_OPLIST(oplist)(M_IL1ST_DEF_P3, M_IL1ST_DEF_FAILURE)(name, type, oplist, list_t, it_t) /* Stop processing with a compilation failure */ #define M_IL1ST_DEF_FAILURE(name, type, oplist, list_t, it_t) \ M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(ILIST_DEF): the given argument is not a valid oplist: " #oplist) /* Definition of the type and function for an intrusive doubly-linked list. USAGE: name: name of the intrusive list type: type of the object oplist: oplist of the type list_t: type of the intrusive list (name##_t) it_t: iterator of the intrusive list (name##_it_t) */ #define M_IL1ST_DEF_P3(name, type, oplist, list_t, it_t) \ M_IL1ST_DEF_TYPE(name, type, oplist, list_t, it_t) \ M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \ M_IL1ST_DEF_CORE(name, type, oplist, list_t, it_t) \ /* Used of internal macro from m-list */ \ M_L1ST_ITBASE_DEF(name, type, oplist, list_t, it_t) /* Define the type of an intrusive list */ #define M_IL1ST_DEF_TYPE(name, type, oplist, list_t, it_t) \ \ /* Define the list as a structure containing pointers \ * to the front & back nodes */ \ typedef struct M_F(name, _s) { \ struct m_il1st_head_s name; \ } list_t[1]; \ \ /* Define internal types pointers to such a list */ \ typedef struct M_F(name, _s) *M_F(name, _ptr); \ typedef const struct M_F(name, _s) *M_F(name, _srcptr); \ \ /* Define iterator of such a list */ \ typedef struct M_F(name, _it_s) { \ struct m_il1st_head_s *head; \ struct m_il1st_head_s *previous; \ struct m_il1st_head_s *current; \ struct m_il1st_head_s *next; \ } it_t[1]; \ \ /* Define types used by oplist */ \ typedef type M_F(name, _subtype_ct); \ typedef list_t M_F(name, _ct); \ typedef it_t M_F(name, _it_ct); \ /* Define core functions for intrusive lists */ #define M_IL1ST_DEF_CORE(name, type, oplist, list_t, it_t) \ \ M_INLINE void \ M_F(name, _init)(list_t list) \ { \ M_ASSERT (list != NULL); \ list->name.next = &list->name; \ list->name.prev = &list->name; \ M_IL1ST_CONTRACT(name, list); \ } \ \ M_INLINE void \ M_F(name, _reset)(list_t list) \ { \ M_IL1ST_CONTRACT(name, list); \ for(struct m_il1st_head_s *it = list->name.next, *next ; \ it != &list->name; it = next) { \ /* Cannot check node contract as previous node may be deleted */ \ type *obj = M_TYPE_FROM_FIELD(type, it, \ struct m_il1st_head_s, name); \ /* Read next now before the object is destroyed */ \ next = it->next; \ M_ASSERT (next != NULL); \ M_CALL_CLEAR(oplist, *obj); \ /* Delete also the object if a DELETE operand is registered */ \ M_IF_METHOD(DEL, oplist)(M_CALL_DEL(oplist, obj), (void) 0); \ } \ /* Nothing remains in the list anymore */ \ list->name.next = &list->name; \ list->name.prev = &list->name; \ M_IL1ST_CONTRACT(name, list); \ } \ \ M_INLINE void \ M_F(name, _clear)(list_t list) \ { \ /* Nothing to do more than clean the list itself */ \ M_F(name, _reset)(list); \ /* For safety purpose (create invalid represenation of object) */ \ list->name.next = NULL; \ list->name.prev = NULL; \ } \ \ M_INLINE bool \ M_F(name, _empty_p)(const list_t list) \ { \ M_IL1ST_CONTRACT(name, list); \ return list->name.next == &list->name; \ } \ \ \ M_INLINE void \ M_F(name, _init_move)(list_t list, list_t ref) \ { \ M_IL1ST_CONTRACT(name, ref); \ M_ASSERT (list != ref); \ M_F(name,_init)(list); \ if (!M_F(name,_empty_p)(ref)) { \ list->name.next = ref->name.next; \ list->name.prev = ref->name.prev; \ list->name.next->prev = &list->name; \ list->name.prev->next = &list->name; \ } \ ref->name.next = NULL; \ ref->name.prev = NULL; \ M_IL1ST_CONTRACT(name, list); \ } \ \ M_INLINE void \ M_F(name, _move)(list_t list, list_t ref) \ { \ M_F(name, _clear)(list); \ M_F(name, _init_move)(list, ref); \ } \ \ M_INLINE size_t \ M_F(name, _size)(const list_t list) \ { \ M_IL1ST_CONTRACT(name, list); \ size_t s = 0; \ /* Scan the full list to count the number of elements */ \ for(const struct m_il1st_head_s *it = list->name.next ; \ it != &list->name; it = it->next) { \ M_IL1ST_NODE_CONTRACT(it); \ s++; \ } \ return s; \ } \ \ M_INLINE void \ M_F(name, _push_back)(list_t list, type *obj) \ { \ M_IL1ST_CONTRACT(name, list); \ M_ASSERT (obj != NULL); \ struct m_il1st_head_s *prev = list->name.prev; \ list->name.prev = &obj->name; \ obj->name.prev = prev; \ obj->name.next = &list->name; \ prev->next = &obj->name; \ M_IL1ST_CONTRACT(name, list); \ } \ \ M_INLINE void \ M_F(name, _push_front)(list_t list, type *obj) \ { \ M_IL1ST_CONTRACT(name, list); \ M_ASSERT (obj != NULL); \ struct m_il1st_head_s *next = list->name.next; \ list->name.next = &obj->name; \ obj->name.next = next; \ obj->name.prev = &list->name; \ next->prev = &obj->name; \ M_IL1ST_CONTRACT(name, list); \ } \ \ M_INLINE void \ M_F(name, _push_after)(type *obj_pos, type *obj) \ { \ M_ASSERT (obj_pos != NULL && obj != NULL); \ /* We don't have the list, so we have no contract at list level */ \ M_IL1ST_NODE_CONTRACT(&obj_pos->name); \ struct m_il1st_head_s *next = obj_pos->name.next; \ obj_pos->name.next = &obj->name; \ obj->name.next = next; \ obj->name.prev = &obj_pos->name; \ next->prev = &obj->name; \ } \ \ M_INLINE void \ M_F(name, _init_field)(type *obj) \ { \ M_ASSERT (obj != NULL); \ /* Init the fields of the node. To be used in object constructor */ \ obj->name.next = NULL; \ obj->name.prev = NULL; \ } \ \ M_INLINE void \ M_F(name, _unlink)(type *obj) \ { \ M_ASSERT (obj != NULL); \ /* We don't have the list, so we have no contract at list level */ \ M_IL1ST_NODE_CONTRACT(&obj->name); \ struct m_il1st_head_s *next = obj->name.next; \ struct m_il1st_head_s *prev = obj->name.prev; \ next->prev = prev; \ prev->next = next; \ /* Note: not really needed, but safer */ \ obj->name.next = NULL; \ obj->name.prev = NULL; \ } \ \ M_INLINE type * \ M_F(name, _back)(const list_t list) \ { \ M_IL1ST_CONTRACT(name, list); \ M_ASSERT(!M_F(name, _empty_p)(list)); \ return M_TYPE_FROM_FIELD(type, list->name.prev, \ struct m_il1st_head_s, name); \ } \ \ M_INLINE type * \ M_F(name, _front)(const list_t list) \ { \ M_IL1ST_CONTRACT(name, list); \ M_ASSERT(!M_F(name, _empty_p)(list)); \ return M_TYPE_FROM_FIELD(type, list->name.next, \ struct m_il1st_head_s, name); \ } \ \ M_INLINE type * \ M_F(name, _next_obj)(const list_t list, type const *obj) \ { \ M_IL1ST_CONTRACT(name, list); \ M_ASSERT (obj != NULL); \ M_IL1ST_NODE_CONTRACT(&obj->name); \ return obj->name.next == &list->name ? NULL : \ M_TYPE_FROM_FIELD(type, obj->name.next, \ struct m_il1st_head_s, name); \ } \ \ M_INLINE type * \ M_F(name, _previous_obj)(const list_t list, type const *obj) \ { \ M_IL1ST_CONTRACT(name, list); \ M_ASSERT (obj != NULL); \ M_IL1ST_NODE_CONTRACT(&obj->name); \ return obj->name.prev == &list->name ? NULL : \ M_TYPE_FROM_FIELD(type, obj->name.prev, \ struct m_il1st_head_s, name); \ } \ \ M_INLINE void \ M_F(name, _it)(it_t it, const list_t list) \ { \ M_IL1ST_CONTRACT(name, list); \ M_ASSERT (it != NULL); \ it->head = list->name.next->prev; \ it->current = list->name.next; \ it->next = list->name.next->next; \ it->previous = it->head; \ M_IL1ST_NODE_CONTRACT(it->current); \ } \ \ M_INLINE void \ M_F(name, _it_set)(it_t it, const it_t cit) \ { \ M_ASSERT (it != NULL && cit != NULL); \ it->head = cit->head; \ it->current = cit->current; \ it->next = cit->next; \ it->previous = cit->previous; \ M_IL1ST_NODE_CONTRACT(it->current); \ } \ \ M_INLINE void \ M_F(name, _it_last)(it_t it, list_t const list) \ { \ M_IL1ST_CONTRACT(name, list); \ M_ASSERT (it != NULL); \ it->head = list->name.next->prev; \ it->current = list->name.prev; \ it->next = it->head; \ it->previous = list->name.prev->prev; \ M_IL1ST_NODE_CONTRACT(it->current); \ } \ \ M_INLINE void \ M_F(name, _it_end)(it_t it, list_t const list) \ { \ M_ASSERT (it != NULL && list != NULL); \ it->head = list->name.next->prev; \ it->current = it->head; \ it->next = list->name.next; \ it->previous = list->name.prev; \ M_IL1ST_NODE_CONTRACT(it->current); \ } \ \ M_INLINE bool \ M_F(name, _end_p)(const it_t it) \ { \ M_ASSERT (it != NULL); \ M_IL1ST_NODE_CONTRACT(it->current); \ return it->current == it->head; \ } \ \ M_INLINE bool \ M_F(name, _last_p)(const it_t it) \ { \ M_ASSERT (it != NULL); \ M_IL1ST_NODE_CONTRACT(it->current); \ return it->next == it->head || it->current == it->head; \ } \ \ M_INLINE void \ M_F(name, _next)(it_t it) \ { \ M_ASSERT (it != NULL); \ /* Cannot check node for it->current: it may have been deleted! */ \ /* Note: Can't set it->previous to it->current. \ it->current may have been unlinked from the list */ \ it->current = it->next; \ M_ASSERT (it->current != NULL); \ it->next = it->current->next; \ it->previous = it->current->prev; \ M_ASSERT (it->next != NULL && it->previous != NULL); \ M_IL1ST_NODE_CONTRACT(it->current); \ } \ \ M_INLINE void \ M_F(name, _previous)(it_t it) \ { \ M_ASSERT (it != NULL); \ /* Cannot check node for it->current: it may have been deleted! */ \ /* Note: Can't set it->next to it->current. \ it->current may have been unlinked from the list */ \ it->current = it->previous; \ M_ASSERT (it->current != NULL); \ it->next = it->current->next; \ it->previous = it->current->prev; \ M_ASSERT (it->next != NULL && it->previous != NULL); \ M_IL1ST_NODE_CONTRACT(it->current); \ } \ \ M_INLINE bool \ M_F(name, _it_equal_p)(const it_t it1, const it_t it2 ) \ { \ M_ASSERT (it1 != NULL && it2 != NULL); \ /* No need to check for next & previous */ \ return it1->head == it2->head && it1->current == it2->current; \ } \ \ M_INLINE type * \ M_F(name, _ref)(const it_t it) \ { \ M_ASSERT (it != NULL && it->current != NULL); \ M_IL1ST_NODE_CONTRACT(it->current); \ /* check if 'it' was not deleted */ \ M_ASSERT (it->current->next == it->next); \ M_ASSERT (it->current->prev == it->previous); \ M_ASSERT (!M_F(name, _end_p)(it)); \ return M_TYPE_FROM_FIELD(type, it->current, \ struct m_il1st_head_s, name); \ } \ \ M_INLINE type const * \ M_F(name, _cref)(const it_t it) \ { \ type *ptr = M_F(name, _ref)(it); \ return M_CONST_CAST(type, ptr); \ } \ \ M_INLINE void \ M_F(name, _remove)(list_t list, it_t it) \ { \ M_IL1ST_CONTRACT(name, list); \ M_IL1ST_NODE_CONTRACT(it->current); \ (void)list; /* list param is not used */ \ type *obj = M_TYPE_FROM_FIELD(type, it->current, \ struct m_il1st_head_s, name); \ M_F(name, _unlink)(obj); \ M_CALL_CLEAR(oplist, obj); \ M_IF_METHOD(DEL, oplist)(M_CALL_DEL(oplist, obj), (void) 0); \ M_F(name, _next)(it); \ } \ \ M_IF_METHOD2(NEW, INIT_SET, oplist)( \ M_INLINE void \ M_F(name, _insert)(list_t list, it_t it, type x) \ { \ M_IL1ST_CONTRACT(name, list); \ M_IL1ST_NODE_CONTRACT(it->current); \ type *p = M_CALL_NEW(oplist, type); \ if (M_UNLIKELY_NOMEM (p == NULL)) { \ M_MEMORY_FULL (sizeof (type)); \ return ; \ } \ M_CALL_INIT_SET(oplist, *p, x); \ type *obj = M_F(name, _ref)(it); \ M_F(name, _push_after)(obj, p); \ it->current = p; \ (void) list; \ M_IL1ST_CONTRACT(name, list); \ } \ , /* NEW & INIT_SET not defined */) \ \ M_INLINE type * \ M_F(name, _pop_back)(list_t list) \ { \ M_IL1ST_CONTRACT(name, list); \ M_ASSERT (!M_F(name, _empty_p)(list)); \ type *obj = M_F(name, _back)(list); \ list->name.prev = list->name.prev->prev; \ list->name.prev->next = &list->name; \ return obj; \ } \ \ M_INLINE type * \ M_F(name, _pop_front)(list_t list) \ { \ M_IL1ST_CONTRACT(name, list); \ M_ASSERT (!M_F(name, _empty_p)(list)); \ type *obj = M_F(name, _front)(list); \ list->name.next = list->name.next->next; \ list->name.next->prev = &list->name; \ return obj; \ } \ \ M_INLINE void \ M_F(name, _splice)(list_t list1, list_t list2) \ { \ M_IL1ST_CONTRACT(name, list1); \ M_IL1ST_CONTRACT(name, list2); \ struct m_il1st_head_s *midle1 = list1->name.prev; \ struct m_il1st_head_s *midle2 = list2->name.next; \ midle1->next = midle2; \ midle2->prev = midle1; \ list1->name.prev = list2->name.prev; \ list2->name.prev->next = &list1->name; \ list2->name.next = &list2->name; \ list2->name.prev = &list2->name; \ M_IL1ST_CONTRACT(name, list1); \ M_IL1ST_CONTRACT(name, list2); \ } \ \ M_INLINE void \ M_F(name, _splice_back)(list_t nv, list_t ov, it_t it) \ { \ M_IL1ST_CONTRACT(name, nv); \ M_IL1ST_CONTRACT(name, ov); \ M_IL1ST_NODE_CONTRACT(it->current); \ M_ASSERT (it != NULL); \ (void) ov; \ type *obj = M_F(name, _ref)(it); \ M_F(name, _unlink)(obj); \ M_F(name, _push_back)(nv, obj); \ M_F(name, _next)(it); \ M_IL1ST_CONTRACT(name, nv); \ M_IL1ST_CONTRACT(name, ov); \ } \ \ M_INLINE void \ M_F(name, _splice_at)(list_t nlist, it_t npos, \ list_t olist, it_t opos) \ { \ M_IL1ST_CONTRACT(name, nlist); \ M_IL1ST_CONTRACT(name, olist); \ M_ASSERT (npos != NULL && opos != NULL); \ M_ASSERT (!M_F(name, _end_p)(opos)); \ /* npos may be end */ \ (void) olist, (void) nlist; \ type *obj = M_F(name, _ref)(opos); \ struct m_il1st_head_s *ref = npos->current; \ /* Remove object */ \ M_F(name, _unlink)(obj); \ /* Push 'obj' after 'ref' */ \ struct m_il1st_head_s *next = ref->next; \ ref->next = &obj->name; \ obj->name.next = next; \ obj->name.prev = ref; \ next->prev = &obj->name; \ /* Move iterator in old list */ \ M_F(name, _next)(opos); \ /* Set npos iterator to new position of object */ \ npos->previous = ref; \ npos->current = &obj->name; \ npos->next = next; \ M_IL1ST_CONTRACT(name, nlist); \ M_IL1ST_CONTRACT(name, olist); \ } \ \ M_INLINE void \ M_F(name, _swap)(list_t d, list_t e) \ { \ M_IL1ST_CONTRACT(name, d); \ M_IL1ST_CONTRACT(name, e); \ struct m_il1st_head_s *d_item = d->name.next; \ struct m_il1st_head_s *e_item = e->name.next; \ /* it is more complicated than other swap functions since \ we need to detect "cyclic" loop */ \ d->name.next = e_item == &e->name ? &d->name : e_item; \ e->name.next = d_item == &d->name ? &e->name : d_item; \ d_item = d->name.prev; \ e_item = e->name.prev; \ d->name.prev = e_item == &e->name ? &d->name : e_item; \ e->name.prev = d_item == &d->name ? &e->name : d_item; \ d->name.next->prev = &d->name; \ d->name.prev->next = &d->name; \ e->name.next->prev = &e->name; \ e->name.prev->next = &e->name; \ M_IL1ST_CONTRACT(name, d); \ M_IL1ST_CONTRACT(name, e); \ } \ \ M_INLINE void \ M_F(name, _reverse)(list_t list) \ { \ M_IL1ST_CONTRACT(name, list); \ struct m_il1st_head_s *next, *it; \ for(it = list->name.next ; it != &list->name; it = next) { \ next = it->next; \ it->next = it->prev; \ it->prev = next; \ } \ next = it->next; \ it->next = it->prev; \ it->prev = next; \ M_IL1ST_CONTRACT(name, list); \ } \ /******************************** INTERNAL ***********************************/ #if M_USE_SMALL_NAME #define ILIST_INTERFACE M_ILIST_INTERFACE #define ILIST_DEF M_ILIST_DEF #define ILIST_DEF_AS M_ILIST_DEF_AS #define ILIST_OPLIST M_ILIST_OPLIST #endif #endif