[RFC][PATCH] type safe list

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hello

This is implementaion of circular doubly linked parametrized list.
It is similar to the list implementation in include/linux/list.h
but it also provides type safety which allows to detect some of list manipulating
mistakes as soon as they happen.

Please consider how feasible is a chance to have this patch accepted.
These lists are widely used by reiser4. I believe others may find it useful.

Thanks
This is implementaion of circular doubly linked parametrized list.
It is similar to the list implementation in include/linux/list.h
but it also provides type safety which allows to detect some of list manipulating
mistakes as soon as they happen.


 include/linux/type_safe_list.h |  433 +++++++++++++++++++++++++++++++++++++++++
 1 files changed, 433 insertions(+)

diff -puN /dev/null include/linux/type_safe_list.h
--- /dev/null	2003-09-23 21:59:22.000000000 +0400
+++ linux-2.6.12-vs/include/linux/type_safe_list.h	2005-07-14 19:28:46.839464437 +0400
@@ -0,0 +1,433 @@
+#ifndef _LINUX_TYPE_SAFE_LIST_H
+#define _LINUX_TYPE_SAFE_LIST_H
+
+/* A circular doubly linked list that differs from the previous
+   <linux/list.h> implementation because it is parametrized to provide
+   type safety.  This data structure is also useful as a queue or stack.
+
+   The "list template" consists of a set of types and methods for
+   implementing list operations.  All of the types and methods
+   associated with a single list class are assigned unique names and
+   type signatures, thus allowing the compiler to verify correct
+   usage.
+
+   The first parameter of a list class is the item type being stored
+   in the list.  The list class maintains two pointers within each
+   item structure for its "next" and "prev" pointers.
+
+   There are two structures associated with the list, in addition to
+   the item type itself.  The "list link" contains the two pointers
+   that are embedded within the item itself.  The "list head" also
+   contains two pointers which refer to the first item ("front") and
+   last item ("back") of the list.
+
+   The list maintains a "circular" invariant, in that you can always
+   begin at the front and follow "next" pointers until eventually you
+   reach the same point.  The "list head" is included within the
+   cycle, even though it does not have the correct item type.  The
+   "list head" and "list link" types are different objects from the
+   user's perspective, but the core algorithms that operate on this
+   style of list treat the "list head" and "list link" as identical
+   types.  That is why these algorithms are so simple.
+
+   The <linux/list.h> implementation uses the same algorithms as those
+   in this file but uses only a single type "struct list_head".  There
+   are two problems with this approach.  First, there are no type
+   distinctions made between the two objects despite their distinct
+   types, which greatly increases the possibility for mistakes.  For
+   example, the <linux/list.h> list_add function takes two "struct
+   list_head" arguments: the first is the item being inserted and the
+   second is the "struct list_head" which should precede the new
+   insertion to the list.  You can use this function to insert at any
+   point in the list, but by far the most common list operations are
+   to insert at the front or back of the list.  This common case
+   should accept two different argument types: a "list head" and an
+   "item", this allows for no confusion.
+
+   The second problem with using a single "struct list_head" is that
+   it does not distinguish between list objects of distinct list
+   classes.  If a single item can belong to two separate lists, there
+   is easily the possibility of a mistake being made that causes the
+   item to be added to a "list head" using the wrong "list link".  By
+   using a parametrized list class we can statically detect such
+   mistakes, detecting mistakes as soon as they happen.
+
+   To create a new list class takes several steps which are described
+   below.  Suppose for this example that you would like to link
+   together items of type "rx_event".  You should decide on
+   prefix-name to be used on all list functions and structures.  For
+   example, the string "rx_event" can be as a prefix for all the list
+   operations, resulting in a "list head" named rx_event_list_head and
+   a "list link" named rx_event_list_link.  The list operations on
+   this list class would be named "rx_event_list_empty",
+   "rx_event_list_init", "rx_event_list_push_front",
+   "rx_event_list_push_back", and so on.
+*/
+
+#define TYPE_SAFE_LIST_LINK_INIT(name) { &(name), &(name) }
+#define TYPE_SAFE_LIST_HEAD_INIT(name) { (void *)&(name), (void *)&(name) }
+#define TYPE_SAFE_LIST_LINK_ZERO { NULL, NULL }
+#define TYPE_SAFE_LIST_HEAD_ZERO { NULL, NULL }
+
+#define TS_LINK_TO_ITEM(ITEM_TYPE,LINK_NAME,LINK) \
+	((ITEM_TYPE *)((char *)(LINK)-(unsigned long)(&((ITEM_TYPE *)0)->LINK_NAME)))
+
+/* Step 1: Use the TYPE_SAFE_LIST_DECLARE() macro to define the "list head"
+   and "list link" objects.  This macro takes one arguments, the
+   prefix-name, which is prepended to every structure and function
+   name of the list class.  Following the example, this will create
+   types named rx_event_list_head and rx_event_list_link.  In the
+   example you would write:
+
+   TYPE_SAFE_LIST_DECLARE(rx_event);
+
+*/
+#define TYPE_SAFE_LIST_DECLARE(PREFIX)				\
+								\
+typedef struct _##PREFIX##_list_head        PREFIX##_list_head;	\
+typedef struct _##PREFIX##_list_link        PREFIX##_list_link;	\
+								\
+struct _##PREFIX##_list_link					\
+{								\
+	PREFIX##_list_link *_next;				\
+	PREFIX##_list_link *_prev;				\
+};								\
+								\
+struct _##PREFIX##_list_head					\
+{								\
+	PREFIX##_list_link *_next;				\
+	PREFIX##_list_link *_prev;				\
+}
+
+/* Step 2: Once you have defined the two list classes, you should
+   define the item type you intend to use.  The list classes must be
+   declared before the item type because the item type must contain an
+   embedded "list link" object.  Following the example, you might define
+   rx_event as follows:
+
+   typedef struct _rx_event  rx_event;
+
+   struct _rx_event
+   {
+     ... other members ...
+
+     rx_event_list_link  _link;
+   };
+
+   In this case we have given the rx_event a field named "_link" of
+   the appropriate type.
+*/
+
+/* Step 3: The final step will define the list-functions for a
+   specific list class using the macro TYPE_SAFE_LIST_DEFINE.  There are
+   three arguments to the TYPE_SAFE_LIST_DEFINE macro: the prefix-name, the
+   item type name, and field name of the "list link" element within
+   the item type.  In the above example you would supply "rx_event" as
+   the type name and "_link" as the field name (without quotes).
+   E.g.,
+
+   TYPE_SAFE_LIST_DEFINE(rx_event,rx_event,_link)
+
+   The list class you define is now complete with the functions:
+
+   rx_event_list_init             Initialize a list_head
+   rx_event_list_clean            Initialize a list_link
+   rx_event_list_is_clean         True if list_link is not in a list
+   rx_event_list_push_front       Insert to the front of the list
+   rx_event_list_push_back        Insert to the back of the list
+   rx_event_list_insert_before    Insert just before given item in the list
+   rx_event_list_insert_after     Insert just after given item in the list
+   rx_event_list_remove           Remove an item from anywhere in the list
+   rx_event_list_remove_clean     Remove an item from anywhere in the list and clean link_item
+   rx_event_list_remove_get_next  Remove an item from anywhere in the list and return the next element
+   rx_event_list_remove_get_prev  Remove an item from anywhere in the list and return the prev element
+   rx_event_list_pop_front        Remove and return the front of the list, cannot be empty
+   rx_event_list_pop_back         Remove and return the back of the list, cannot be empty
+   rx_event_list_front            Get the front of the list
+   rx_event_list_back             Get the back of the list
+   rx_event_list_next             Iterate front-to-back through the list
+   rx_event_list_prev             Iterate back-to-front through the list
+   rx_event_list_end              Test to end an iteration, either direction
+   rx_event_list_splice           Join two lists at the head
+   rx_event_list_empty            True if the list is empty
+   rx_event_list_object_ok        Check that list element satisfies double
+                                  list invariants. For debugging.
+
+   To iterate over such a list use a for-loop such as:
+
+     rx_event_list_head *head = ...;
+     rx_event *item;
+
+     for (item = rx_event_list_front (head);
+               ! rx_event_list_end   (head, item);
+          item = rx_event_list_next  (item))
+       {...}
+*/
+#define TYPE_SAFE_LIST_DEFINE(PREFIX,ITEM_TYPE,LINK_NAME)					\
+												\
+static __inline__ int										\
+PREFIX##_list_link_invariant (const PREFIX##_list_link  *_link)					\
+{												\
+	return (_link != NULL) &&								\
+		(_link->_prev != NULL) && (_link->_next != NULL ) &&				\
+		(_link->_prev->_next == _link) &&						\
+		(_link->_next->_prev == _link);							\
+}												\
+												\
+static __inline__ void										\
+PREFIX##_list_link_ok (const PREFIX##_list_link  *_link UNUSED_ARG)				\
+{												\
+	BUG_ON(!PREFIX##_list_link_invariant (_link));						\
+}												\
+												\
+static __inline__ void										\
+PREFIX##_list_object_ok (const ITEM_TYPE           *item)					\
+{												\
+	PREFIX##_list_link_ok (&item->LINK_NAME);						\
+}												\
+												\
+static __inline__ void										\
+PREFIX##_list_init (PREFIX##_list_head  *head)							\
+{												\
+	head->_next = (PREFIX##_list_link*) head;						\
+	head->_prev = (PREFIX##_list_link*) head;						\
+}												\
+												\
+static __inline__ void										\
+PREFIX##_list_clean (ITEM_TYPE           *item)							\
+{												\
+	PREFIX##_list_link *_link = &item->LINK_NAME;						\
+												\
+	_link->_next = _link;									\
+	_link->_prev = _link;									\
+}												\
+												\
+static __inline__ int										\
+PREFIX##_list_is_clean (const ITEM_TYPE           *item)					\
+{												\
+	const PREFIX##_list_link *_link = &item->LINK_NAME;					\
+												\
+	PREFIX##_list_link_ok (_link);								\
+	return (_link == _link->_next) && (_link == _link->_prev);				\
+}												\
+												\
+static __inline__ void										\
+PREFIX##_list_insert_int (PREFIX##_list_link  *next,						\
+			  PREFIX##_list_link  *item)						\
+{												\
+	PREFIX##_list_link *prev = next->_prev;							\
+	PREFIX##_list_link_ok (next);								\
+	PREFIX##_list_link_ok (prev);								\
+	next->_prev = item;									\
+	item->_next = next;									\
+	item->_prev = prev;									\
+	prev->_next = item;									\
+	PREFIX##_list_link_ok (next);								\
+	PREFIX##_list_link_ok (prev);								\
+	PREFIX##_list_link_ok (item);								\
+}												\
+												\
+static __inline__ void										\
+PREFIX##_list_push_front (PREFIX##_list_head  *head,						\
+			  ITEM_TYPE           *item)						\
+{												\
+	PREFIX##_list_insert_int (head->_next, & item->LINK_NAME);				\
+}												\
+												\
+static __inline__ void										\
+PREFIX##_list_push_back (PREFIX##_list_head  *head,						\
+			 ITEM_TYPE           *item)						\
+{												\
+	PREFIX##_list_insert_int ((PREFIX##_list_link *) head, & item->LINK_NAME);		\
+}												\
+												\
+static __inline__ void										\
+PREFIX##_list_insert_before (ITEM_TYPE         *reference,					\
+			     ITEM_TYPE           *item)						\
+{												\
+	PREFIX##_list_insert_int (& reference->LINK_NAME, & item->LINK_NAME);			\
+}												\
+												\
+static __inline__ void										\
+PREFIX##_list_insert_after (ITEM_TYPE         *reference,					\
+			    ITEM_TYPE           *item)						\
+{												\
+	PREFIX##_list_insert_int (reference->LINK_NAME._next, & item->LINK_NAME);		\
+}												\
+												\
+static __inline__ PREFIX##_list_link*								\
+PREFIX##_list_remove_int (PREFIX##_list_link *list_link)					\
+{												\
+	PREFIX##_list_link *next = list_link->_next;						\
+	PREFIX##_list_link *prev = list_link->_prev;						\
+	PREFIX##_list_link_ok (list_link);							\
+	PREFIX##_list_link_ok (next);								\
+	PREFIX##_list_link_ok (prev);								\
+	next->_prev = prev;									\
+	prev->_next = next;									\
+	PREFIX##_list_link_ok (next);								\
+	PREFIX##_list_link_ok (prev);								\
+	return list_link;									\
+}												\
+												\
+static __inline__ void										\
+PREFIX##_list_remove (ITEM_TYPE  *item)								\
+{												\
+	PREFIX##_list_remove_int (& item->LINK_NAME);						\
+}												\
+												\
+static __inline__ void										\
+PREFIX##_list_remove_clean (ITEM_TYPE  *item)							\
+{												\
+	PREFIX##_list_remove_int (& item->LINK_NAME);						\
+	PREFIX##_list_clean (item);								\
+}												\
+												\
+static __inline__ ITEM_TYPE*									\
+PREFIX##_list_remove_get_next (ITEM_TYPE  *item)						\
+{												\
+	PREFIX##_list_link *next = item->LINK_NAME._next;					\
+	PREFIX##_list_remove_int (& item->LINK_NAME);						\
+	return TS_LINK_TO_ITEM(ITEM_TYPE,LINK_NAME,next);					\
+}												\
+												\
+static __inline__ ITEM_TYPE*									\
+PREFIX##_list_remove_get_prev (ITEM_TYPE  *item)						\
+{												\
+	PREFIX##_list_link *prev = item->LINK_NAME._prev;					\
+	PREFIX##_list_remove_int (& item->LINK_NAME);						\
+	return TS_LINK_TO_ITEM(ITEM_TYPE,LINK_NAME,prev);					\
+}												\
+												\
+static __inline__ int										\
+PREFIX##_list_empty (const PREFIX##_list_head  *head)						\
+{												\
+	return head == (PREFIX##_list_head*) head->_next;					\
+}												\
+												\
+static __inline__ ITEM_TYPE*									\
+PREFIX##_list_pop_front (PREFIX##_list_head  *head)						\
+{												\
+	BUG_ON(PREFIX##_list_empty (head));							\
+	return TS_LINK_TO_ITEM(ITEM_TYPE,LINK_NAME,PREFIX##_list_remove_int (head->_next));	\
+}												\
+												\
+static __inline__ ITEM_TYPE*									\
+PREFIX##_list_pop_back (PREFIX##_list_head  *head)						\
+{												\
+	BUG_ON(PREFIX##_list_empty (head)); /* WWI started */					\
+	return TS_LINK_TO_ITEM(ITEM_TYPE,LINK_NAME,PREFIX##_list_remove_int (head->_prev));	\
+}												\
+												\
+static __inline__ ITEM_TYPE*									\
+PREFIX##_list_front (const PREFIX##_list_head  *head)						\
+{												\
+	return TS_LINK_TO_ITEM(ITEM_TYPE,LINK_NAME,head->_next);				\
+}												\
+												\
+static __inline__ ITEM_TYPE*									\
+PREFIX##_list_back (const PREFIX##_list_head  *head)						\
+{												\
+	return TS_LINK_TO_ITEM(ITEM_TYPE,LINK_NAME,head->_prev);				\
+}												\
+												\
+static __inline__ ITEM_TYPE*									\
+PREFIX##_list_next (const ITEM_TYPE *item)							\
+{												\
+	return TS_LINK_TO_ITEM(ITEM_TYPE,LINK_NAME,item->LINK_NAME._next);			\
+}												\
+												\
+static __inline__ ITEM_TYPE*									\
+PREFIX##_list_prev (const ITEM_TYPE *item)							\
+{												\
+	return TS_LINK_TO_ITEM(ITEM_TYPE,LINK_NAME,item->LINK_NAME._prev);			\
+}												\
+												\
+static __inline__ int										\
+PREFIX##_list_end (const PREFIX##_list_head  *head,						\
+ 		   const ITEM_TYPE           *item)						\
+{												\
+	return ((PREFIX##_list_link *) head) == (& item->LINK_NAME);				\
+}												\
+												\
+static __inline__ void										\
+PREFIX##_list_splice (PREFIX##_list_head  *head_join,						\
+ 		      PREFIX##_list_head  *head_empty)						\
+{												\
+	if (PREFIX##_list_empty (head_empty)) {							\
+		return;										\
+	}											\
+												\
+	head_empty->_prev->_next = (PREFIX##_list_link*) head_join;				\
+	head_empty->_next->_prev = head_join->_prev;						\
+												\
+	head_join->_prev->_next  = head_empty->_next;						\
+	head_join->_prev         = head_empty->_prev;						\
+												\
+	PREFIX##_list_link_ok ((PREFIX##_list_link*) head_join);				\
+	PREFIX##_list_link_ok (head_join->_prev);						\
+	PREFIX##_list_link_ok (head_join->_next);						\
+												\
+	PREFIX##_list_init (head_empty);							\
+}												\
+												\
+static __inline__ void										\
+PREFIX##_list_split(PREFIX##_list_head  *head_split,						\
+		    PREFIX##_list_head  *head_new,						\
+		    ITEM_TYPE  *item)								\
+{												\
+	BUG_ON(!PREFIX##_list_empty(head_new));							\
+												\
+	/* attach to new list */								\
+	head_new->_next = (& item->LINK_NAME);							\
+	head_new->_prev = head_split->_prev;							\
+												\
+	/* cut from old list */									\
+	item->LINK_NAME._prev->_next = (PREFIX##_list_link*)head_split;				\
+	head_split->_prev = item->LINK_NAME._prev;						\
+												\
+	/* link new list */									\
+	head_new->_next->_prev = (PREFIX##_list_link*)head_new;					\
+	head_new->_prev->_next = (PREFIX##_list_link*)head_new;					\
+}												\
+												\
+static __inline__ void										\
+PREFIX##_list_check (const PREFIX##_list_head  *head)						\
+{												\
+	const PREFIX##_list_link *link;								\
+												\
+	for (link = head->_next ; link != ((PREFIX##_list_link *) head) ; link = link->_next)	\
+		PREFIX##_list_link_ok (link);							\
+}												\
+												\
+typedef struct { int foo; } PREFIX##_list_dummy_decl
+
+/* The final typedef is to allow a semicolon at the end of
+ * TYPE_SAFE_LIST_DEFINE(); */
+
+#define for_all_type_safe_list(prefix, head, item)		\
+	for(item = prefix ## _list_front(head),			\
+                   prefetch(prefix ## _list_next(item));	\
+	    !prefix ## _list_end(head, item) ;			\
+	    item = prefix ## _list_next(item),			\
+		    prefetch(prefix ## _list_next(item)))
+
+#define for_all_type_safe_list_safe(prefix, head, item, next)	\
+	for(item = prefix ## _list_front(head),			\
+            next = prefix ## _list_next(item);			\
+	    !prefix ## _list_end(head, item) ;			\
+	    item = next,					\
+	    next = prefix ## _list_next(item))
+
+/* _LINUX_TYPE_SAFE_LIST_H */
+#endif
+
+/*
+   Local variables:
+   c-indentation-style: "K&R"
+   mode-name: "LC"
+   c-basic-offset: 8
+   tab-width: 8
+   fill-column: 120
+   End:
+*/

_

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]
  Powered by Linux