mirror of
https://github.com/ByteWelder/Tactility.git
synced 2026-02-18 19:03:16 +00:00
680 lines
48 KiB
C
680 lines
48 KiB
C
/*
|
|
* 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
|