public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
From: Daniel Santos <danielfsantos@att.net>
To: linux-kernel@vger.kernel.org
Cc: Kent Overstreet <koverstreet@google.com>,
	tj@kernel.org, Peter Zijlstra <peterz@infradead.org>,
	axboe@kernel.dk, paul.gortmaker@windriver.com,
	Andi Kleen <andi@firstfloor.org>,
	jack@suse.cz, Andrea Arcangeli <aarcange@redhat.com>,
	John Stultz <john.stultz@linaro.org>
Subject: [PATCH v2 2/3] [RFC] Generic Red-Black Trees
Date: Thu, 31 May 2012 18:26:39 -0500	[thread overview]
Message-ID: <4FC7FE2F.6010600@att.net> (raw)
In-Reply-To: <4FC7FD23.6080800@att.net>

[-- Attachment #1: Type: text/plain, Size: 1 bytes --]



[-- Attachment #2: 0007-Generic-search-insert-for-Red-Black-Trees.patch --]
[-- Type: text/x-patch, Size: 19958 bytes --]

>From 5d71e7b4bc2b43f40568e0493b65332218dce0ba Mon Sep 17 00:00:00 2001
From: Daniel Santos <daniel.santos@pobox.com>
Date: Thu, 31 May 2012 17:43:24 -0500
Subject: Generic search & insert for Red-Black Trees

---
 include/linux/rbtree.h |  623 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 623 insertions(+), 0 deletions(-)

diff --git a/include/linux/rbtree.h b/include/linux/rbtree.h
index 033b507..1133682 100644
--- a/include/linux/rbtree.h
+++ b/include/linux/rbtree.h
@@ -96,6 +96,8 @@ static inline struct page * rb_insert_page_cache(struct inode * inode,
 
 #include <linux/kernel.h>
 #include <linux/stddef.h>
+#include <linux/typecheck.h>
+#include <linux/bug.h>
 
 struct rb_node
 {
@@ -148,6 +150,7 @@ extern void rb_insert_color(struct rb_node *, struct rb_root *);
 extern void rb_erase(struct rb_node *, struct rb_root *);
 
 typedef void (*rb_augment_f)(struct rb_node *node, void *data);
+typedef long (*rb_compare_f)(const void *a, const void *b);
 
 extern void rb_augment_insert(struct rb_node *node,
 			      rb_augment_f func, void *data);
@@ -174,4 +177,624 @@ static inline void rb_link_node(struct rb_node * node, struct rb_node * parent,
 	*rb_link = node;
 }
 
+
+#define __JUNK junk,
+#define _iff_empty(test_or_junk, t, f) __iff_empty(test_or_junk, t, f)
+#define __iff_empty(__ignored1, __ignored2, result, ...) result
+
+/**
+ * IFF_EMPTY() - Expands to the second argument when the first is empty, the
+ *               third if non-empty.
+ * @test:        An argument to test for emptiness.
+ * @t:           A value to expand to if test is empty.
+ * @f:           A value to expand to if test is non-empty.
+ *
+ * Caveats:
+ * IFF_EMPTY isn't perfect.  The test parmater must either be empty or a valid
+ * pre-processor token as well as result in a valid token when pasted to the
+ * end of a word.
+ *
+ * Valid Examples:
+ * IFF_EMPTY(a, b, c) = c
+ * IFF_EMPTY( , b, c) = b
+ * IFF_EMPTY( ,  , c) = (nothing)
+ *
+ * Invalid Examples:
+ * IFF_EMPTY(.,  b, c)
+ * IFF_EMPTY(+,  b, c)
+ */
+#define IFF_EMPTY(test, t, f) _iff_empty(__JUNK##test, t, f)
+
+/**
+ * IS_EMPTY() - test if a pre-processor argument is empty.
+ * @arg:        An argument (empty or non-empty)
+ *
+ * If empty, expands to 1, 0 otherwise.  See IFF_EMPTY() for caveats &
+ * limitations.
+ */
+#define IS_EMPTY(arg)	IFF_EMPTY(arg, 1, 0)
+
+/**
+ * OPT_OFFSETOF() - return the offsetof for the supplied expression, or zero
+ *                  if m is an empty argument.
+ * @type:           struct/union type
+ * @m:              (optional) struct member name
+ *
+ * Since any offsetof can return zero if the specified member is the first in
+ * the struct/union, you should also check if the argument is empty separately
+ * with IS_EMPTY(m).
+ */
+#define OPT_OFFSETOF(type, m) ((size_t) &((*((type *)0)) IFF_EMPTY(m, , .m)))
+
+
+enum rb_flags {
+	RB_HAS_LEFTMOST	   = 0x00000001,
+	RB_HAS_RIGHTMOST   = 0x00000002,
+	RB_UNIQUE_KEYS	   = 0x00000004,
+	RB_INSERT_REPLACES = 0x00000008,
+	RB_ALL_FLAGS	   = RB_HAS_LEFTMOST | RB_HAS_RIGHTMOST
+			   | RB_UNIQUE_KEYS | RB_INSERT_REPLACES,
+};
+
+/**
+ * struct rb_relationship - Defines relationship between a container and
+ *                      the objects it contains.
+ * @root_offset:        Offset of container's struct rb_root member.
+ * @left_offset:        (Used only if has_left.) Offset of the container's
+ *                      struct rb_node *leftmost member for storing a pointer
+ *                      to the leftmost node in the tree, which is kept
+ *                      updated as inserts and deletions are made.
+ * @right_offset:       Same as left_offset, except for right side of tree.
+ * @node_offset:        Offset of object's struct rb_node member.
+ * @key_offset:         Offset of object's key member.
+ * @flags:              TODO
+ *
+ * Instances of struct rb_relationship should be compile-time constants (or
+ * rather, the value of its members).
+ */
+struct rb_relationship {
+	long root_offset;
+	long left_offset;
+	long right_offset;
+	long node_offset;
+	long key_offset;
+	int flags;
+};
+
+static __always_inline
+struct rb_root *__rb_to_root(const void *ptr, const struct rb_relationship *rel)
+{
+	BUILD_BUG_ON_NON_CONST2(rel->root_offset);
+	return (struct rb_root *)((char *)ptr + rel->root_offset);
+}
+
+static __always_inline
+struct rb_node **__rb_root_to_left(void *ptr, const struct rb_relationship *rel)
+{
+	BUILD_BUG_ON(!(rel->flags & RB_HAS_LEFTMOST));
+	BUILD_BUG_ON_NON_CONST2(rel->root_offset);
+	BUILD_BUG_ON_NON_CONST2(rel->left_offset);
+	return (struct rb_node **)((char *)ptr - rel->root_offset
+					       + rel->left_offset);
+}
+
+static __always_inline
+struct rb_node **__rb_root_to_right(void *ptr, const struct rb_relationship *rel)
+{
+	BUILD_BUG_ON(!(rel->flags & RB_HAS_RIGHTMOST));
+	BUILD_BUG_ON_NON_CONST2(rel->root_offset);
+	BUILD_BUG_ON_NON_CONST2(rel->right_offset);
+	return (struct rb_node **)((char *)ptr - rel->root_offset
+					       + rel->right_offset);
+}
+
+static __always_inline
+const void *__rb_node_to_key(const void *ptr, const struct rb_relationship *rel)
+{
+	BUILD_BUG_ON_NON_CONST2(rel->node_offset);
+	BUILD_BUG_ON_NON_CONST2(rel->key_offset);
+	return (const void *)((const char *)ptr - rel->node_offset
+						+ rel->key_offset);
+}
+
+static __always_inline
+char *__rb_node_to_obj(const void *ptr, const struct rb_relationship *rel)
+{
+	BUILD_BUG_ON_NON_CONST2(rel->node_offset);
+	return (char *)ptr - rel->node_offset;
+}
+
+/* not used anymore */
+#if 0
+static __always_inline
+struct rb_node *__rb_to_node(const void *ptr, const struct rb_relationship *rel)
+{
+	BUILD_BUG_ON_NON_CONST2(rel->node_offset);
+	return (struct rb_node *)((char *)ptr + rel->node_offset);
+}
+
+static __always_inline
+const void *__rb_to_key(const void *ptr, const struct rb_relationship *rel)
+{
+	BUILD_BUG_ON_NON_CONST2(rel->key_offset);
+	return (const void *)((const char *)ptr + rel->key_offset);
+}
+
+#endif
+
+/** __rb_find -
+ *
+ */
+static __always_inline
+struct rb_node *__rb_find(
+		struct rb_node *node,
+		const void *key,
+		const struct rb_relationship *rel,
+		const rb_compare_f compare)
+{
+	while (node) {
+		long diff = compare(key, __rb_node_to_key(node, rel));
+
+		if (diff > 0)
+			node = node->rb_right;
+		else if (diff < 0)
+			node = node->rb_left;
+		else
+			return node;
+	}
+
+	return 0;
+}
+
+
+static __always_inline
+struct rb_node *rb_find(
+	struct rb_root *root,
+	const void *key,
+	const struct rb_relationship *rel,
+	const rb_compare_f compare)
+{
+	return __rb_find(root->rb_node, key, rel, compare);
+}
+
+enum rb_find_subtree_match {
+	RB_MATCH_NONE		= 0,
+	RB_MATCH_IMMEDIATE	= 2,
+	RB_MATCH_LEFT		= -1,
+	RB_MATCH_RIGHT		= 1,
+};
+
+
+/**
+ * rb_find_subtree - Locate the subtree that contains the specified key (if it
+ * 		     exists) starting from a specific node traversing upwards.
+ *
+ */
+static __always_inline
+struct rb_node *__rb_find_subtree(
+		struct rb_node *from,
+		const void *key,
+		int *matched,
+		const struct rb_relationship *rel,
+		const rb_compare_f compare)
+{
+	struct rb_node *prev = from;
+	struct rb_node *node = rb_parent(from);
+	long diff;
+
+	if (!node) {
+		*matched = RB_MATCH_NONE;
+		return prev;
+	}
+
+	diff = compare(key, __rb_node_to_key(node, rel));
+
+	if (diff > 0) {
+		while (1) {
+			prev = node;
+			node = rb_parent(prev);
+			if (!node)
+				break;
+
+			diff = compare(key, __rb_node_to_key(node, rel));
+			if (diff < 0)
+				break;
+			else if (!diff) {
+				*matched = RB_MATCH_LEFT;
+				return node;
+			}
+		}
+		*matched = RB_MATCH_NONE;
+		return prev->rb_left;
+	} else if (diff < 0) {
+		while (1) {
+			prev = node;
+			node = rb_parent(prev);
+			if (!node)
+				break;
+
+			diff = compare(key, __rb_node_to_key(node, rel));
+			if (diff > 0)
+				break;
+			else if (!diff) {
+				*matched = RB_MATCH_RIGHT;
+				return node;
+			}
+		}
+		*matched = RB_MATCH_NONE;
+		return prev->rb_right;
+	}
+
+	*matched = RB_MATCH_IMMEDIATE;
+	return node;
+}
+
+static __always_inline
+struct rb_node *rb_find_near(
+	struct rb_node *from,
+	const void *key,
+	const struct rb_relationship *rel,
+	const rb_compare_f compare)
+{
+	int matched;
+	struct rb_node *subtree;
+
+	subtree = __rb_find_subtree(from, key, &matched, rel, compare);
+
+	if (matched) {
+		return subtree;
+	}
+
+	return __rb_find(subtree, key, rel, compare);
+}
+
+static __always_inline
+struct rb_node *__rb_insert_epilogue(
+	struct rb_root *root,
+	struct rb_node *parent,
+	struct rb_node *node,
+	struct rb_node *found,
+	struct rb_node **rb_link,
+	const struct rb_relationship *rel,
+	const rb_augment_f augmented) {
+
+	if ((rel->flags & RB_UNIQUE_KEYS) && found) {
+		/* if replacing, we will still need to call do augmented */
+		if (rel->flags & RB_INSERT_REPLACES)
+			rb_replace_node(found, node, root);
+		/* otherwise, we can bail */
+		else
+			goto exit;
+	} else {
+		rb_link_node(node, parent, rb_link);
+		rb_insert_color(node, root);
+	}
+
+	if (augmented)	/* TODO: check verify which versions of gcc compile this out */
+		rb_augment_insert(node, augmented, NULL);
+
+exit:
+	return found;
+}
+
+
+/**
+ * rb_insert() - Inserts an object into a container.
+ * @container:  Pointer to the container.
+ * @obj:        Pointer to the new object to insert.
+ * @rel:        Pointer to the compile-time constant relationship definition.
+ *
+ * If an object with the same key already exists and rel->ins_replace is non-zero,
+ * then it is replaced with obj; if rel->ins_replace is zero, then no change is made.
+ * In either case, a pointer to the existing object is returned. Note that
+ * return values are pointers to the objects themselves, not to the struct
+ * rb_node.
+ *
+ * If no object with the same key exists, then obj is inserted and NULL is
+ * returned.
+ *
+ * See rb_find for example.
+ */
+static __always_inline
+struct rb_node *rb_insert(
+	struct rb_root *root,
+	struct rb_node *node,
+	const struct rb_relationship *rel,
+	const rb_compare_f compare,
+	const rb_augment_f augmented)
+{
+	struct rb_node **p     = &root->rb_node;
+	struct rb_node *parent = NULL;
+	const void *key        = __rb_node_to_key(node, rel);
+	int leftmost           = 1;
+	int rightmost          = 1;
+
+	BUILD_BUG_ON_NON_CONST2(rel->flags);
+	BUG_ON((rel->flags & RB_INSERT_REPLACES)
+		 && !(rel->flags & RB_UNIQUE_KEYS));
+
+	while (*p) {
+		long diff = compare(key, __rb_node_to_key(*p, rel));
+		parent    = *p;
+
+		if (diff > 0) {
+			p = &(*p)->rb_right;
+			if (rel->flags & RB_HAS_LEFTMOST)
+				leftmost = 0;
+		} else if (!(rel->flags & RB_UNIQUE_KEYS) || diff < 0) {
+			p = &(*p)->rb_left;
+			if (rel->flags & RB_HAS_RIGHTMOST)
+				rightmost = 0;
+		} else
+			break;
+	}
+
+	if ((rel->flags & RB_HAS_LEFTMOST) && leftmost) {
+		struct rb_node **left = __rb_root_to_left(root, rel);
+
+		if (!(rel->flags & RB_INSERT_REPLACES) || !(*p) || *left == *p)
+			*left = node;
+	}
+	if ((rel->flags & RB_HAS_RIGHTMOST) && rightmost) {
+		struct rb_node **right = __rb_root_to_right(root, rel);
+
+		if (!(rel->flags & RB_INSERT_REPLACES) || !(*p) || *right == *p)
+			*right = node;
+	}
+
+	return __rb_insert_epilogue(root, parent, node, *p, p, rel, augmented);
+}
+
+static __always_inline
+struct rb_node *rb_insert_near(
+		struct rb_root *root,
+		struct rb_node *start,
+		struct rb_node *node,
+		const struct rb_relationship *rel,
+		const rb_compare_f compare,
+		const rb_augment_f augmented)
+{
+
+	return 0;
+/* TODO: not yet finished */
+#if 0
+	const void *key        = __rb_node_to_key(node, rel);
+	struct rb_node **p     = &start;
+	struct rb_node *parent = NULL;
+	struct rb_node *ret;
+	int matched;
+	long diff;
+
+	BUILD_BUG_ON_NON_CONST2(rel->flags);
+
+	ret = __rb_find_subtree(start, key, &matched, rel, compare);
+
+	if (!matched) {
+		while (*p) {
+			diff   = compare(__rb_node_to_key(*p, rel), key);
+			parent = *p;
+
+			if (diff > 0) {
+				p = &(*p)->rb_right;
+			} else if (!(rel->flags & RB_UNIQUE_KEYS) || diff < 0) {
+				p = &(*p)->rb_left;
+			} else
+				break;
+		}
+		ret = *p;
+	} else {
+		/* FIXME: p will not be correctly set to point to the parent's
+		 * rb_left or rb_right member here when it's passed as
+		 * __rb_insert_epilogue()'s rb_link parameter.
+		 */
+		if (rel->flags & (RB_HAS_LEFTMOST | RB_HAS_RIGHTMOST)) {
+			if ((rel->flags & RB_HAS_LEFTMOST)) {
+				struct rb_node **left = __rb_root_to_left(root, rel);
+				if (*left == ret) {
+					*left = node;
+				}
+			}
+
+			if ((rel->flags & RB_HAS_RIGHTMOST)) {
+				struct rb_node **right = __rb_root_to_right(root, rel);
+				if (*right == ret) {
+					*right = node;
+				}
+			}
+		}
+	}
+
+	if (rel->flags & RB_HAS_LEFTMOST | RB_HAS_RIGHTMOST) {
+
+	}
+
+	if ((rel->flags & RB_HAS_LEFTMOST)) {
+		struct rb_node **left = __rb_root_to_left(root, rel);
+		if (!*left || (*left == parent && diff < 0)) {
+			*left = node;
+		}
+	}
+
+	if ((rel->flags & RB_HAS_RIGHTMOST)) {
+		struct rb_node **right = __rb_root_to_right(root, rel);
+		if ((*right == parent && diff > 0) || !*right) {
+			*right = node;
+		}
+	}
+
+	return __rb_insert_epilogue(root, parent, node, ret, p, rel, augmented);
+#endif
+}
+
+static __always_inline
+void rb_remove(
+	struct rb_root *root,
+	struct rb_node *node,
+	const struct rb_relationship *rel,
+	const rb_augment_f augmented)
+{
+	struct rb_node *deepest = NULL;
+
+	BUILD_BUG_ON_NON_CONST2(rel->flags);
+
+	if (augmented)
+		deepest = rb_augment_erase_begin(node);
+
+	if (rel->flags & RB_HAS_LEFTMOST) {
+		struct rb_node **left = __rb_root_to_left(root, rel);
+
+		if (*left == node)
+			*left = rb_next(node);
+	}
+
+	if (rel->flags & RB_HAS_RIGHTMOST) {
+		struct rb_node **right = __rb_root_to_right(root, rel);
+
+		if (*right == node)
+			*right = rb_prev(node);
+	}
+
+	rb_erase(node, root);
+
+	if (augmented)
+		rb_augment_erase_end(deepest, augmented, NULL);
+}
+
+
+/**
+ * RB_RELATIONHIP - Define the relationship bewteen a container with a
+ *                  struct rb_root member, and the objects it contains.
+ * @cont_type: container type
+ * @root:      container's struct rb_root member name
+ * @left:      (optional) if the container needs a pointer to the tree's
+ *             leftmost (smallest) object, then specify the container's struct
+ *             rb_node *leftmost member.  Otherwise, leave this parameter
+ *             empty.
+ * @right:     (optional) same as left, but for the rightmost (largest)
+ * @obj_type:  the type of object stored in container
+ * @node:      the struct rb_node memeber of the object
+ * @key:       the key member of the object
+ * @flags      see rb_flags.  Note: you do not have to specify RB_HAS_LEFTMOST
+ *             or RB_HAS_RIGHTMOST as these will be added automatically if the
+ *             left or right parameter (respectively) is non-empty
+ */
+#define RB_RELATIONHIP(							\
+		cont_type, root, left, right,				\
+		obj_type, node, key,					\
+		_flags) {						\
+	.root_offset     = offsetof(cont_type, root),			\
+	.left_offset     = OPT_OFFSETOF(cont_type, left),		\
+	.right_offset    = OPT_OFFSETOF(cont_type, right),		\
+	.node_offset     = offsetof(obj_type, node),			\
+	.key_offset      = offsetof(obj_type, key),			\
+	.flags           = (_flags)					\
+			 | IFF_EMPTY(left , 0, RB_HAS_LEFTMOST)		\
+			 | IFF_EMPTY(right, 0, RB_HAS_RIGHTMOST),	\
+}
+
+/**
+ * RB_DEFINE_INTERFACE - Defines a complete interface for a relationship
+ *                       between container and object including a struct
+ *                       rb_relationship and an interface of type-safe wrapper
+ *                       functions.
+ * @prefix:    name for the relationship (see explanation below)
+ * @cont_type: container type
+ * @root:      container's struct rb_root member name
+ * @left:      (optional) if the container needs a pointer to the tree's
+ *             leftmost (smallest) object, then specify the container's struct
+ *             rb_node *leftmost member.  Otherwise, leave this parameter
+ *             empty.
+ * @right:     (optional) same as left, but for the rightmost (largest)
+ * @obj_type:  the type of object stored in container
+ * @node:      the struct rb_node memeber of the object
+ * @key:       the key member of the object
+ * @flags      see rb_flags.  Note: you do not have to specify RB_HAS_LEFTMOST
+ *             or RB_HAS_RIGHTMOST as these will be added automatically if the
+ *             left or right parameter (respectively) is non-empty
+ * @compare:   pointer to key rb_compare_f function to compare keys.  Function
+ *             will be cast to and called as type long (*)(const void *a, const
+ *             void *b), hence type-safety is lost (FIXME: can this be improved
+ *             at all?).
+ * @augmented: pointer to the rb_augment_f or zero if tree is not augmented.
+ *
+ * This macro can be delcared in the global scope of either a source or header
+ * file and will generate a static const struct rb_relationship variable named
+ * prefix##_rel as well as similarly named (i.e., prefix##_##func_name)
+ * type-safe wrapper functions for find, find_near, insert, insert_near and
+ * remove.  If these function names are not sufficient, you can use the
+ * __RB_DEFINE_INTERFACE macro to specify them explicitly.
+ *
+ * The compare function will be passed pointers to the key members of two
+ * objects.  If your compare function needs access to other members of your
+ * struct (e.g., compound keys, etc.) , you can use the rb_entry macro to
+ * access other members.  However, if you use this mechanism, your find
+ * function must always pass it's key parameter as a pointer to the key member
+ * of an object of type obj_type, since the compare function is used for both
+ * inserts and lookups.
+ */
+#define RB_DEFINE_INTERFACE(prefix, ...)\
+__RB_DEFINE_INTERFACE(			\
+	prefix ## _rel,			\
+	prefix ## _insert,		\
+	prefix ## _insert_near,		\
+	prefix ## _find,		\
+	prefix ## _find_near,		\
+	prefix ## _remove,		\
+	__VA_ARGS__)
+
+
+#define __RB_DEFINE_INTERFACE(						\
+	rel_var, insert, insert_near, find, find_near, remove,		\
+	cont_type, root, left, right,					\
+	obj_type, node, key,						\
+	flags, compare, augmented)					\
+static const struct rb_relationship rel_var = RB_RELATIONHIP(		\
+	cont_type, root, left, right,					\
+	obj_type, node, key,						\
+	flags);								\
+									\
+static __always_inline							\
+obj_type *insert(cont_type *cont, obj_type *obj)			\
+{									\
+	struct rb_node *ret = rb_insert(				\
+			&cont->root, &obj->node, &rel_var,		\
+			(const rb_compare_f)compare, augmented);	\
+	return ret ? rb_entry(ret, obj_type, node) : 0;			\
+}									\
+									\
+static __always_inline							\
+obj_type *insert_near(cont_type *cont, obj_type *near, obj_type *obj)	\
+{									\
+	struct rb_node *ret = rb_insert_near(				\
+			&cont->root, &near->node, &obj->node, &rel_var,	\
+			(const rb_compare_f)compare, augmented);	\
+	return ret ? rb_entry(ret, obj_type, node) : 0;			\
+}									\
+									\
+static __always_inline							\
+obj_type *find(cont_type *cont,						\
+	       const typeof(((obj_type *)0)->key) *_key)		\
+{									\
+	struct rb_node *ret = rb_find(					\
+			&cont->root, _key, &rel_var,			\
+			(const rb_compare_f)compare);			\
+	return ret ? rb_entry(ret, obj_type, node) : 0;			\
+}									\
+									\
+static __always_inline							\
+obj_type *find_near(obj_type *near,					\
+		    const typeof(((obj_type *)0)->key) *_key)		\
+{									\
+	struct rb_node *ret = rb_find_near(				\
+			&near->node, _key, &rel_var,			\
+			(const rb_compare_f)compare);			\
+	return ret ? rb_entry(ret, obj_type, node) : 0;			\
+}									\
+									\
+static __always_inline							\
+void remove(cont_type *cont, obj_type *obj)				\
+{									\
+	rb_remove(&cont->root, &obj->node, &rel_var, augmented);	\
+}									\
+
 #endif	/* _LINUX_RBTREE_H */
-- 
1.7.3.4


  reply	other threads:[~2012-05-31 23:26 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-05-31 23:22 [PATCH v2 1/3] [RFC] Generic Red-Black Trees Daniel Santos
2012-05-31 23:26 ` Daniel Santos [this message]
2012-05-31 23:30   ` [PATCH v2 3/3] " Daniel Santos
2012-06-01  1:08 ` [PATCH v2 1/3] " Daniel Santos
2012-06-01 17:56   ` [PATCH v2 1/3] [RFC] Generic Red-Black Trees (performance notes) Daniel Santos

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4FC7FE2F.6010600@att.net \
    --to=danielfsantos@att.net \
    --cc=aarcange@redhat.com \
    --cc=andi@firstfloor.org \
    --cc=axboe@kernel.dk \
    --cc=daniel.santos@pobox.com \
    --cc=jack@suse.cz \
    --cc=john.stultz@linaro.org \
    --cc=koverstreet@google.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=paul.gortmaker@windriver.com \
    --cc=peterz@infradead.org \
    --cc=tj@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox