Add dual push singly linked list
This commit is contained in:
1 parent
1befa63c9b
commit
6ec277ec99
2 files changed
+465
-2
No files matched your search
@@ -27,13 +27,20 @@
|
||||
|
||||
#include "m-core.h"
|
||||
|
||||
/* Define a singly list of a given type.
|
||||
/* Define a singly linked list of a given type.
|
||||
USAGE: LIST_DEF(name, type [, oplist_of_the_type]) */
|
||||
#define LIST_DEF(name, ...) \
|
||||
LISTI_DEF(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__), M_C(name,_t), M_C(name, _it_t) ), \
|
||||
(name, __VA_ARGS__, M_C(name,_t), M_C(name, _it_t) )))
|
||||
|
||||
/* Define a dual-push singly linked list of a given type.
|
||||
USAGE: LIST_DEF(name, type [, oplist_of_the_type]) */
|
||||
#define LIST_DUAL_PUSH_DEF(name, ...) \
|
||||
LISTI_DUAL_PUSH_DEF(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__), M_C(name,_t), M_C(name, _it_t) ), \
|
||||
(name, __VA_ARGS__, M_C(name,_t), M_C(name, _it_t) )))
|
||||
|
||||
/* Define the oplist of a list of type.
|
||||
USAGE: LIST_OPLIST(name [, oplist_of_the_type]) */
|
||||
#define LIST_OPLIST(...) \
|
||||
@@ -228,7 +235,7 @@
|
||||
static inline void \
|
||||
M_C(name, _it)(list_it_t l, const list_t v) \
|
||||
{ \
|
||||
assert (v != NULL && l[0].l != NULL); \
|
||||
assert (v != NULL && l != NULL); \
|
||||
l[0].l[0] = *v; \
|
||||
l[0].previous = NULL; \
|
||||
} \
|
||||
@@ -589,5 +596,460 @@
|
||||
} \
|
||||
, /* no hash */ ) \
|
||||
|
||||
/* Dual Push singly linked list.
|
||||
Support Push Back / Push Front / Pop back in O(1).
|
||||
Doesn't support Pop front.
|
||||
This is done by keeping a pointer to both back & front
|
||||
*/
|
||||
#define LISTI_DUAL_PUSH_DEF(arg) LISTI_DUAL_PUSH_DEF2 arg
|
||||
|
||||
#define LISTI_DUAL_PUSH_DEF2(name, type, oplist, list_t, list_it_t) \
|
||||
\
|
||||
struct M_C(name, _s) { \
|
||||
struct M_C(name, _s) *next; \
|
||||
type data; \
|
||||
}; \
|
||||
\
|
||||
typedef struct { \
|
||||
struct M_C(name, _s) *front; \
|
||||
struct M_C(name, _s) *back; \
|
||||
} list_t[1]; \
|
||||
\
|
||||
typedef type M_C(name, _type_t); \
|
||||
\
|
||||
typedef struct M_C(name, _it_s) { \
|
||||
struct M_C(name, _s) *previous; \
|
||||
struct M_C(name, _s) *current; \
|
||||
} list_it_t[1]; \
|
||||
\
|
||||
LISTI_MEMPOOL_DEF(name, type, oplist, list_t, list_it_t) \
|
||||
LISTI_DUAL_PUSH_DEF3(name, type, oplist, list_t, list_it_t) \
|
||||
LISTI_ITBASE_DEF(name, type, oplist, list_t, list_it_t)
|
||||
|
||||
#define LISTI_DUAL_PUSH_CONTRACT(l) do { \
|
||||
assert (l != NULL); \
|
||||
assert ( (l->back == NULL && l->front == NULL) \
|
||||
|| (l->back != NULL && l->front != NULL)); \
|
||||
} while (0)
|
||||
|
||||
#define LISTI_DUAL_PUSH_DEF3(name, type, oplist, list_t, list_it_t) \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init)(list_t v) \
|
||||
{ \
|
||||
assert( v != NULL); \
|
||||
v->front = NULL; \
|
||||
v->back = NULL; \
|
||||
LISTI_DUAL_PUSH_CONTRACT(v); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clean)(list_t v) \
|
||||
{ \
|
||||
LISTI_DUAL_PUSH_CONTRACT(v); \
|
||||
struct M_C(name, _s) *it = v->back; \
|
||||
while (it != NULL) { \
|
||||
struct M_C(name, _s) *next = it->next; \
|
||||
M_GET_CLEAR oplist(it->data); \
|
||||
M_C(name,_int_del)(it); \
|
||||
it = next; \
|
||||
} \
|
||||
v->front = NULL; \
|
||||
v->back = NULL; \
|
||||
LISTI_DUAL_PUSH_CONTRACT(v); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clear)(list_t v) \
|
||||
{ \
|
||||
M_C(name, _clean)(v); \
|
||||
} \
|
||||
\
|
||||
static inline const type * \
|
||||
M_C(name, _back)(const list_t v) \
|
||||
{ \
|
||||
LISTI_DUAL_PUSH_CONTRACT(v); \
|
||||
assert (v->back != NULL); \
|
||||
return M_CONST_CAST(type, &(v->back->data)); \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name, _push_back_raw)(list_t v) \
|
||||
{ \
|
||||
LISTI_DUAL_PUSH_CONTRACT(v); \
|
||||
struct M_C(name, _s) *next = M_C(name, _int_new)(); \
|
||||
if (M_UNLIKELY (next == NULL)) { \
|
||||
M_MEMORY_FULL(sizeof (struct M_C(name, _s))); \
|
||||
return NULL; \
|
||||
} \
|
||||
type *ret = &next->data; \
|
||||
next->next = v->back; \
|
||||
v->back = next; \
|
||||
/* Update front too if the list was empty */ \
|
||||
/* This C code shall generate branchless code */ \
|
||||
struct M_C(name, _s) *front = v->front; \
|
||||
front = (front == NULL) ? next : front; \
|
||||
v->front = front; \
|
||||
LISTI_DUAL_PUSH_CONTRACT(v); \
|
||||
return ret; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _push_back)(list_t v, type const x) \
|
||||
{ \
|
||||
type *data = M_C(name, _push_back_raw)(v); \
|
||||
if (M_UNLIKELY (data == NULL)) \
|
||||
return; \
|
||||
M_GET_INIT_SET oplist(*data, x); \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name, _push_back_new)(list_t v) \
|
||||
{ \
|
||||
type *data = M_C(name, _push_back_raw)(v); \
|
||||
if (M_UNLIKELY (data == NULL)) \
|
||||
return NULL; \
|
||||
M_GET_INIT oplist(*data); \
|
||||
return data; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _pop_back)(type *data, list_t v) \
|
||||
{ \
|
||||
LISTI_DUAL_PUSH_CONTRACT(v); \
|
||||
assert (v->back != NULL); \
|
||||
struct M_C(name, _s) *tofree = v->back; \
|
||||
if (data != NULL) { \
|
||||
M_GET_SET oplist(*data, tofree->data); \
|
||||
} \
|
||||
M_GET_CLEAR oplist(tofree->data); \
|
||||
v->back = tofree->next; \
|
||||
M_C(name,_int_del)(tofree); \
|
||||
/* Update front too if the list became empty */ \
|
||||
/* This C code shall generate branchless code */ \
|
||||
struct M_C(name, _s) *front = v->front; \
|
||||
front = (front == tofree) ? NULL : front; \
|
||||
v->front = front; \
|
||||
LISTI_DUAL_PUSH_CONTRACT(v); \
|
||||
} \
|
||||
\
|
||||
static inline const type * \
|
||||
M_C(name, _front)(list_t v) \
|
||||
{ \
|
||||
LISTI_DUAL_PUSH_CONTRACT(v); \
|
||||
assert (v->front != NULL); \
|
||||
return M_CONST_CAST(type, &(v->front->data)); \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name, _push_front_raw)(list_t v) \
|
||||
{ \
|
||||
LISTI_DUAL_PUSH_CONTRACT(v); \
|
||||
struct M_C(name, _s) *next = M_C(name, _int_new)(); \
|
||||
if (M_UNLIKELY (next == NULL)) { \
|
||||
M_MEMORY_FULL(sizeof (struct M_C(name, _s))); \
|
||||
return NULL; \
|
||||
} \
|
||||
type *ret = &next->data; \
|
||||
next->next = NULL; \
|
||||
if (M_LIKELY(v->front != NULL)) { \
|
||||
v->front->next = next; \
|
||||
} else { \
|
||||
/* Update back too as the list was empty */ \
|
||||
v->back = next; \
|
||||
} \
|
||||
v->front = next; \
|
||||
LISTI_DUAL_PUSH_CONTRACT(v); \
|
||||
return ret; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _push_front)(list_t v, type const x) \
|
||||
{ \
|
||||
type *data = M_C(name, _push_front_raw)(v); \
|
||||
if (M_UNLIKELY (data == NULL)) \
|
||||
return; \
|
||||
M_GET_INIT_SET oplist(*data, x); \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name, _push_front_new)(list_t v) \
|
||||
{ \
|
||||
type *data = M_C(name, _push_back_raw)(v); \
|
||||
if (M_UNLIKELY (data == NULL)) \
|
||||
return NULL; \
|
||||
M_GET_INIT oplist(*data); \
|
||||
return data; \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _empty_p)(const list_t v) \
|
||||
{ \
|
||||
LISTI_DUAL_PUSH_CONTRACT(v); \
|
||||
return v->back == NULL; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _swap)(list_t l, list_t v) \
|
||||
{ \
|
||||
LISTI_DUAL_PUSH_CONTRACT(l); \
|
||||
LISTI_DUAL_PUSH_CONTRACT(v); \
|
||||
M_SWAP(struct M_C(name, _s) *, l->front, v->front); \
|
||||
M_SWAP(struct M_C(name, _s) *, l->back, v->back); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _it)(list_it_t it, const list_t v) \
|
||||
{ \
|
||||
LISTI_DUAL_PUSH_CONTRACT(v); \
|
||||
assert (it != NULL); \
|
||||
it->current = v->back; \
|
||||
it->previous = NULL; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _it_set)(list_it_t it1, const list_it_t it2) \
|
||||
{ \
|
||||
assert (it1 != NULL && it2 != NULL); \
|
||||
it1->current = it2->current; \
|
||||
it1->previous = it2->previous; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _it_end)(list_it_t it1, const list_t v) \
|
||||
{ \
|
||||
assert (it1 != NULL); \
|
||||
LISTI_DUAL_PUSH_CONTRACT(v); \
|
||||
(void)v; /* unused */ \
|
||||
it1->current = NULL; \
|
||||
it1->previous = NULL; \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _end_p)(const list_it_t it) \
|
||||
{ \
|
||||
assert (it != NULL); \
|
||||
return it->current == NULL; \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _last_p)(const list_it_t it) \
|
||||
{ \
|
||||
assert (it != NULL); \
|
||||
return it->current == NULL || it->current->next == NULL; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _next)(list_it_t it) \
|
||||
{ \
|
||||
assert(it != NULL && it->current->next != NULL); \
|
||||
it->previous = it->current; \
|
||||
it->current = it->current->next; \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _it_equal_p)(const list_it_t it1, const list_it_t it2) \
|
||||
{ \
|
||||
assert(it1 != NULL && it2 != NULL); \
|
||||
return it1->current == it2->current; \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name, _ref)(const list_it_t it) \
|
||||
{ \
|
||||
assert(it != NULL && it->current != NULL); \
|
||||
return &(it->current->data); \
|
||||
} \
|
||||
\
|
||||
static inline const type * \
|
||||
M_C(name, _cref)(const list_it_t it) \
|
||||
{ \
|
||||
assert(it != NULL && it->current != NULL); \
|
||||
return M_CONST_CAST(type, &(it->current->data)); \
|
||||
} \
|
||||
\
|
||||
static inline size_t \
|
||||
M_C(name, _size)(const list_t v) \
|
||||
{ \
|
||||
LISTI_DUAL_PUSH_CONTRACT(v); \
|
||||
size_t size = 0; \
|
||||
struct M_C(name, _s) *it = v->back; \
|
||||
while (it != NULL) { \
|
||||
size ++; \
|
||||
it = it->next; \
|
||||
} \
|
||||
return size; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _insert)(list_t list, list_it_t insertion_point, \
|
||||
type const x) \
|
||||
{ \
|
||||
LISTI_DUAL_PUSH_CONTRACT(list); \
|
||||
assert (insertion_point != NULL); \
|
||||
struct M_C(name, _s) *next = M_C(name, _int_new)(); \
|
||||
if (M_UNLIKELY (next == NULL)) { \
|
||||
M_MEMORY_FULL(sizeof (struct M_C(name, _s))); \
|
||||
return; \
|
||||
} \
|
||||
M_GET_INIT_SET oplist(next->data, x); \
|
||||
if (M_UNLIKELY (insertion_point->current == NULL)) { \
|
||||
next->next = list->back; \
|
||||
list->back = next; \
|
||||
/* update front if list is empty */ \
|
||||
struct M_C(name, _s) *front = list->front; \
|
||||
front = (front == NULL) ? next : front; \
|
||||
list->front = front; \
|
||||
} else { \
|
||||
next->next = insertion_point->current->next; \
|
||||
insertion_point->current->next = next; \
|
||||
/* update front if current == front */ \
|
||||
struct M_C(name, _s) *front = list->front; \
|
||||
front = (front == insertion_point->current) ? next : front; \
|
||||
list->front = front; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _remove)(list_t list, list_it_t removing_point) \
|
||||
{ \
|
||||
LISTI_DUAL_PUSH_CONTRACT(list); \
|
||||
assert (removing_point != NULL); \
|
||||
assert(removing_point->current != NULL); \
|
||||
struct M_C(name, _s) *next = removing_point->current->next; \
|
||||
struct M_C(name, _s) *previous = removing_point->previous; \
|
||||
if (M_UNLIKELY (previous == NULL)) { \
|
||||
list->back = next; \
|
||||
} else { \
|
||||
previous->next = next; \
|
||||
} \
|
||||
/* Update front */ \
|
||||
struct M_C(name, _s) *front = list->front; \
|
||||
front = (next == NULL) ? previous : front; \
|
||||
list->front = front; \
|
||||
/* Remove node */ \
|
||||
M_GET_CLEAR oplist(removing_point->current->data); \
|
||||
M_C(name,_int_del) (removing_point->current); \
|
||||
removing_point->current = next; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _set)(list_t list, const list_t org) \
|
||||
{ \
|
||||
LISTI_DUAL_PUSH_CONTRACT(list); \
|
||||
LISTI_DUAL_PUSH_CONTRACT(org); \
|
||||
struct M_C(name, _s) *next = NULL; \
|
||||
struct M_C(name, _s) *it_org; \
|
||||
struct M_C(name, _s) **update_list; \
|
||||
if (M_UNLIKELY (list == org)) return; \
|
||||
M_C(name, _clean)(list); \
|
||||
update_list = &list->back; \
|
||||
it_org = org->back; \
|
||||
while (it_org != NULL) { \
|
||||
next = M_C(name, _int_new)(); \
|
||||
*update_list = next; \
|
||||
if (M_UNLIKELY (next == NULL)) { \
|
||||
M_MEMORY_FULL(sizeof (struct M_C(name, _s))); \
|
||||
return; \
|
||||
} \
|
||||
update_list = &next->next; \
|
||||
M_GET_INIT_SET oplist(next->data, it_org->data); \
|
||||
it_org = it_org->next; \
|
||||
} \
|
||||
list->front = next; \
|
||||
*update_list = NULL; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init_set)(list_t list, const list_t org) \
|
||||
{ \
|
||||
assert (list != org); \
|
||||
M_C(name, _init)(list); \
|
||||
M_C(name, _set)(list, org); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init_move)(list_t list, list_t org) \
|
||||
{ \
|
||||
assert (list != org); \
|
||||
list->back = org->back; \
|
||||
list->front = org->front; \
|
||||
org->back = NULL; \
|
||||
org->front = NULL; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _move)(list_t list, list_t org) \
|
||||
{ \
|
||||
M_C(name, _clear)(list); \
|
||||
M_C(name, _init_move)(list, org); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _splice_back)(list_t list1, list_t list2, list_it_t it) \
|
||||
{ \
|
||||
LISTI_DUAL_PUSH_CONTRACT(list1); \
|
||||
LISTI_DUAL_PUSH_CONTRACT(list2); \
|
||||
assert (list1 != list2); \
|
||||
assert(it->current != NULL); \
|
||||
/* First remove 'it' from list2 */ \
|
||||
struct M_C(name, _s) *current = it->current; \
|
||||
struct M_C(name, _s) *next = current->next; \
|
||||
if (it->previous == NULL) { \
|
||||
list1->back = next; \
|
||||
} else { \
|
||||
it->previous->next = next; \
|
||||
} \
|
||||
/* Update front */ \
|
||||
struct M_C(name, _s) *front = list2->front; \
|
||||
front = (next == NULL) ? it->previous : front; \
|
||||
list2->front = front; \
|
||||
/* Update it to next element */ \
|
||||
it->current = next; \
|
||||
/* Move current in nv */ \
|
||||
current->next = list1->back; \
|
||||
list1->back = current; \
|
||||
/* Update front too if the list was empty */ \
|
||||
/* This C code shall generate branchless code */ \
|
||||
front = list1->front; \
|
||||
front = (front == NULL) ? current : front; \
|
||||
list1->front = front; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _splice)(list_t list1, list_t list2) \
|
||||
{ \
|
||||
LISTI_DUAL_PUSH_CONTRACT(list1); \
|
||||
LISTI_DUAL_PUSH_CONTRACT(list2); \
|
||||
assert (list1 != list2); \
|
||||
if (M_LIKELY (list1->front != NULL)) { \
|
||||
list1->front->next = list2->back; \
|
||||
list1->front = list2->front; \
|
||||
} else { \
|
||||
/* list1 is empty */ \
|
||||
list1->back = list2->back; \
|
||||
list1->front = list2->front; \
|
||||
} \
|
||||
list2->back = NULL; \
|
||||
list2->front = NULL; \
|
||||
LISTI_DUAL_PUSH_CONTRACT(list1); \
|
||||
LISTI_DUAL_PUSH_CONTRACT(list2); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _reverse)(list_t list) \
|
||||
{ \
|
||||
LISTI_DUAL_PUSH_CONTRACT(list); \
|
||||
list->front = list->back; \
|
||||
struct M_C(name, _s) *previous = NULL, *it = list->back, *next; \
|
||||
while (it != NULL) { \
|
||||
next = it->next; \
|
||||
it->next = previous; \
|
||||
previous = it; \
|
||||
it = next; \
|
||||
} \
|
||||
list->back = previous; \
|
||||
LISTI_DUAL_PUSH_CONTRACT(list); \
|
||||
} \
|
||||
|
||||
#endif
|
||||
@@ -29,6 +29,7 @@
|
||||
START_COVERAGE
|
||||
LIST_DEF(list_uint, unsigned int)
|
||||
LIST_DEF(list_mpz, mpz_t, MYMPZ_OPLIST)
|
||||
LIST_DUAL_PUSH_DEF(list2_double, double)
|
||||
END_COVERAGE
|
||||
#define LIST_UINT_OPLIST LIST_OPLIST(list_uint)
|
||||
|
||||
|
||||
Reference in new issue
Block a user