netsukuku/src/llist.c
Kirill Sotnikov f1761cad9a git repo init
2013-09-16 13:53:25 +04:00

636 lines
16 KiB
C

/* This file is part of Netsukuku
* (c) Copyright 2005 Andrea Lo Pumo aka AlpT <alpt@freaknet.org>
*
* This source code is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published
* by the Free Software Foundation; either version 2 of the License,
* or (at your option) any later version.
*
* This source code is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* Please refer to the GNU Public License for more details.
*
* You should have received a copy of the GNU Public License along with
* this source code; if not, write to:
* Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* --
*
* llist.c: Various functions to handle (doubled) linked lists
*
* Why did I used macros for all these functions?
* Well, I just love the blue-smurf-like syntax highlighting of Vim ^_-
*
* Moreover using `typeof' and other nice tricks each macro can recognize the
* size of the arguments, in this way we can have functions like `list_copy',
* `list_init'.
* Finally, performance is optimised. I don't trust gcc and its -O2, (and they
* don't trust me).
*/
#ifndef LLIST_C
#define LLIST_C
/*
* This struct is used as a header to handle all the linked list struct.
* The only limitation is to put _EXACTLY_
* struct bla_bla *next;
* struct bla_bla *prev;
* at the beginning.
* You can also use the LLIST_HDR() macro.
*/
#define LLIST_HDR(_struct) _struct *next, *prev
struct linked_list
{
LLIST_HDR (struct linked_list);
}linked_list;
typedef struct linked_list l_list;
#define is_list_zero(list) \
({ \
int _iz, _rz=1; \
char *_a=(char *)(list); \
for(_iz=0; _iz<sizeof(typeof(*(list))); _iz++, _a++) \
if(*_a) { \
_rz=0; \
break; \
} \
_rz; \
})
/*
* list_copy
*
* It copies just the contents of `new' in `list' without overwriting the
* ->prev and ->next pointers.
*/
#define list_copy(list, new) \
do{ \
l_list _oc, *_lc=(l_list *)(list); \
if((new)) { \
_oc.prev=_lc->prev; \
_oc.next=_lc->next; \
memcpy((list), (new), sizeof(typeof(*(new)))); \
_lc->prev=_oc.prev; \
_lc->next=_oc.next; \
} \
} while(0)
/*
* list_dup
*
* the strdup equivalent of a single llist
*/
#define list_dup(list) \
({ \
l_list *_dd; \
_dd=xmalloc(sizeof(typeof(*(list)))); \
memset(_dd, 0, sizeof(typeof(*(list)))); \
list_copy(_dd, (list)); \
(typeof((list)))_dd; \
})
/*
* list_init
*
* If `new' is 0, it stores in `list' a pointer to a newly mallocated
* and zeroed struct.
* Its type is the same of `list'.
* If `new' is non zero, then `list' is simply set to `new'.
* The ->prev and ->next pointers are always set to zero.
*/
#define list_init(list, new) \
do { \
l_list *_li; \
if((new)) \
(list)=(new); \
else \
(list)=(typeof (list))xmalloc(sizeof(typeof(*(list)))); \
_li=(l_list *)(list); \
_li->prev=0; \
_li->next=0; \
if(!(new)) \
memset((list), 0, sizeof(typeof(*(list)))); \
} while (0)
/*
* list_last
*
* It returns the last element of the `list' llist
*/
#define list_last(list) \
({ \
l_list *_il=(l_list *)(list); \
for(; _il && _il->next; _il=(l_list *)_il->next); \
(typeof((list)))_il; \
})
/*
* list_head
*
* Returns the head of the linked list.
*/
#define list_head(tail) \
({ \
l_list *_ih=(l_list *)(list); \
for(; _ih && _ih->prev; _ih=(l_list *)_ih->prev); \
(typeof((list)))_ih; \
})
/*
* list_append
*
* It appends the `_new' struct at the end of the `_head' llist.
* If `_tail' is not 0, then it is considered as the end of the llist and the
* `_head' argument isn't required.
* If `_tail' is 0, the end will be reached by traversing the entire llist,
* starting from `_head'.
* If both `_tail' and `_head' are 0, `new->next' and `new->prev' will be set
* to 0.
* The new tail is always returned.
* Example: tail=list_append(0, tail, new);
* or
* list_append(head, 0, new);
*/
#define list_append(_head, _tail, _new) \
({ \
l_list *_tt, *_na; \
_tt=(_tail) ? (l_list *)(_tail) : (l_list *)list_last((_head)); \
_na=(l_list *)(_new); \
if(_na != _tt) { \
if(_tt) \
_tt->next=_na; \
if(_na) { \
_na->prev=_tt; \
_na->next=0; \
} \
} \
_new; \
})
/*
* list_add
*
* It adds the `_new' struct at the start of the `_head' llist.
* The new head of the llist is returned.
*
* Example:
* head=list_add(head, new);
*/
#define list_add(_head, _new) \
({ \
l_list *_hd, *_nd; \
_hd=(l_list *)(_head); \
_nd=(l_list *)(_new); \
if(_hd != _nd) { \
_nd->next=_hd; \
_nd->prev=0; \
if(_hd) \
_hd->prev=_nd; \
} \
(typeof((_head)))_nd; \
})
/*
* list_join:
* before list_join(list):
* ... <-> A <-> list <-> C <-> ...
* after:
* ... <-> A <-> C <-> ...
* Note that `list' is not freed!
* It returns the head of the list, so call it in this way:
* head=list_join(head, list);
*/
#define list_join(head, list) \
({ \
l_list *_lj=(l_list *)(list), *_hj=(l_list *)(head), *_ret; \
if(_lj->next) \
_lj->next->prev=_lj->prev; \
if(_lj->prev) \
_lj->prev->next=_lj->next; \
_ret = _lj == _hj ? _lj->next : _hj; \
(typeof((head)))_ret; \
})
#define list_free(list) \
do { \
memset((list), 0, sizeof(typeof(*(list)))); \
xfree((list)); \
} while(0)
/*
* list_del
*
* It's the same of list_join() but it frees the `list'.
* It returns the new head of the linked list, so it must be called in
* this way: head=list_del(head, list);
*/
#define list_del(head, list) \
({ \
l_list *_lid=(l_list *)(list), *_hed=(l_list *)(head); \
\
_hed=(l_list *)list_join((head), _lid); \
list_free(_lid); \
(typeof((head)))_hed; \
})
/*
* list_ins
*
* It inserts the `new' struct between the `list' and `list'->next
* structs.
*/
#define list_ins(list, new) \
do { \
l_list *_lin=(l_list *)(list), *_n=(l_list *)(new); \
if(_lin->next) \
_lin->next->prev=_n; \
_n->next=_lin->next; \
_lin->next=_n; \
_n->prev=_lin; \
} while (0)
/*
* list_substitute
*
* It removes from the llist the `old_list' struct and inserts in its
* position the `new_list' struct
* Note that `old_list' isn't freed, it is just unlinked from the llist.
*/
#define list_substitute(old_list, new_list) \
do{ \
l_list *_ns, *_os; \
_ns=(l_list *)(new_list); \
_os=(l_list *)(old_list); \
if(_os->next != _ns) \
_ns->next=_os->next; \
if(_os->prev != _ns) \
_ns->prev=_os->prev; \
if(_ns->next) \
_ns->next->prev=_ns; \
if(_ns->prev) \
_ns->prev->next=_ns; \
}while(0)
/*
* list_swap
*
* Before: H -> Y <-> [A] <-> I <-> [B] <-> P <-> T
* list_swap(A, B);
* After: H -> Y <-> [B] <-> I <-> [A] <-> P <-> T
*/
#define list_swap(a, b) \
do{ \
l_list _ltmp, *_aa, *_bb; \
_aa=(l_list *)(a); \
_bb=(l_list *)(b); \
if(_aa->next == _bb) { \
list_substitute(_aa, _bb); \
list_ins(_bb, _aa); \
} else if(_aa->prev == _bb) { \
list_substitute(_bb, _aa); \
list_ins(_aa, _bb); \
} else { \
_ltmp.next=(l_list *)_bb->next; \
_ltmp.prev=(l_list *)_bb->prev; \
list_substitute(_aa, _bb); \
list_substitute(&_ltmp, _aa); \
} \
}while(0)
/*
* list_moveback
*
* It swaps `list' with its previous struct
*/
#define list_moveback(list) \
do{ \
l_list *_lm=(l_list *)(list); \
if(_lm->prev) \
list_swap(_lm->prev, _lm); \
}while(0)
/*
* list_movefwd
*
* It swaps `list' with its next struct
*/
#define list_movefwd(list) \
do{ \
l_list *_lmf=(l_list *)(list); \
if(_lmf->next) \
list_swap(_lmf->next, _lmf); \
}while(0)
/*
* list_moveontop
*
* `_list' must be already present in the `_head' llist, otherwise this
* function is just equal to list_add().
*
* list_moveontop() moves `_list' on top of the `_head' llist, thus:
* - `_list' is joined (see list_join() above)
* - `_list' becomes the new head
* - `_head' goes in `_list'->next
* The new head of the llist is returned.
*
* Example: head=list_moveontop(head, list);
*/
#define list_moveontop(_head, _list) \
({ \
l_list *_hmt=(l_list *)(_head), *_lmt=(l_list *)(_list); \
\
if(_hmt != _lmt) { \
_hmt=(l_list *)list_join((typeof((_head)))_hmt, _lmt); \
_hmt=(l_list *)list_add((typeof((_head)))_hmt, _lmt); \
} \
(typeof((_head)))_hmt; \
})
/*
* list_for
*
* Pretty simple, use it in this way:
* my_llist_ptr *index;
* index=head_of_the_llist;
* list_for(index) {
* do_something_with(index);
* }
*
* WARNING: do not use expressions!! For example:
* DO NOT THIS
* list_for(index=head_of_the_llist) {
* ...
* }
* DO NOT THIS
* In this case `index' will be set to `head_of_the_llist' each time and
* you'll get an infinite loop;
*/
#define list_for(i) for(; (i); (i)=(typeof (i))(i)->next)
/*
* list_count
*
* Returns the number of structs present in the llist
*/
#define list_count(_head) \
({ \
l_list *_lc=(l_list *)(_head); \
int _ic=0; \
\
list_for(_lc) \
_ic++; \
_ic; \
})
/*
* list_safe_for
*
* Use this for if you want to do something like:
* list_for(list)
* list_del(list);
* If you are trying to do that, the normal list_for isn't safe! That's
* because when list_del will free the current `list', list_for will use a
* wrong list->next pointer, which doesn't exist at all.
* list_for_del is the same as list_for but it takes a second parameter, which
* is a list pointer. This pointer will be used to store, before executing the
* code inside the for, the list->next pointer.
* So this is a safe for. Example:
*
* l_list *ptr;
* list_safe_for(list, ptr) {
* ... do stuff ...
* }
*
* WARNING: do not use expressions in the arguments, (see the warning above
* for the normal list_for)
*/
#define list_safe_for(_ii, _next_ptr) \
for((_ii) ? (_next_ptr)=(typeof (_ii))(_ii)->next : 0; (_ii); \
(_ii)=(_next_ptr), (_ii) ? (_next_ptr)=(typeof (_ii))(_ii)->next : 0)
/*
* list_pos: returns the `pos'-th struct present in `list'
*/
#define list_pos(list, pos) \
({ \
int _ip=0; \
l_list *_xp=(l_list *)(list); \
list_for(_xp) { \
if(_ip==(pos)) \
break; \
else \
_ip++; \
} \
(typeof((list)))_xp; \
})
/*
* list_get_pos: returns the position of the `list' struct in the `head'
* linked list, so that list_pos(head, list_get_pos(head, list)) == list
* If `list' is not present in the linked list, -1 is returned.
*/
#define list_get_pos(head, list) \
({ \
int _igp=0, _egp=0; \
l_list *_xgp=(l_list *)(head); \
\
list_for(_xgp) { \
if(_xgp == (l_list *)(list)) { \
_egp=1; \
break; \
} else \
_igp++; \
} \
_egp ? _igp : -1; \
})
/*
* list_destroy
*
* It traverse the entire `list' llist and calls list_del() on each
* struct.
*/
#define list_destroy(list) \
do{ \
l_list *_xd=(l_list *)(list), *_id, *_nextd; \
_id=_xd; \
list_safe_for(_id, _nextd) \
_xd=list_del(_xd, _id); \
(list)=0; \
}while(0)
/*
* list_copy_some
*
* It calls the `check_func' function for each struct of the `list' llist,
* passing to it, as first argument, a pointer to the struct itself.
* The other parameters to list_copy_some are passed to `check_func', for
* example by calling:
* list_copy_some(list, my_check_func, arg1, arg2, arg3);
* the `my_check_func' will be called in this way:
* my_check_func(arg1, arg2, arg3);
*
* If the `check_func' function returns a non zero value, the struct is
* copied in a new allocated space.
* All the copied structs form the replicated llist.
* Its head is returned.
*
* The `list' llist is not modified.
*/
#define list_copy_some(list, check_func, func_args...) \
({ \
l_list *_ncs=0, *_hcs=0, *_tcs=0, *_lcs=(l_list *)(list); \
\
list_for(_lcs) { \
if(!check_func(((typeof((list)))_lcs), ## func_args )) \
continue; \
\
_ncs=(l_list *)list_dup(((typeof((list)))_lcs)); \
if(!_hcs) _hcs=_ncs; \
\
_tcs=list_append(0, _tcs, _ncs); \
} \
\
(typeof((list)))_hcs; \
})
/*
* list_copy_all
*
* It copies the entire `list' llist in a new allocated one.
* It returns the head to the replicated llist.
* The `list' llist is not modified.
*/
#define list_copy_all_yes(_nil) (1)
#define list_copy_all(list) list_copy_some((list), list_copy_all_yes)
/*
* Here below there are the definitions for the linked list with a counter.
* The arguments format is:
* l_list **_head, int *_counter, l_list *list
*/
#define clist_add(_head, _counter, _list) \
do{ \
if(!(*(_counter)) || !(*(_head))) \
list_init(*(_head), (_list)); \
else \
*((_head))=list_add(*(_head), (_list)); \
(*(_counter))++; \
}while(0)
#define clist_append(_head, _tail, _counter, _list) \
do{ \
l_list *_tca=0, **_targv=(l_list **)(_tail); \
if((_tail)) \
_tca=*_targv; \
if(!(*(_counter)) || !(*(_head))) \
list_init(*(_head), (_list)); \
else { \
_tca=(l_list *)list_append(*(_head), _tca, (_list)); \
if(_targv) \
(*_targv)=_tca; \
} \
(*(_counter))++; \
}while(0)
#define clist_del(_head, _counter, _list) \
do{ \
if((*(_counter)) > 0) { \
*((_head))=list_del(*(_head), (_list)); \
(*(_counter))--; \
} \
}while(0)
#define clist_ins(_head, _counter, _list) \
do{ \
if(!(*(_counter)) || !(*(_head))) \
clist_add((_head), (_counter), (_list)); \
else { \
list_ins(*(_head), (_list)); \
(*(_counter))++; \
} \
}while(0)
#define clist_join(_head, _counter, _list) \
do{ \
if((*(_counter)) > 0) { \
*((_head))=list_join((*(_head)), _list); \
(*(_counter))--; \
} \
} while(0)
/*
* Zeros the `counter' and set the head pointer to 0.
* usage: head=clist_init(&counter);
*/
#define clist_init(_counter) \
({ \
*(_counter)=0; \
0; \
})
#define clist_destroy(_head, _counter) \
({ \
list_destroy(*((_head))); \
(*(_head))=0; \
(*(_counter))=0; \
0; \
})
/*
* clist_qsort
*
* It qsorts the `_head' llist, which has `_counter' elements.
* The `_cmp_func' function will be used to compare two llist.
* The new head of the llist is returned. Example:
* head=clist_qsort(head, counter, my_cmp_func);
* `counter' can be also 0, but it's better if you've counted already.
*
* Btw, this function just calls qsort(3), this is how it works:
* - first of all it counts how many elements there are in the llist.
* This is done only if `_counter' is 0.
* - it uses a temporary callocated array to store all the pointers to the
* elements of the llist.
* tmp[0]=_head; tmp[1]=_head->next; tmp[..]=_head->next->..
* - it calls qsort(3) on the tmp array. Note that qsort gives the
* address of &tmp[x] and &tmp[y] to `_cmp_func()', thus `_cmp_func()'
* should be aware of this.
* - it follows the new order of `tmp' and appends each array element in
* a new llist.
* - the head of the new llist is returned.
*/
#define clist_qsort(_head, _counter, _cmp_func) \
({ \
l_list *_hcq=(l_list *)(_head), *_ncq, *_hecq, *_tcq; \
int _icq=0, _ccq; \
\
_ccq = !(_counter) ? list_count(_hcq) : (_counter); \
l_list *_tmp_list[_ccq]; \
\
_ncq=_hcq; \
list_for(_ncq) { \
_tmp_list[_icq]=_ncq; \
_icq++; \
} \
\
qsort(_tmp_list, _ccq, sizeof(l_list *), (_cmp_func)); \
\
_tcq=0; \
_hecq=_tmp_list[0]; \
for(_icq=0; _icq<_ccq; _icq++) \
_tcq=(l_list *)list_append(0, _tcq, _tmp_list[_icq]); \
\
(typeof((_head)))_hecq; \
}) \
#endif /*LLIST_C*/