Cyclic L1-list. Implements almost the same set of operations as for L2-list
(except those, which reverse enumeration of elements).
This commit is contained in:
parent
767638bc86
commit
87e528bd58
4 changed files with 1065 additions and 0 deletions
666
src/lib/slist.h
Normal file
666
src/lib/slist.h
Normal file
|
|
@ -0,0 +1,666 @@
|
||||||
|
/*
|
||||||
|
* slist.h - simple intrusive cyclic single linked list
|
||||||
|
*
|
||||||
|
* Copyright (C) Lumiera.org
|
||||||
|
* 2009 Anton Yakovlev <just.yakovlev@gmail.com>
|
||||||
|
*
|
||||||
|
* This program 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 program 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. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SLIST_H
|
||||||
|
#define SLIST_H
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* Intrusive cyclic single linked list.
|
||||||
|
*
|
||||||
|
* List node is a structure, which consists only of a forward pointer. This is
|
||||||
|
* much easier and makes code much cleaner, than to have forward pointer as is.
|
||||||
|
* In a empty initialized node, this pointer points to the node itself. Note
|
||||||
|
* that this pointer can never ever become NULL.
|
||||||
|
*
|
||||||
|
* This lists are used by using one node as 'root' node where it's pointer is
|
||||||
|
* the head pointer to the actual list. Care needs to be taken to ensure not to
|
||||||
|
* apply any operations meant to be applied to data nodes to the root node.
|
||||||
|
* This way is the prefered way to use this lists.
|
||||||
|
*
|
||||||
|
* Alternatively one can store only a chain of data nodes and use a SList
|
||||||
|
* pointer to point to the first item (which might be NULL in case no data is
|
||||||
|
* stored). When using such approach care must be taken since most functions
|
||||||
|
* below expect lists to have a root node.
|
||||||
|
*
|
||||||
|
* Due to nature of single linked list, there's no easy way to implement
|
||||||
|
* functions, which need reverse passing through a list. But some of L1-list
|
||||||
|
* interface functions need such ability (for example, when we need to find
|
||||||
|
* previous element for current element). Because search of previous element
|
||||||
|
* requires visiting of exactly N-1 nodes (where N is length of L1-list), we
|
||||||
|
* use root node as start point. This gives to us probability of visiting
|
||||||
|
* 1 <= C <= N-1 nodes, and, thus, speed up search.
|
||||||
|
*
|
||||||
|
* This header can be used in 2 different ways:
|
||||||
|
* 1) (prerefered) just including it provides all functions as static inlined
|
||||||
|
* functions. This is the default
|
||||||
|
* 2) #define LLIST_INTERFACE before including this header gives only the declarations
|
||||||
|
* #define LLIST_IMPLEMENTATION before including this header yields in definitions
|
||||||
|
* this can be used to generate a library. This is currently untested and not
|
||||||
|
* recommended.
|
||||||
|
* The rationale for using inlined functions is that most functions are very
|
||||||
|
* small and likely to be used in performance critical parts. Inlining can give
|
||||||
|
* a hughe performance and optimization improvement here. The few functions
|
||||||
|
* which are slightly larger are expected to be the less common used ones, so
|
||||||
|
* inlining them too shouldn't be a problem either.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* TODO __STDC_VERSION__ 199901L
|
||||||
|
150) This macro was not specified in ISO/IEC 9899:1990 and was specified as 199409L in
|
||||||
|
ISO/IEC 9899/AMD1:1995. The intention is that this will remain an integer constant of type long
|
||||||
|
int that is increased with each revision of this International Standard.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_INLINE
|
||||||
|
# define SLIST_MACRO static inline
|
||||||
|
#else
|
||||||
|
# ifdef __GNUC__
|
||||||
|
# define SLIST_MACRO static __inline__
|
||||||
|
# else
|
||||||
|
# define SLIST_MACRO static
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(SLIST_INTERFACE)
|
||||||
|
/* only the interface is generated */
|
||||||
|
#define SLIST_FUNC(proto, ...) proto
|
||||||
|
#elif defined(SLIST_IMPLEMENTATION)
|
||||||
|
/* generate a non inlined implementation */
|
||||||
|
#define SLIST_FUNC(proto, ...) proto { __VA_ARGS__ }
|
||||||
|
#else
|
||||||
|
/* all functions are macro-like inlined */
|
||||||
|
#define SLIST_FUNC(proto, ...) SLIST_MACRO proto { __VA_ARGS__ }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Type of a slist node.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SLIST_DEFINED
|
||||||
|
#define SLIST_DEFINED
|
||||||
|
|
||||||
|
struct slist_struct {
|
||||||
|
struct slist_struct* next;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct slist_struct slist;
|
||||||
|
typedef slist* SList;
|
||||||
|
typedef const slist* const_SList;
|
||||||
|
typedef slist** SList_ref;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Macro to instantiate a local llist.
|
||||||
|
*
|
||||||
|
* @param name of the slist node
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define SLIST_AUTO( name ) slist name = { &name }
|
||||||
|
|
||||||
|
/*
|
||||||
|
* some macros for convenience
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define slist_head slist_next
|
||||||
|
#define slist_insert_head( list, element ) slist_insert( list, element )
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Сast back from a member of a structure to a pointer of the structure.
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
*
|
||||||
|
* struct point {
|
||||||
|
* int x;
|
||||||
|
* int y;
|
||||||
|
* slist list;
|
||||||
|
* };
|
||||||
|
*
|
||||||
|
* SList points = ...; // some initialization; must be the root of our list
|
||||||
|
*
|
||||||
|
* SLIST_FOREACH( points, current_node ) {
|
||||||
|
* struct point* current_point = SLIST_TO_STRUCTP( current_node, struct point, list );
|
||||||
|
* printf( "point = ( %d, %d )\n", current_point -> x, current_point -> y );
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* @param list is a pointer to the SList member of the linked structures
|
||||||
|
* @param type is type name of the linked structures
|
||||||
|
* @param member is a name of the SList member of the linked structures
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define SLIST_TO_STRUCTP( list, type, member ) \
|
||||||
|
( ( type* ) ( ( ( char* )( list ) ) - offsetof( type, member ) ) )
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Iterate forward over a list.
|
||||||
|
*
|
||||||
|
* @param list the root node of the list to be iterated
|
||||||
|
* @param node pointer to the iterated node
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define SLIST_FOREACH( list, node ) \
|
||||||
|
for ( SList node = slist_head( list ); ! slist_is_end( node, list ); slist_forward( &node ) )
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Iterate forward over a range.
|
||||||
|
*
|
||||||
|
* @param start first node to be interated
|
||||||
|
* @param end node after the last node be iterated
|
||||||
|
* @param node pointer to the iterated node
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define SLIST_FORRANGE( start, end, node ) \
|
||||||
|
for ( SList node = start; node != end; slist_forward( &node ) )
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Consume a list from head.
|
||||||
|
* The body of this statement should remove the head from the list, else it would be a infinite loop
|
||||||
|
*
|
||||||
|
* @param list the root node of the list to be consumed
|
||||||
|
* @param head pointer to the head node
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define SLIST_WHILE_HEAD( list, head ) \
|
||||||
|
for ( SList head = slist_head( list ); ! slist_is_empty( list ); head = slist_head( list ) )
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize a new llist.
|
||||||
|
* Must not be applied to a list node which is not empty! Lists need to be initialized
|
||||||
|
* before any other operation on them is called.
|
||||||
|
*
|
||||||
|
* @param list node to be initialized
|
||||||
|
*/
|
||||||
|
|
||||||
|
SLIST_FUNC (
|
||||||
|
void slist_init( SList list ),
|
||||||
|
list -> next = list;
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a node is not linked with some other node.
|
||||||
|
*/
|
||||||
|
|
||||||
|
SLIST_FUNC (
|
||||||
|
int slist_is_empty( const_SList list ),
|
||||||
|
return list -> next == list;
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if self is the only node in a list or self is not in a list.
|
||||||
|
*
|
||||||
|
* Warning:
|
||||||
|
* There's no check for empty list, so if you have a list with no items,
|
||||||
|
* you'll get seg fault here.
|
||||||
|
*
|
||||||
|
* @param list is root node of the list to be checked
|
||||||
|
*/
|
||||||
|
|
||||||
|
SLIST_FUNC (
|
||||||
|
int slist_is_single( const_SList list ),
|
||||||
|
return list -> next -> next == list;
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check for the head of a list.
|
||||||
|
*
|
||||||
|
* @param list is root node of the list
|
||||||
|
* @param head is expected head of the list
|
||||||
|
*/
|
||||||
|
|
||||||
|
SLIST_FUNC (
|
||||||
|
int slist_is_head( const_SList list, const_SList head ),
|
||||||
|
return list -> next == head;
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check for the end of a list.
|
||||||
|
* The end is by definition one past the tail of a list, which is the root node itself.
|
||||||
|
*
|
||||||
|
* @param list is root node of the list
|
||||||
|
* @param end is expected end of the list
|
||||||
|
*/
|
||||||
|
|
||||||
|
SLIST_FUNC (
|
||||||
|
int slist_is_end( const_SList list, const_SList end ),
|
||||||
|
return list == end;
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a node is a member of a list.
|
||||||
|
*
|
||||||
|
* @param list is root node of the list
|
||||||
|
* @param member is node to be searched
|
||||||
|
*/
|
||||||
|
|
||||||
|
SLIST_FUNC (
|
||||||
|
int slist_is_member( const_SList list, const_SList member ),
|
||||||
|
for ( const_SList i = member -> next; i != member; i = i -> next ) {
|
||||||
|
if ( i == list ) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check the order of elements in a list.
|
||||||
|
*
|
||||||
|
* @param list is root node of the list
|
||||||
|
* @param before is expected to be before after
|
||||||
|
* @param after is expected to be after before
|
||||||
|
*/
|
||||||
|
|
||||||
|
SLIST_FUNC (
|
||||||
|
int slist_is_before_after( const_SList list, const_SList before, const_SList after ),
|
||||||
|
for ( const_SList i = before -> next; i != list; i = i -> next ) {
|
||||||
|
if ( i == after ) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Count the nodes of a list.
|
||||||
|
*
|
||||||
|
* @param list is root node of the list
|
||||||
|
* @return number of nodes in `list`
|
||||||
|
*/
|
||||||
|
|
||||||
|
SLIST_FUNC (
|
||||||
|
unsigned slist_count( const_SList list ),
|
||||||
|
unsigned cnt = 0;
|
||||||
|
for ( const_SList i = list; i -> next != list; ++cnt, i = i -> next ) {
|
||||||
|
;
|
||||||
|
}
|
||||||
|
return cnt;
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get next node.
|
||||||
|
* Will not stop at tail.
|
||||||
|
*
|
||||||
|
* @param node is current node
|
||||||
|
* @return node after current node
|
||||||
|
*/
|
||||||
|
|
||||||
|
SLIST_FUNC (
|
||||||
|
SList slist_next( const_SList node ),
|
||||||
|
return node -> next;
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get previous node.
|
||||||
|
*
|
||||||
|
* @param list is root node of the list
|
||||||
|
* @param node is current node
|
||||||
|
* @return node before current node
|
||||||
|
*/
|
||||||
|
|
||||||
|
SLIST_FUNC (
|
||||||
|
SList slist_prev( SList list, SList node ),
|
||||||
|
while ( list -> next != node ) {
|
||||||
|
list = list -> next;
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a node from a list.
|
||||||
|
*
|
||||||
|
* @param list is root node of the list
|
||||||
|
* @param node to be removed
|
||||||
|
* @return node
|
||||||
|
*/
|
||||||
|
|
||||||
|
SLIST_FUNC (
|
||||||
|
SList slist_unlink( SList list, SList node ),
|
||||||
|
SList prev_node = slist_prev( list, node );
|
||||||
|
prev_node -> next = node -> next;
|
||||||
|
return node -> next = node;
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Insert a node after another.
|
||||||
|
*
|
||||||
|
* @param head is node after which we want to insert
|
||||||
|
* @param node is node which shall be inserted after `head`. Could already linked to a list from where it will be removed.
|
||||||
|
* @return head
|
||||||
|
*/
|
||||||
|
|
||||||
|
SLIST_FUNC (
|
||||||
|
SList slist_insert( SList head, SList node ),
|
||||||
|
if ( ! slist_is_empty( node ) ) {
|
||||||
|
slist_unlink( node, node );
|
||||||
|
}
|
||||||
|
node -> next = head -> next;
|
||||||
|
head -> next = node;
|
||||||
|
return head;
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Move the content of a list after a node in another list.
|
||||||
|
*
|
||||||
|
* @param xnode is node after which we want to insert a list
|
||||||
|
* @param ylist is root node of the list which shall be inserted after self. This list will be empty after call.
|
||||||
|
* @return xnode
|
||||||
|
*/
|
||||||
|
|
||||||
|
SLIST_FUNC (
|
||||||
|
SList slist_insert_list( SList xnode, SList ylist ),
|
||||||
|
if ( ! slist_is_empty( ylist ) ) {
|
||||||
|
SList tail = slist_prev( ylist, ylist ); // search for the Y list tail
|
||||||
|
tail -> next = xnode -> next;
|
||||||
|
xnode -> next = ylist -> next;
|
||||||
|
|
||||||
|
ylist -> next = ylist; // clear the Y list
|
||||||
|
}
|
||||||
|
return xnode;
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Move a range of nodes after a given node.
|
||||||
|
*
|
||||||
|
* @param node is node after which the range shall be inserted
|
||||||
|
* @param start first node in range to be moved
|
||||||
|
* @param end node after the last node of the range
|
||||||
|
* @return node
|
||||||
|
*/
|
||||||
|
|
||||||
|
SLIST_FUNC (
|
||||||
|
SList slist_insert_range( SList node, SList start, SList end ),
|
||||||
|
// insert range
|
||||||
|
SList tail = slist_prev( start, end ); // search for the end of range
|
||||||
|
tail -> next = node -> next;
|
||||||
|
node -> next = start -> next;
|
||||||
|
// fix list
|
||||||
|
start -> next = end;
|
||||||
|
return node;
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Swap a node with its next node.
|
||||||
|
* Advancing will not stop at tail, one has to check that if this is intended.
|
||||||
|
*
|
||||||
|
* @param list is root node of the list
|
||||||
|
* @param node is node to be advaced
|
||||||
|
* @return node
|
||||||
|
*/
|
||||||
|
|
||||||
|
SLIST_FUNC (
|
||||||
|
SList slist_advance( SList list, SList node ),
|
||||||
|
SList prev = slist_prev( list, node );
|
||||||
|
prev -> next = node -> next;
|
||||||
|
node -> next = node -> next -> next;
|
||||||
|
prev -> next -> next = node;
|
||||||
|
return node;
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Advance a pointer to a node to its next node.
|
||||||
|
*
|
||||||
|
* @param node pointer-to-pointer to the current node. `node` will point to the next node after this call.
|
||||||
|
*/
|
||||||
|
|
||||||
|
SLIST_FUNC (
|
||||||
|
void slist_forward( SList_ref node ),
|
||||||
|
*node = ( *node ) -> next;
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the nth element of a list (this function does not stop at head/tail).
|
||||||
|
*
|
||||||
|
* @param list is root node of the list to be queried
|
||||||
|
* @param n is number of element to find
|
||||||
|
* @return |n|-th element of list
|
||||||
|
*/
|
||||||
|
|
||||||
|
SLIST_FUNC (
|
||||||
|
SList slist_get_nth( SList list, unsigned int n ),
|
||||||
|
while ( n-- > 0 ) {
|
||||||
|
list = slist_next( list );
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the nth element of a list with a stop node.
|
||||||
|
*
|
||||||
|
* @param list is root node of the list to be queried
|
||||||
|
* @param n is number of element to find
|
||||||
|
* @param stop is node which will abort the iteration
|
||||||
|
* @return |n|-th element of list or NULL if `stop` node has been reached
|
||||||
|
*/
|
||||||
|
|
||||||
|
SLIST_FUNC (
|
||||||
|
SList slist_get_nth_stop( SList list, unsigned int n, const_SList stop ),
|
||||||
|
while ( n-- > 0 ) {
|
||||||
|
list = slist_next( list );
|
||||||
|
if ( list == stop ) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sort a list.
|
||||||
|
*
|
||||||
|
* This is iterative version of bottom-up merge sort for (L1/L2) linked-list:
|
||||||
|
* + there's no recursion
|
||||||
|
* + there's no extra stackspace allocation (only a few bytes for locals)
|
||||||
|
* Such implementation should be optimal and fast enough.
|
||||||
|
*
|
||||||
|
* Maybe this function is too big for inlining (though I don't think so), so
|
||||||
|
* maybe somebody can make it smaller without losing perfomance? ;)
|
||||||
|
*
|
||||||
|
* @param list is root node of a list to be sorted
|
||||||
|
* @param cmp is compare function of 2 SList items
|
||||||
|
* @return list
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef int ( *slist_cmpfn )( const_SList a, const_SList b );
|
||||||
|
|
||||||
|
SLIST_FUNC (
|
||||||
|
SList slist_sort( SList list, slist_cmpfn cmp ),
|
||||||
|
if ( ! slist_is_single( list ) ) {
|
||||||
|
|
||||||
|
unsigned int length = slist_count( list );
|
||||||
|
|
||||||
|
// `max_size` is a half of minimum power of 2, greater of equal to `length`
|
||||||
|
// ( 2 * max_size = 2^k ) >= length
|
||||||
|
// We need `max_size` value for proper binary division of a list for sorting.
|
||||||
|
|
||||||
|
unsigned long long max_size = 1;
|
||||||
|
while ( ( max_size << 1 ) < length ) {
|
||||||
|
max_size <<= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The main idea of bottom-up merge sort is sequential merging of each pair
|
||||||
|
// of sequences of { 1, .. 2^k, .. max_size } length. That's all. :)
|
||||||
|
|
||||||
|
for ( unsigned int size = 1; size <= max_size; size <<= 1 ) {
|
||||||
|
|
||||||
|
// On each iteration:
|
||||||
|
// * `result` points to the current node of global (merged/sorted) list.
|
||||||
|
// thus, we can holds all nodes are linked.
|
||||||
|
// * `left` and `right` points to begin of (sub)lists for merging.
|
||||||
|
|
||||||
|
SList result = list;
|
||||||
|
SList left = list -> next;
|
||||||
|
SList right;
|
||||||
|
|
||||||
|
// Process each pairs of sequences of size=2^k length.
|
||||||
|
|
||||||
|
for ( unsigned int position = 0; position < length; position += size + size ) {
|
||||||
|
|
||||||
|
right = slist_get_nth_stop( left, size, list );
|
||||||
|
|
||||||
|
unsigned int size_left = size;
|
||||||
|
unsigned int size_right = right == NULL ? 0 : size;
|
||||||
|
|
||||||
|
// Here we have 2 sublists of `size_left` and `size_right` sizes.
|
||||||
|
// Implementation of `merge` function is next three loops.
|
||||||
|
|
||||||
|
while ( ( size_left > 0 ) && ( size_right > 0 ) ) {
|
||||||
|
|
||||||
|
if ( cmp( left, right ) <= 0 ) {
|
||||||
|
|
||||||
|
result -> next = left;
|
||||||
|
|
||||||
|
left = left -> next;
|
||||||
|
if ( left == list ) {
|
||||||
|
size_left = 0;
|
||||||
|
} else {
|
||||||
|
size_left--;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
result -> next = right;
|
||||||
|
|
||||||
|
right = right -> next;
|
||||||
|
if ( right == list ) {
|
||||||
|
size_right = 0;
|
||||||
|
} else {
|
||||||
|
size_right--;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
result = result -> next;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
while ( size_left > 0 ) {
|
||||||
|
result -> next = left;
|
||||||
|
result = left;
|
||||||
|
|
||||||
|
left = left -> next;
|
||||||
|
if ( left == list ) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
size_left--;
|
||||||
|
}
|
||||||
|
|
||||||
|
while ( size_right > 0 ) {
|
||||||
|
result -> next = right;
|
||||||
|
result = right;
|
||||||
|
|
||||||
|
right = right -> next;
|
||||||
|
if ( right == list ) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
size_right--;
|
||||||
|
}
|
||||||
|
|
||||||
|
// go to begin of next pair of sequences
|
||||||
|
|
||||||
|
left = right;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// here `result` points to the last node of a list.
|
||||||
|
// we wanna keep cyclic list.
|
||||||
|
|
||||||
|
result -> next = list;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find the first occurence of an element in a list.
|
||||||
|
* Does not change the order of a list.
|
||||||
|
*
|
||||||
|
* @param list is root node of a list to be searched
|
||||||
|
* @param pattern is template for the element being searched
|
||||||
|
* @param cmp is compare function of 2 SList items
|
||||||
|
* @return pointer to the found SList element or NULL if nothing found
|
||||||
|
*/
|
||||||
|
|
||||||
|
SLIST_FUNC (
|
||||||
|
SList slist_find( const_SList list, const_SList pattern, slist_cmpfn cmp ),
|
||||||
|
SLIST_FOREACH( list, node ) {
|
||||||
|
if ( cmp( node, pattern ) == 0 ) {
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find the first occurence of an element in an unsorted list.
|
||||||
|
*
|
||||||
|
* Searches the list until it finds the searched element and moves it then to
|
||||||
|
* the head. Useful if the order of the list is not required and few elements
|
||||||
|
* are frequently searched.
|
||||||
|
*
|
||||||
|
* @param list is root node of a list to be searched
|
||||||
|
* @param pattern is template for the element being searched
|
||||||
|
* @param cmp is compare function of 2 SList items
|
||||||
|
* @return pointer to the found SList element (head) or NULL if nothing found
|
||||||
|
*/
|
||||||
|
|
||||||
|
SLIST_FUNC (
|
||||||
|
SList slist_ufind( SList list, const_SList pattern, slist_cmpfn cmp ),
|
||||||
|
SLIST_FOREACH( list, node ) {
|
||||||
|
if ( cmp( node, pattern ) == 0 ) {
|
||||||
|
slist_insert_head( list, node );
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find the first occurence of an element in a sorted list.
|
||||||
|
*
|
||||||
|
* Searches the list until it finds the searched element, exits searching when
|
||||||
|
* found an element biggier than the searched one.
|
||||||
|
*
|
||||||
|
* @param list is root node of a list to be searched
|
||||||
|
* @param pattern is template for the element being searched
|
||||||
|
* @param cmp is compare function of 2 SList items
|
||||||
|
* @return pointer to the found SList element (head) or NULL if nothing found
|
||||||
|
*/
|
||||||
|
|
||||||
|
SLIST_FUNC (
|
||||||
|
SList slist_sfind( const_SList list, const_SList pattern, slist_cmpfn cmp ),
|
||||||
|
SLIST_FOREACH( list, node ) {
|
||||||
|
|
||||||
|
int result = cmp( node, pattern );
|
||||||
|
|
||||||
|
if ( result == 0 ) {
|
||||||
|
return node;
|
||||||
|
} else if ( result > 0 ) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
)
|
||||||
|
|
||||||
|
#endif /* SLIST_H */
|
||||||
46
tests/15slist.tests
Normal file
46
tests/15slist.tests
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
TESTING "Single Linked Lists" ./test-slist
|
||||||
|
|
||||||
|
TEST "initialization and predicates" basic <<END
|
||||||
|
out: 1
|
||||||
|
out: 0
|
||||||
|
out: 1
|
||||||
|
out: 0
|
||||||
|
out: 1
|
||||||
|
out: 0
|
||||||
|
out: 1
|
||||||
|
out: 0
|
||||||
|
END
|
||||||
|
|
||||||
|
TEST "insert/delete nodes" insert_delete <<END
|
||||||
|
out: 1
|
||||||
|
out: 0
|
||||||
|
out: 1
|
||||||
|
out: 0
|
||||||
|
out: 1
|
||||||
|
END
|
||||||
|
|
||||||
|
TEST "moving across a list" movement <<END
|
||||||
|
out: 1
|
||||||
|
END
|
||||||
|
|
||||||
|
TEST "enumerates elements of a list" enumerations <<END
|
||||||
|
out: A B C D .
|
||||||
|
out: ---
|
||||||
|
out: B C .
|
||||||
|
out: ---
|
||||||
|
out: A B C D .
|
||||||
|
out: 1
|
||||||
|
END
|
||||||
|
|
||||||
|
TEST "get length and n-th element of a list" count <<END
|
||||||
|
out: 3
|
||||||
|
out: 1
|
||||||
|
END
|
||||||
|
|
||||||
|
TEST "sorts a list" sort <<END
|
||||||
|
return: 0
|
||||||
|
END
|
||||||
|
|
||||||
|
TEST "finds element inside a list" search <<END
|
||||||
|
out: 1
|
||||||
|
END
|
||||||
|
|
@ -69,6 +69,10 @@ test_resourcecollector_SOURCES = $(tests_srcdir)/library/test-resourcecollector.
|
||||||
test_resourcecollector_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -I$(top_srcdir)/src/
|
test_resourcecollector_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -I$(top_srcdir)/src/
|
||||||
test_resourcecollector_LDADD = $(NOBUGMT_LUMIERA_LIBS) liblumierabackend.la liblumieracommon.la liblumieraproc.la -ldl liblumiera.la -lboost_program_options-mt -lboost_regex-mt
|
test_resourcecollector_LDADD = $(NOBUGMT_LUMIERA_LIBS) liblumierabackend.la liblumieracommon.la liblumieraproc.la -ldl liblumiera.la -lboost_program_options-mt -lboost_regex-mt
|
||||||
|
|
||||||
|
check_PROGRAMS += test-slist
|
||||||
|
test_slist_SOURCES = $(tests_srcdir)/library/test-slist.c
|
||||||
|
test_slist_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror
|
||||||
|
test_slist_LDADD = $(NOBUGMT_LUMIERA_LIBS) liblumiera.la -lboost_program_options-mt -lboost_regex-mt
|
||||||
|
|
||||||
check_PROGRAMS += test-config
|
check_PROGRAMS += test-config
|
||||||
test_config_SOURCES = $(tests_srcdir)/common/test-config.c
|
test_config_SOURCES = $(tests_srcdir)/common/test-config.c
|
||||||
|
|
|
||||||
349
tests/library/test-slist.c
Normal file
349
tests/library/test-slist.c
Normal file
|
|
@ -0,0 +1,349 @@
|
||||||
|
/*
|
||||||
|
* test-slist.c - test the linked list lib
|
||||||
|
*
|
||||||
|
* Copyright (C) Lumiera.org
|
||||||
|
* 2009 Anton Yakovlev <just.yakovlev@gmail.com>
|
||||||
|
*
|
||||||
|
* This program 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 program 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. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "lib/slist.h"
|
||||||
|
#include "tests/test.h"
|
||||||
|
|
||||||
|
#include <sys/time.h>
|
||||||
|
|
||||||
|
typedef struct item {
|
||||||
|
int key;
|
||||||
|
slist list;
|
||||||
|
} item_t;
|
||||||
|
|
||||||
|
int cmp( const_SList a, const_SList b ) {
|
||||||
|
|
||||||
|
item_t* x = SLIST_TO_STRUCTP( a, item_t, list );
|
||||||
|
item_t* y = SLIST_TO_STRUCTP( b, item_t, list );
|
||||||
|
|
||||||
|
if ( x -> key < y -> key ) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( x -> key > y -> key ) {
|
||||||
|
return +1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
TESTS_BEGIN
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 1. Basic:
|
||||||
|
* SLIST_AUTO( name )
|
||||||
|
* void slist_init( SList list )
|
||||||
|
* int slist_is_empty( const_SList list )
|
||||||
|
* int slist_is_single( const_SList list )
|
||||||
|
* int slist_is_head( const_SList list, const_SList head )
|
||||||
|
* int slist_is_end( const_SList list, const_SList end )
|
||||||
|
* int slist_is_member( const_SList list, const_SList member )
|
||||||
|
* int slist_is_before_after( const_SList list, const_SList before, const_SList after )
|
||||||
|
*/
|
||||||
|
|
||||||
|
TEST( "basic" ) {
|
||||||
|
|
||||||
|
SLIST_AUTO( listX );
|
||||||
|
slist listY;
|
||||||
|
SLIST_AUTO( nodeA );
|
||||||
|
SLIST_AUTO( nodeB );
|
||||||
|
|
||||||
|
printf( "%d\n", slist_is_end( &listX, &listX ) );
|
||||||
|
|
||||||
|
slist_init( &listY );
|
||||||
|
|
||||||
|
printf( "%d\n", slist_is_empty( &listY ) );
|
||||||
|
|
||||||
|
slist_insert( &listX, &nodeA );
|
||||||
|
printf( "%d\n", slist_is_empty( &listX ) );
|
||||||
|
printf( "%d\n", slist_is_single( &listX ) );
|
||||||
|
printf( "%d\n", slist_is_head( &listX, &nodeA ) );
|
||||||
|
printf( "%d\n", slist_is_end( &listX, &nodeA ) );
|
||||||
|
printf( "%d\n", slist_is_member( &listX, &nodeA ) );
|
||||||
|
printf( "%d\n", slist_is_member( &listX, &nodeB ) );
|
||||||
|
|
||||||
|
slist_insert( &nodeA, &nodeB );
|
||||||
|
printf( "%d\n", slist_is_empty( &listX ) );
|
||||||
|
printf( "%d\n", slist_is_single( &listX ) );
|
||||||
|
printf( "%d\n", slist_is_head( &listX, &nodeB ) );
|
||||||
|
printf( "%d\n", slist_is_end( &listX, &nodeB ) );
|
||||||
|
printf( "%d\n", slist_is_member( &listX, &nodeB ) );
|
||||||
|
|
||||||
|
printf( "%d\n", slist_is_before_after( &listX, &nodeA, &nodeB ) );
|
||||||
|
printf( "%d\n", slist_is_before_after( &listX, &nodeB, &nodeA ) );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 2. Insert/delete:
|
||||||
|
* slist_insert_head( list, element )
|
||||||
|
* SList slist_insert( SList head, SList node )
|
||||||
|
* SList slist_insert_list( SList xnode, SList ylist )
|
||||||
|
* SList slist_insert_range( SList node, SList start, SList end )
|
||||||
|
* SList slist_unlink( SList list, SList node )
|
||||||
|
*/
|
||||||
|
|
||||||
|
TEST( "insert_delete" ) {
|
||||||
|
|
||||||
|
SLIST_AUTO( listX );
|
||||||
|
SLIST_AUTO( nodeA );
|
||||||
|
SLIST_AUTO( nodeB );
|
||||||
|
SLIST_AUTO( nodeC );
|
||||||
|
|
||||||
|
slist_insert_head( &listX, &nodeA );
|
||||||
|
slist_insert( &nodeA, &nodeB );
|
||||||
|
slist_insert( &nodeB, &nodeC );
|
||||||
|
printf( "%d\n", slist_next( &listX ) == &nodeA );
|
||||||
|
printf( "%d\n", slist_next( &nodeA ) == &nodeB );
|
||||||
|
printf( "%d\n", slist_next( &nodeB ) == &nodeC );
|
||||||
|
printf( "%d\n", slist_next( &nodeC ) == &listX );
|
||||||
|
|
||||||
|
slist_unlink( &listX, &nodeA );
|
||||||
|
printf( "%d\n", slist_next( &listX ) == &nodeB );
|
||||||
|
|
||||||
|
slist_insert( &listX, &nodeA );
|
||||||
|
printf( "%d\n", slist_next( &listX ) == &nodeA );
|
||||||
|
|
||||||
|
SLIST_AUTO( listY );
|
||||||
|
|
||||||
|
slist_insert_list( &listY, &listX );
|
||||||
|
printf( "%d\n", slist_is_empty( &listX ) );
|
||||||
|
printf( "%d\n", slist_next( &listY ) == &nodeA );
|
||||||
|
printf( "%d\n", slist_next( &nodeA ) == &nodeB );
|
||||||
|
printf( "%d\n", slist_next( &nodeB ) == &nodeC );
|
||||||
|
printf( "%d\n", slist_next( &nodeC ) == &listY );
|
||||||
|
|
||||||
|
slist_insert_range( &listX, &nodeA, &nodeB );
|
||||||
|
printf( "%d\n", slist_next( &listX ) == &nodeA );
|
||||||
|
printf( "%d\n", slist_next( &nodeA ) == &nodeB );
|
||||||
|
printf( "%d\n", slist_next( &nodeB ) == &listX );
|
||||||
|
|
||||||
|
printf( "%d\n", slist_is_single( &listY ) );
|
||||||
|
printf( "%d\n", slist_next( &listY ) == &nodeC );
|
||||||
|
printf( "%d\n", slist_next( &nodeC ) == &listY );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 3. Movements:
|
||||||
|
* slist_head()
|
||||||
|
* SList slist_next( const_SList node )
|
||||||
|
* SList slist_prev( SList list, SList node )
|
||||||
|
* SList slist_advance( SList list, SList node )
|
||||||
|
* void slist_forward( SList_ref node )
|
||||||
|
*/
|
||||||
|
|
||||||
|
TEST( "movement" ) {
|
||||||
|
|
||||||
|
SLIST_AUTO( listX );
|
||||||
|
SLIST_AUTO( nodeA );
|
||||||
|
SLIST_AUTO( nodeB );
|
||||||
|
SLIST_AUTO( nodeC );
|
||||||
|
|
||||||
|
slist_insert_head( &listX, &nodeA );
|
||||||
|
slist_insert( &nodeA, &nodeB );
|
||||||
|
slist_insert( &nodeB, &nodeC );
|
||||||
|
|
||||||
|
printf( "%d\n", slist_next( &listX ) == &nodeA );
|
||||||
|
printf( "%d\n", slist_next( &nodeA ) == &nodeB );
|
||||||
|
printf( "%d\n", slist_next( &nodeB ) == &nodeC );
|
||||||
|
printf( "%d\n", slist_next( &nodeC ) == &listX );
|
||||||
|
|
||||||
|
printf( "%d\n", slist_prev( &listX, &listX ) == &nodeC );
|
||||||
|
printf( "%d\n", slist_prev( &listX, &nodeC ) == &nodeB );
|
||||||
|
printf( "%d\n", slist_prev( &listX, &nodeB ) == &nodeA );
|
||||||
|
printf( "%d\n", slist_prev( &listX, &nodeA ) == &listX );
|
||||||
|
|
||||||
|
slist_advance( &listX, &nodeA );
|
||||||
|
printf( "%d\n", slist_next( &listX ) == &nodeB );
|
||||||
|
printf( "%d\n", slist_next( &nodeB ) == &nodeA );
|
||||||
|
printf( "%d\n", slist_next( &nodeA ) == &nodeC );
|
||||||
|
printf( "%d\n", slist_next( &nodeC ) == &listX );
|
||||||
|
|
||||||
|
SList node = &listX;
|
||||||
|
slist_forward( &node );
|
||||||
|
printf( "%d\n", node == &nodeB );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 4. Enumerations:
|
||||||
|
* SLIST_TO_STRUCTP( list, type, member )
|
||||||
|
* SLIST_FOREACH( list, node )
|
||||||
|
* SLIST_FORRANGE( start, end, node )
|
||||||
|
* SLIST_WHILE_HEAD( list, head )
|
||||||
|
*/
|
||||||
|
|
||||||
|
TEST( "enumerations" ) {
|
||||||
|
|
||||||
|
SLIST_AUTO( list );
|
||||||
|
|
||||||
|
item_t nodeA = { 'A', { NULL } };
|
||||||
|
item_t nodeB = { 'B', { NULL } };
|
||||||
|
item_t nodeC = { 'C', { NULL } };
|
||||||
|
item_t nodeD = { 'D', { NULL } };
|
||||||
|
|
||||||
|
slist_init( &nodeA.list );
|
||||||
|
slist_init( &nodeB.list );
|
||||||
|
slist_init( &nodeC.list );
|
||||||
|
slist_init( &nodeD.list );
|
||||||
|
|
||||||
|
slist_insert( &list, &nodeA.list );
|
||||||
|
slist_insert( &nodeA.list, &nodeB.list );
|
||||||
|
slist_insert( &nodeB.list, &nodeC.list );
|
||||||
|
slist_insert( &nodeC.list, &nodeD.list );
|
||||||
|
|
||||||
|
SLIST_FOREACH ( &list, node ) {
|
||||||
|
item_t* item = ( item_t* ) SLIST_TO_STRUCTP( node, item_t, list );
|
||||||
|
printf( "%c ", item -> key );
|
||||||
|
}
|
||||||
|
printf( ".\n" );
|
||||||
|
|
||||||
|
printf( "---\n" );
|
||||||
|
|
||||||
|
SLIST_FORRANGE ( &nodeB.list, &nodeD.list, node ) {
|
||||||
|
item_t* item = ( item_t* ) SLIST_TO_STRUCTP( node, item_t, list );
|
||||||
|
printf( "%c ", item -> key );
|
||||||
|
}
|
||||||
|
printf( ".\n" );
|
||||||
|
|
||||||
|
printf( "---\n" );
|
||||||
|
|
||||||
|
SLIST_WHILE_HEAD ( &list, head ) {
|
||||||
|
item_t* item = ( item_t* ) SLIST_TO_STRUCTP( head, item_t, list );
|
||||||
|
printf( "%c ", item -> key );
|
||||||
|
slist_unlink( &list, head );
|
||||||
|
}
|
||||||
|
printf( ".\n" );
|
||||||
|
|
||||||
|
printf( "%d\n", slist_is_empty( &list ) );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 5. Counting:
|
||||||
|
* unsigned slist_count( const_SList list )
|
||||||
|
* SList slist_get_nth( SList list, int n )
|
||||||
|
* SList slist_get_nth_stop( SList list, int n, const_SList stop )
|
||||||
|
*/
|
||||||
|
|
||||||
|
TEST( "count" ) {
|
||||||
|
|
||||||
|
SLIST_AUTO( list );
|
||||||
|
SLIST_AUTO( nodeA );
|
||||||
|
SLIST_AUTO( nodeB );
|
||||||
|
SLIST_AUTO( nodeC );
|
||||||
|
|
||||||
|
slist_insert( &list, &nodeA );
|
||||||
|
slist_insert( &nodeA, &nodeB );
|
||||||
|
slist_insert( &nodeB, &nodeC );
|
||||||
|
|
||||||
|
printf( "%u\n", slist_count( &list ) );
|
||||||
|
printf( "%d\n", slist_get_nth( &list, 3 ) == &nodeC );
|
||||||
|
printf( "%d\n", slist_get_nth_stop( &list, 3, &nodeC ) == NULL );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 6. Sort:
|
||||||
|
* SList slist_sort( SList list, slist_cmpfn cmp )
|
||||||
|
*/
|
||||||
|
|
||||||
|
TEST( "sort" ) {
|
||||||
|
|
||||||
|
srand( time( NULL ) );
|
||||||
|
|
||||||
|
SLIST_AUTO( list );
|
||||||
|
|
||||||
|
unsigned int n = 1000000;
|
||||||
|
|
||||||
|
item_t* items;
|
||||||
|
if ( ( items = ( item_t* ) malloc( sizeof( item_t ) * n ) ) == NULL ) {
|
||||||
|
return 1; // ERROR: not enough memory
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( unsigned int i = 0; i < n; i++ ) {
|
||||||
|
items[ i ].key = rand();
|
||||||
|
slist_init( &items[ i ].list );
|
||||||
|
slist_insert( &list, &items[ i ].list );
|
||||||
|
}
|
||||||
|
|
||||||
|
slist_sort( &list, cmp );
|
||||||
|
|
||||||
|
int is_first_cmp = 1;
|
||||||
|
int prev_key = 0;
|
||||||
|
|
||||||
|
SLIST_FOREACH ( &list, x ) {
|
||||||
|
item_t* item = SLIST_TO_STRUCTP( x, item_t, list );
|
||||||
|
if ( is_first_cmp ) {
|
||||||
|
is_first_cmp = 0;
|
||||||
|
} else if ( prev_key > item -> key ) {
|
||||||
|
return 2; // ERROR: wrong order of elements
|
||||||
|
}
|
||||||
|
prev_key = item -> key;
|
||||||
|
}
|
||||||
|
|
||||||
|
free( items );
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 7. Search:
|
||||||
|
* SList slist_find( const_SList list, const_SList pattern, slist_cmpfn cmp )
|
||||||
|
* SList slist_ufind( SList list, const_SList pattern, slist_cmpfn cmp )
|
||||||
|
* SList slist_sfind( const_SList list, const_SList pattern, slist_cmpfn cmp )
|
||||||
|
*/
|
||||||
|
|
||||||
|
TEST( "search" ) {
|
||||||
|
|
||||||
|
SLIST_AUTO( list );
|
||||||
|
|
||||||
|
item_t nodeA = { 'A', { NULL } };
|
||||||
|
item_t nodeB = { 'B', { NULL } };
|
||||||
|
item_t nodeC = { 'C', { NULL } };
|
||||||
|
item_t nodeD = { 'D', { NULL } };
|
||||||
|
item_t nodeX = { '?', { NULL } };
|
||||||
|
|
||||||
|
slist_init( &nodeA.list );
|
||||||
|
slist_init( &nodeB.list );
|
||||||
|
slist_init( &nodeC.list );
|
||||||
|
slist_init( &nodeD.list );
|
||||||
|
|
||||||
|
slist_insert( &list, &nodeA.list );
|
||||||
|
slist_insert( &nodeA.list, &nodeB.list );
|
||||||
|
slist_insert( &nodeB.list, &nodeC.list );
|
||||||
|
slist_insert( &nodeC.list, &nodeD.list );
|
||||||
|
|
||||||
|
nodeX.key = 'C';
|
||||||
|
|
||||||
|
printf( "%d\n", slist_find( &list, &nodeX.list, cmp ) == &nodeC.list );
|
||||||
|
printf( "%d\n", slist_ufind( &list, &nodeX.list, cmp ) == &nodeC.list );
|
||||||
|
printf( "%d\n", slist_next( &nodeC.list ) == &nodeA.list );
|
||||||
|
|
||||||
|
nodeX.key = 'A';
|
||||||
|
printf( "%d\n", slist_sfind( &list, &nodeX.list, cmp ) == NULL );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
TESTS_END
|
||||||
Loading…
Reference in a new issue