@@ -14,7 +14,6 @@ rdma_library(ibnetdisc libibnetdisc.map
target_link_libraries(ibnetdisc LINK_PRIVATE
ibmad
ibumad
- osmcomp
)
# FIXME for osmcomp
target_include_directories(ibnetdisc PRIVATE "/usr/include/infiniband")
@@ -46,7 +46,6 @@
#include <infiniband/mad.h>
#include <infiniband/ibnetdisc.h>
-#include <complib/cl_nodenamemap.h>
#include "internal.h"
#include "chassis.h"
@@ -39,7 +39,7 @@
#define _INTERNAL_H_
#include <infiniband/ibnetdisc.h>
-#include <complib/cl_qmap.h>
+#include <util/cl_qmap.h>
#define IBND_DEBUG(fmt, ...) \
if (ibdebug) { \
@@ -44,7 +44,6 @@
#include <errno.h>
#include <inttypes.h>
-#include <infiniband/complib/cl_nodenamemap.h>
#include <infiniband/ibnetdisc.h>
static const char *argv0 = "iblinkinfotest";
@@ -1,10 +1,12 @@
publish_internal_headers(util
+ cl_qmap.h
compiler.h
symver.h
util.h
)
set(C_FILES
+ cl_map.c
util.c)
if (HAVE_COHERENT_DMA)
new file mode 100644
@@ -0,0 +1,700 @@
+/*
+ * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved.
+ * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved.
+ * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+/*
+ * Abstract:
+ * Implementation of quick map, a binary tree where the caller always
+ * provides all necessary storage.
+ *
+ */
+
+/*****************************************************************************
+*
+* Map
+*
+* Map is an associative array. By providing a key, the caller can retrieve
+* an object from the map. All objects in the map have an associated key,
+* as specified by the caller when the object was inserted into the map.
+* In addition to random access, the caller can traverse the map much like
+* a linked list, either forwards from the first object or backwards from
+* the last object. The objects in the map are always traversed in
+* order since the nodes are stored sorted.
+*
+* This implementation of Map uses a red black tree verified against
+* Cormen-Leiserson-Rivest text, McGraw-Hill Edition, fourteenth
+* printing, 1994.
+*
+*****************************************************************************/
+
+#include <util/cl_qmap.h>
+#include <string.h>
+
+static inline void __cl_primitive_insert(cl_list_item_t *const p_list_item,
+ cl_list_item_t *const p_new_item)
+{
+ /* CL_ASSERT that a non-null pointer is provided. */
+ assert(p_list_item);
+ /* CL_ASSERT that a non-null pointer is provided. */
+ assert(p_new_item);
+
+ p_new_item->p_next = p_list_item;
+ p_new_item->p_prev = p_list_item->p_prev;
+ p_list_item->p_prev = p_new_item;
+ p_new_item->p_prev->p_next = p_new_item;
+}
+
+static inline void __cl_primitive_remove(cl_list_item_t *const p_list_item)
+{
+ /* CL_ASSERT that a non-null pointer is provided. */
+ assert(p_list_item);
+
+ /* set the back pointer */
+ p_list_item->p_next->p_prev = p_list_item->p_prev;
+ /* set the next pointer */
+ p_list_item->p_prev->p_next = p_list_item->p_next;
+
+ /* if we're debugging, spruce up the pointers to help find bugs */
+#if defined( _DEBUG_ )
+ if (p_list_item != p_list_item->p_next) {
+ p_list_item->p_next = NULL;
+ p_list_item->p_prev = NULL;
+ }
+#endif /* defined( _DEBUG_ ) */
+}
+
+/******************************************************************************
+ IMPLEMENTATION OF QUICK MAP
+******************************************************************************/
+
+/*
+ * Get the root.
+ */
+static inline cl_map_item_t *__cl_map_root(const cl_qmap_t * const p_map)
+{
+ assert(p_map);
+ return (p_map->root.p_left);
+}
+
+/*
+ * Returns whether a given item is on the left of its parent.
+ */
+static bool __cl_map_is_left_child(const cl_map_item_t * const p_item)
+{
+ assert(p_item);
+ assert(p_item->p_up);
+ assert(p_item->p_up != p_item);
+
+ return (p_item->p_up->p_left == p_item);
+}
+
+/*
+ * Retrieve the pointer to the parent's pointer to an item.
+ */
+static cl_map_item_t **__cl_map_get_parent_ptr_to_item(cl_map_item_t *
+ const p_item)
+{
+ assert(p_item);
+ assert(p_item->p_up);
+ assert(p_item->p_up != p_item);
+
+ if (__cl_map_is_left_child(p_item))
+ return (&p_item->p_up->p_left);
+
+ assert(p_item->p_up->p_right == p_item);
+ return (&p_item->p_up->p_right);
+}
+
+/*
+ * Rotate a node to the left. This rotation affects the least number of links
+ * between nodes and brings the level of C up by one while increasing the depth
+ * of A one. Note that the links to/from W, X, Y, and Z are not affected.
+ *
+ * R R
+ * | |
+ * A C
+ * / \ / \
+ * W C A Z
+ * / \ / \
+ * B Z W B
+ * / \ / \
+ * X Y X Y
+ */
+static void __cl_map_rot_left(cl_qmap_t * const p_map,
+ cl_map_item_t * const p_item)
+{
+ cl_map_item_t **pp_root;
+
+ assert(p_map);
+ assert(p_item);
+ assert(p_item->p_right != &p_map->nil);
+
+ pp_root = __cl_map_get_parent_ptr_to_item(p_item);
+
+ /* Point R to C instead of A. */
+ *pp_root = p_item->p_right;
+ /* Set C's parent to R. */
+ (*pp_root)->p_up = p_item->p_up;
+
+ /* Set A's right to B */
+ p_item->p_right = (*pp_root)->p_left;
+ /*
+ * Set B's parent to A. We trap for B being NIL since the
+ * caller may depend on NIL not changing.
+ */
+ if ((*pp_root)->p_left != &p_map->nil)
+ (*pp_root)->p_left->p_up = p_item;
+
+ /* Set C's left to A. */
+ (*pp_root)->p_left = p_item;
+ /* Set A's parent to C. */
+ p_item->p_up = *pp_root;
+}
+
+/*
+ * Rotate a node to the right. This rotation affects the least number of links
+ * between nodes and brings the level of A up by one while increasing the depth
+ * of C one. Note that the links to/from W, X, Y, and Z are not affected.
+ *
+ * R R
+ * | |
+ * C A
+ * / \ / \
+ * A Z W C
+ * / \ / \
+ * W B B Z
+ * / \ / \
+ * X Y X Y
+ */
+static void __cl_map_rot_right(cl_qmap_t * const p_map,
+ cl_map_item_t * const p_item)
+{
+ cl_map_item_t **pp_root;
+
+ assert(p_map);
+ assert(p_item);
+ assert(p_item->p_left != &p_map->nil);
+
+ /* Point R to A instead of C. */
+ pp_root = __cl_map_get_parent_ptr_to_item(p_item);
+ (*pp_root) = p_item->p_left;
+ /* Set A's parent to R. */
+ (*pp_root)->p_up = p_item->p_up;
+
+ /* Set C's left to B */
+ p_item->p_left = (*pp_root)->p_right;
+ /*
+ * Set B's parent to C. We trap for B being NIL since the
+ * caller may depend on NIL not changing.
+ */
+ if ((*pp_root)->p_right != &p_map->nil)
+ (*pp_root)->p_right->p_up = p_item;
+
+ /* Set A's right to C. */
+ (*pp_root)->p_right = p_item;
+ /* Set C's parent to A. */
+ p_item->p_up = *pp_root;
+}
+
+void cl_qmap_init(cl_qmap_t * const p_map)
+{
+ assert(p_map);
+
+ memset(p_map, 0, sizeof(cl_qmap_t));
+
+ /* special setup for the root node */
+ p_map->root.p_up = &p_map->root;
+ p_map->root.p_left = &p_map->nil;
+ p_map->root.p_right = &p_map->nil;
+ p_map->root.color = CL_MAP_BLACK;
+
+ /* Setup the node used as terminator for all leaves. */
+ p_map->nil.p_up = &p_map->nil;
+ p_map->nil.p_left = &p_map->nil;
+ p_map->nil.p_right = &p_map->nil;
+ p_map->nil.color = CL_MAP_BLACK;
+
+ cl_qmap_remove_all(p_map);
+}
+
+cl_map_item_t *cl_qmap_get(const cl_qmap_t * const p_map,
+ const uint64_t key)
+{
+ cl_map_item_t *p_item;
+
+ assert(p_map);
+
+ p_item = __cl_map_root(p_map);
+
+ while (p_item != &p_map->nil) {
+ if (key == p_item->key)
+ break; /* just right */
+
+ if (key < p_item->key)
+ p_item = p_item->p_left; /* too small */
+ else
+ p_item = p_item->p_right; /* too big */
+ }
+
+ return (p_item);
+}
+
+cl_map_item_t *cl_qmap_get_next(const cl_qmap_t * const p_map,
+ const uint64_t key)
+{
+ cl_map_item_t *p_item;
+ cl_map_item_t *p_item_found;
+
+ assert(p_map);
+
+ p_item = __cl_map_root(p_map);
+ p_item_found = (cl_map_item_t *) & p_map->nil;
+
+ while (p_item != &p_map->nil) {
+ if (key < p_item->key) {
+ p_item_found = p_item;
+ p_item = p_item->p_left;
+ } else {
+ p_item = p_item->p_right;
+ }
+ }
+
+ return (p_item_found);
+}
+
+void cl_qmap_apply_func(const cl_qmap_t * const p_map,
+ cl_pfn_qmap_apply_t pfn_func,
+ const void *const context)
+{
+ cl_map_item_t *p_map_item;
+
+ /* Note that context can have any arbitrary value. */
+ assert(p_map);
+ assert(pfn_func);
+
+ p_map_item = cl_qmap_head(p_map);
+ while (p_map_item != cl_qmap_end(p_map)) {
+ pfn_func(p_map_item, (void *)context);
+ p_map_item = cl_qmap_next(p_map_item);
+ }
+}
+
+/*
+ * Balance a tree starting at a given item back to the root.
+ */
+static void __cl_map_ins_bal(cl_qmap_t * const p_map,
+ cl_map_item_t * p_item)
+{
+ cl_map_item_t *p_grand_uncle;
+
+ assert(p_map);
+ assert(p_item);
+ assert(p_item != &p_map->root);
+
+ while (p_item->p_up->color == CL_MAP_RED) {
+ if (__cl_map_is_left_child(p_item->p_up)) {
+ p_grand_uncle = p_item->p_up->p_up->p_right;
+ assert(p_grand_uncle);
+ if (p_grand_uncle->color == CL_MAP_RED) {
+ p_grand_uncle->color = CL_MAP_BLACK;
+ p_item->p_up->color = CL_MAP_BLACK;
+ p_item->p_up->p_up->color = CL_MAP_RED;
+ p_item = p_item->p_up->p_up;
+ continue;
+ }
+
+ if (!__cl_map_is_left_child(p_item)) {
+ p_item = p_item->p_up;
+ __cl_map_rot_left(p_map, p_item);
+ }
+ p_item->p_up->color = CL_MAP_BLACK;
+ p_item->p_up->p_up->color = CL_MAP_RED;
+ __cl_map_rot_right(p_map, p_item->p_up->p_up);
+ } else {
+ p_grand_uncle = p_item->p_up->p_up->p_left;
+ assert(p_grand_uncle);
+ if (p_grand_uncle->color == CL_MAP_RED) {
+ p_grand_uncle->color = CL_MAP_BLACK;
+ p_item->p_up->color = CL_MAP_BLACK;
+ p_item->p_up->p_up->color = CL_MAP_RED;
+ p_item = p_item->p_up->p_up;
+ continue;
+ }
+
+ if (__cl_map_is_left_child(p_item)) {
+ p_item = p_item->p_up;
+ __cl_map_rot_right(p_map, p_item);
+ }
+ p_item->p_up->color = CL_MAP_BLACK;
+ p_item->p_up->p_up->color = CL_MAP_RED;
+ __cl_map_rot_left(p_map, p_item->p_up->p_up);
+ }
+ }
+}
+
+cl_map_item_t *cl_qmap_insert(cl_qmap_t * const p_map,
+ const uint64_t key,
+ cl_map_item_t * const p_item)
+{
+ cl_map_item_t *p_insert_at, *p_comp_item;
+
+ assert(p_map);
+ assert(p_item);
+ assert(p_map->root.p_up == &p_map->root);
+ assert(p_map->root.color != CL_MAP_RED);
+ assert(p_map->nil.color != CL_MAP_RED);
+
+ p_item->p_left = &p_map->nil;
+ p_item->p_right = &p_map->nil;
+ p_item->key = key;
+ p_item->color = CL_MAP_RED;
+
+ /* Find the insertion location. */
+ p_insert_at = &p_map->root;
+ p_comp_item = __cl_map_root(p_map);
+
+ while (p_comp_item != &p_map->nil) {
+ p_insert_at = p_comp_item;
+
+ if (key == p_insert_at->key)
+ return (p_insert_at);
+
+ /* Traverse the tree until the correct insertion point is found. */
+ if (key < p_insert_at->key)
+ p_comp_item = p_insert_at->p_left;
+ else
+ p_comp_item = p_insert_at->p_right;
+ }
+
+ assert(p_insert_at != &p_map->nil);
+ assert(p_comp_item == &p_map->nil);
+ /* Insert the item. */
+ if (p_insert_at == &p_map->root) {
+ p_insert_at->p_left = p_item;
+ /*
+ * Primitive insert places the new item in front of
+ * the existing item.
+ */
+ __cl_primitive_insert(&p_map->nil.pool_item.list_item,
+ &p_item->pool_item.list_item);
+ } else if (key < p_insert_at->key) {
+ p_insert_at->p_left = p_item;
+ /*
+ * Primitive insert places the new item in front of
+ * the existing item.
+ */
+ __cl_primitive_insert(&p_insert_at->pool_item.list_item,
+ &p_item->pool_item.list_item);
+ } else {
+ p_insert_at->p_right = p_item;
+ /*
+ * Primitive insert places the new item in front of
+ * the existing item.
+ */
+ __cl_primitive_insert(p_insert_at->pool_item.list_item.p_next,
+ &p_item->pool_item.list_item);
+ }
+ /* Increase the count. */
+ p_map->count++;
+
+ p_item->p_up = p_insert_at;
+
+ /*
+ * We have added depth to this section of the tree.
+ * Rebalance as necessary as we retrace our path through the tree
+ * and update colors.
+ */
+ __cl_map_ins_bal(p_map, p_item);
+
+ __cl_map_root(p_map)->color = CL_MAP_BLACK;
+
+ /*
+ * Note that it is not necessary to re-color the nil node black because all
+ * red color assignments are made via the p_up pointer, and nil is never
+ * set as the value of a p_up pointer.
+ */
+
+#ifdef _DEBUG_
+ /* Set the pointer to the map in the map item for consistency checking. */
+ p_item->p_map = p_map;
+#endif
+
+ return (p_item);
+}
+
+static void __cl_map_del_bal(cl_qmap_t * const p_map,
+ cl_map_item_t * p_item)
+{
+ cl_map_item_t *p_uncle;
+
+ while ((p_item->color != CL_MAP_RED) && (p_item->p_up != &p_map->root)) {
+ if (__cl_map_is_left_child(p_item)) {
+ p_uncle = p_item->p_up->p_right;
+
+ if (p_uncle->color == CL_MAP_RED) {
+ p_uncle->color = CL_MAP_BLACK;
+ p_item->p_up->color = CL_MAP_RED;
+ __cl_map_rot_left(p_map, p_item->p_up);
+ p_uncle = p_item->p_up->p_right;
+ }
+
+ if (p_uncle->p_right->color != CL_MAP_RED) {
+ if (p_uncle->p_left->color != CL_MAP_RED) {
+ p_uncle->color = CL_MAP_RED;
+ p_item = p_item->p_up;
+ continue;
+ }
+
+ p_uncle->p_left->color = CL_MAP_BLACK;
+ p_uncle->color = CL_MAP_RED;
+ __cl_map_rot_right(p_map, p_uncle);
+ p_uncle = p_item->p_up->p_right;
+ }
+ p_uncle->color = p_item->p_up->color;
+ p_item->p_up->color = CL_MAP_BLACK;
+ p_uncle->p_right->color = CL_MAP_BLACK;
+ __cl_map_rot_left(p_map, p_item->p_up);
+ break;
+ } else {
+ p_uncle = p_item->p_up->p_left;
+
+ if (p_uncle->color == CL_MAP_RED) {
+ p_uncle->color = CL_MAP_BLACK;
+ p_item->p_up->color = CL_MAP_RED;
+ __cl_map_rot_right(p_map, p_item->p_up);
+ p_uncle = p_item->p_up->p_left;
+ }
+
+ if (p_uncle->p_left->color != CL_MAP_RED) {
+ if (p_uncle->p_right->color != CL_MAP_RED) {
+ p_uncle->color = CL_MAP_RED;
+ p_item = p_item->p_up;
+ continue;
+ }
+
+ p_uncle->p_right->color = CL_MAP_BLACK;
+ p_uncle->color = CL_MAP_RED;
+ __cl_map_rot_left(p_map, p_uncle);
+ p_uncle = p_item->p_up->p_left;
+ }
+ p_uncle->color = p_item->p_up->color;
+ p_item->p_up->color = CL_MAP_BLACK;
+ p_uncle->p_left->color = CL_MAP_BLACK;
+ __cl_map_rot_right(p_map, p_item->p_up);
+ break;
+ }
+ }
+ p_item->color = CL_MAP_BLACK;
+}
+
+void cl_qmap_remove_item(cl_qmap_t * const p_map,
+ cl_map_item_t * const p_item)
+{
+ cl_map_item_t *p_child, *p_del_item;
+
+ assert(p_map);
+ assert(p_item);
+
+ if (p_item == cl_qmap_end(p_map))
+ return;
+
+ if ((p_item->p_right == &p_map->nil) || (p_item->p_left == &p_map->nil)) {
+ /* The item being removed has children on at most on side. */
+ p_del_item = p_item;
+ } else {
+ /*
+ * The item being removed has children on both side.
+ * We select the item that will replace it. After removing
+ * the substitute item and rebalancing, the tree will have the
+ * correct topology. Exchanging the substitute for the item
+ * will finalize the removal.
+ */
+ p_del_item = cl_qmap_next(p_item);
+ assert(p_del_item != &p_map->nil);
+ }
+
+ /* Remove the item from the list. */
+ __cl_primitive_remove(&p_item->pool_item.list_item);
+ /* Decrement the item count. */
+ p_map->count--;
+
+ /* Get the pointer to the new root's child, if any. */
+ if (p_del_item->p_left != &p_map->nil)
+ p_child = p_del_item->p_left;
+ else
+ p_child = p_del_item->p_right;
+
+ /*
+ * This assignment may modify the parent pointer of the nil node.
+ * This is inconsequential.
+ */
+ p_child->p_up = p_del_item->p_up;
+ (*__cl_map_get_parent_ptr_to_item(p_del_item)) = p_child;
+
+ if (p_del_item->color != CL_MAP_RED)
+ __cl_map_del_bal(p_map, p_child);
+
+ /*
+ * Note that the splicing done below does not need to occur before
+ * the tree is balanced, since the actual topology changes are made by the
+ * preceding code. The topology is preserved by the color assignment made
+ * below (reader should be reminded that p_del_item == p_item in some cases).
+ */
+ if (p_del_item != p_item) {
+ /*
+ * Finalize the removal of the specified item by exchanging it with
+ * the substitute which we removed above.
+ */
+ p_del_item->p_up = p_item->p_up;
+ p_del_item->p_left = p_item->p_left;
+ p_del_item->p_right = p_item->p_right;
+ (*__cl_map_get_parent_ptr_to_item(p_item)) = p_del_item;
+ p_item->p_right->p_up = p_del_item;
+ p_item->p_left->p_up = p_del_item;
+ p_del_item->color = p_item->color;
+ }
+
+ assert(p_map->nil.color != CL_MAP_RED);
+
+#ifdef _DEBUG_
+ /* Clear the pointer to the map since the item has been removed. */
+ p_item->p_map = NULL;
+#endif
+}
+
+cl_map_item_t *cl_qmap_remove(cl_qmap_t * const p_map, const uint64_t key)
+{
+ cl_map_item_t *p_item;
+
+ assert(p_map);
+
+ /* Seek the node with the specified key */
+ p_item = cl_qmap_get(p_map, key);
+
+ cl_qmap_remove_item(p_map, p_item);
+
+ return (p_item);
+}
+
+void cl_qmap_merge(cl_qmap_t * const p_dest_map,
+ cl_qmap_t * const p_src_map)
+{
+ cl_map_item_t *p_item, *p_item2, *p_next;
+
+ assert(p_dest_map);
+ assert(p_src_map);
+
+ p_item = cl_qmap_head(p_src_map);
+
+ while (p_item != cl_qmap_end(p_src_map)) {
+ p_next = cl_qmap_next(p_item);
+
+ /* Remove the item from its current map. */
+ cl_qmap_remove_item(p_src_map, p_item);
+ /* Insert the item into the destination map. */
+ p_item2 =
+ cl_qmap_insert(p_dest_map, cl_qmap_key(p_item), p_item);
+ /* Check that the item was successfully inserted. */
+ if (p_item2 != p_item) {
+ /* Put the item in back in the source map. */
+ p_item2 =
+ cl_qmap_insert(p_src_map, cl_qmap_key(p_item),
+ p_item);
+ assert(p_item2 == p_item);
+ }
+ p_item = p_next;
+ }
+}
+
+static void __cl_qmap_delta_move(cl_qmap_t * const p_dest,
+ cl_qmap_t * const p_src,
+ cl_map_item_t ** const pp_item)
+{
+ cl_map_item_t __attribute__((__unused__)) *p_temp;
+ cl_map_item_t *p_next;
+
+ /*
+ * Get the next item so that we can ensure that pp_item points to
+ * a valid item upon return from the function.
+ */
+ p_next = cl_qmap_next(*pp_item);
+ /* Move the old item from its current map the the old map. */
+ cl_qmap_remove_item(p_src, *pp_item);
+ p_temp = cl_qmap_insert(p_dest, cl_qmap_key(*pp_item), *pp_item);
+ /* We should never have duplicates. */
+ assert(p_temp == *pp_item);
+ /* Point pp_item to a valid item in the source map. */
+ (*pp_item) = p_next;
+}
+
+void cl_qmap_delta(cl_qmap_t * const p_map1,
+ cl_qmap_t * const p_map2,
+ cl_qmap_t * const p_new, cl_qmap_t * const p_old)
+{
+ cl_map_item_t *p_item1, *p_item2;
+ uint64_t key1, key2;
+
+ assert(p_map1);
+ assert(p_map2);
+ assert(p_new);
+ assert(p_old);
+ assert(cl_is_qmap_empty(p_new));
+ assert(cl_is_qmap_empty(p_old));
+
+ p_item1 = cl_qmap_head(p_map1);
+ p_item2 = cl_qmap_head(p_map2);
+
+ while (p_item1 != cl_qmap_end(p_map1) && p_item2 != cl_qmap_end(p_map2)) {
+ key1 = cl_qmap_key(p_item1);
+ key2 = cl_qmap_key(p_item2);
+ if (key1 < key2) {
+ /* We found an old item. */
+ __cl_qmap_delta_move(p_old, p_map1, &p_item1);
+ } else if (key1 > key2) {
+ /* We found a new item. */
+ __cl_qmap_delta_move(p_new, p_map2, &p_item2);
+ } else {
+ /* Move both forward since they have the same key. */
+ p_item1 = cl_qmap_next(p_item1);
+ p_item2 = cl_qmap_next(p_item2);
+ }
+ }
+
+ /* Process the remainder if the end of either source map was reached. */
+ while (p_item2 != cl_qmap_end(p_map2))
+ __cl_qmap_delta_move(p_new, p_map2, &p_item2);
+
+ while (p_item1 != cl_qmap_end(p_map1))
+ __cl_qmap_delta_move(p_old, p_map1, &p_item1);
+}
new file mode 100644
@@ -0,0 +1,970 @@
+/*
+ * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved.
+ * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved.
+ * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+/*
+ * Abstract:
+ * Declaration of quick map, a binary tree where the caller always provides
+ * all necessary storage.
+ */
+
+#ifndef _CL_QMAP_H_
+#define _CL_QMAP_H_
+
+#include <stdbool.h>
+#include <assert.h>
+#include <inttypes.h>
+#include <stdio.h>
+
+typedef struct _cl_list_item {
+ struct _cl_list_item *p_next;
+ struct _cl_list_item *p_prev;
+} cl_list_item_t;
+
+typedef struct _cl_pool_item {
+ cl_list_item_t list_item;
+} cl_pool_item_t;
+
+/****h* Component Library/Quick Map
+* NAME
+* Quick Map
+*
+* DESCRIPTION
+* Quick map implements a binary tree that stores user provided cl_map_item_t
+* structures. Each item stored in a quick map has a unique 64-bit key
+* (duplicates are not allowed). Quick map provides the ability to
+* efficiently search for an item given a key.
+*
+* Quick map does not allocate any memory, and can therefore not fail
+* any operations due to insufficient memory. Quick map can thus be useful
+* in minimizing the error paths in code.
+*
+* Quick map is not thread safe, and users must provide serialization when
+* adding and removing items from the map.
+*
+* The quick map functions operate on a cl_qmap_t structure which should be
+* treated as opaque and should be manipulated only through the provided
+* functions.
+*
+* SEE ALSO
+* Structures:
+* cl_qmap_t, cl_map_item_t, cl_map_obj_t
+*
+* Callbacks:
+* cl_pfn_qmap_apply_t
+*
+* Item Manipulation:
+* cl_qmap_set_obj, cl_qmap_obj, cl_qmap_key
+*
+* Initialization:
+* cl_qmap_init
+*
+* Iteration:
+* cl_qmap_end, cl_qmap_head, cl_qmap_tail, cl_qmap_next, cl_qmap_prev
+*
+* Manipulation:
+* cl_qmap_insert, cl_qmap_get, cl_qmap_remove_item, cl_qmap_remove,
+* cl_qmap_remove_all, cl_qmap_merge, cl_qmap_delta, cl_qmap_get_next
+*
+* Search:
+* cl_qmap_apply_func
+*
+* Attributes:
+* cl_qmap_count, cl_is_qmap_empty,
+*********/
+/****i* Component Library: Quick Map/cl_map_color_t
+* NAME
+* cl_map_color_t
+*
+* DESCRIPTION
+* The cl_map_color_t enumerated type is used to note the color of
+* nodes in a map.
+*
+* SYNOPSIS
+*/
+typedef enum _cl_map_color {
+ CL_MAP_RED,
+ CL_MAP_BLACK
+} cl_map_color_t;
+/*
+* VALUES
+* CL_MAP_RED
+* The node in the map is red.
+*
+* CL_MAP_BLACK
+* The node in the map is black.
+*
+* SEE ALSO
+* Quick Map, cl_map_item_t
+*********/
+
+/****s* Component Library: Quick Map/cl_map_item_t
+* NAME
+* cl_map_item_t
+*
+* DESCRIPTION
+* The cl_map_item_t structure is used by maps to store objects.
+*
+* The cl_map_item_t structure should be treated as opaque and should
+* be manipulated only through the provided functions.
+*
+* SYNOPSIS
+*/
+typedef struct _cl_map_item {
+ /* Must be first to allow casting. */
+ cl_pool_item_t pool_item;
+ struct _cl_map_item *p_left;
+ struct _cl_map_item *p_right;
+ struct _cl_map_item *p_up;
+ cl_map_color_t color;
+ uint64_t key;
+#ifdef _DEBUG_
+ struct _cl_qmap *p_map;
+#endif
+} cl_map_item_t;
+/*
+* FIELDS
+* pool_item
+* Used to store the item in a doubly linked list, allowing more
+* efficient map traversal.
+*
+* p_left
+* Pointer to the map item that is a child to the left of the node.
+*
+* p_right
+* Pointer to the map item that is a child to the right of the node.
+*
+* p_up
+* Pointer to the map item that is the parent of the node.
+*
+* color
+* Indicates whether a node is red or black in the map.
+*
+* key
+* Value that uniquely represents a node in a map. This value is
+* set by calling cl_qmap_insert and can be retrieved by calling
+* cl_qmap_key.
+*
+* NOTES
+* None of the fields of this structure should be manipulated by users, as
+* they are crititcal to the proper operation of the map in which they
+* are stored.
+*
+* To allow storing items in either a quick list, a quick pool, or a quick
+* map, the map implementation guarantees that the map item can be safely
+* cast to a pool item used for storing an object in a quick pool, or cast
+* to a list item used for storing an object in a quick list. This removes
+* the need to embed a map item, a list item, and a pool item in objects
+* that need to be stored in a quick list, a quick pool, and a quick map.
+*
+* SEE ALSO
+* Quick Map, cl_qmap_insert, cl_qmap_key, cl_pool_item_t, cl_list_item_t
+*********/
+
+/****s* Component Library: Quick Map/cl_map_obj_t
+* NAME
+* cl_map_obj_t
+*
+* DESCRIPTION
+* The cl_map_obj_t structure is used to store objects in maps.
+*
+* The cl_map_obj_t structure should be treated as opaque and should
+* be manipulated only through the provided functions.
+*
+* SYNOPSIS
+*/
+typedef struct _cl_map_obj {
+ cl_map_item_t item;
+ const void *p_object;
+} cl_map_obj_t;
+/*
+* FIELDS
+* item
+* Map item used by internally by the map to store an object.
+*
+* p_object
+* User defined context. Users should not access this field directly.
+* Use cl_qmap_set_obj and cl_qmap_obj to set and retrieve the value
+* of this field.
+*
+* NOTES
+* None of the fields of this structure should be manipulated by users, as
+* they are crititcal to the proper operation of the map in which they
+* are stored.
+*
+* Use cl_qmap_set_obj and cl_qmap_obj to set and retrieve the object
+* stored in a map item, respectively.
+*
+* SEE ALSO
+* Quick Map, cl_qmap_set_obj, cl_qmap_obj, cl_map_item_t
+*********/
+
+/****s* Component Library: Quick Map/cl_qmap_t
+* NAME
+* cl_qmap_t
+*
+* DESCRIPTION
+* Quick map structure.
+*
+* The cl_qmap_t structure should be treated as opaque and should
+* be manipulated only through the provided functions.
+*
+* SYNOPSIS
+*/
+typedef struct _cl_qmap {
+ cl_map_item_t root;
+ cl_map_item_t nil;
+ size_t count;
+} cl_qmap_t;
+/*
+* PARAMETERS
+* root
+* Map item that serves as root of the map. The root is set up to
+* always have itself as parent. The left pointer is set to point
+* to the item at the root.
+*
+* nil
+* Map item that serves as terminator for all leaves, as well as
+* providing the list item used as quick list for storing map items
+* in a list for faster traversal.
+*
+* state
+* State of the map, used to verify that operations are permitted.
+*
+* count
+* Number of items in the map.
+*
+* SEE ALSO
+* Quick Map
+*********/
+
+/****d* Component Library: Quick Map/cl_pfn_qmap_apply_t
+* NAME
+* cl_pfn_qmap_apply_t
+*
+* DESCRIPTION
+* The cl_pfn_qmap_apply_t function type defines the prototype for
+* functions used to iterate items in a quick map.
+*
+* SYNOPSIS
+*/
+typedef void
+ (*cl_pfn_qmap_apply_t) (cl_map_item_t * const p_map_item, void *context);
+/*
+* PARAMETERS
+* p_map_item
+* [in] Pointer to a cl_map_item_t structure.
+*
+* context
+* [in] Value passed to the callback function.
+*
+* RETURN VALUE
+* This function does not return a value.
+*
+* NOTES
+* This function type is provided as function prototype reference for the
+* function provided by users as a parameter to the cl_qmap_apply_func
+* function.
+*
+* SEE ALSO
+* Quick Map, cl_qmap_apply_func
+*********/
+
+/****f* Component Library: Quick Map/cl_qmap_count
+* NAME
+* cl_qmap_count
+*
+* DESCRIPTION
+* The cl_qmap_count function returns the number of items stored
+* in a quick map.
+*
+* SYNOPSIS
+*/
+static inline uint32_t cl_qmap_count(const cl_qmap_t * const p_map)
+{
+ assert(p_map);
+ return ((uint32_t) p_map->count);
+}
+
+/*
+* PARAMETERS
+* p_map
+* [in] Pointer to a cl_qmap_t structure whose item count to return.
+*
+* RETURN VALUE
+* Returns the number of items stored in the map.
+*
+* SEE ALSO
+* Quick Map, cl_is_qmap_empty
+*********/
+
+/****f* Component Library: Quick Map/cl_is_qmap_empty
+* NAME
+* cl_is_qmap_empty
+*
+* DESCRIPTION
+* The cl_is_qmap_empty function returns whether a quick map is empty.
+*
+* SYNOPSIS
+*/
+static inline bool cl_is_qmap_empty(const cl_qmap_t * const p_map)
+{
+ assert(p_map);
+
+ return (p_map->count == 0);
+}
+
+/*
+* PARAMETERS
+* p_map
+* [in] Pointer to a cl_qmap_t structure to test for emptiness.
+*
+* RETURN VALUES
+* TRUE if the quick map is empty.
+*
+* FALSE otherwise.
+*
+* SEE ALSO
+* Quick Map, cl_qmap_count, cl_qmap_remove_all
+*********/
+
+/****f* Component Library: Quick Map/cl_qmap_set_obj
+* NAME
+* cl_qmap_set_obj
+*
+* DESCRIPTION
+* The cl_qmap_set_obj function sets the object stored in a map object.
+*
+* SYNOPSIS
+*/
+static inline void
+cl_qmap_set_obj(cl_map_obj_t * const p_map_obj,
+ const void *const p_object)
+{
+ assert(p_map_obj);
+ p_map_obj->p_object = p_object;
+}
+
+/*
+* PARAMETERS
+* p_map_obj
+* [in] Pointer to a map object stucture whose object pointer
+* is to be set.
+*
+* p_object
+* [in] User defined context.
+*
+* RETURN VALUE
+* This function does not return a value.
+*
+* SEE ALSO
+* Quick Map, cl_qmap_obj
+*********/
+
+/****f* Component Library: Quick Map/cl_qmap_obj
+* NAME
+* cl_qmap_obj
+*
+* DESCRIPTION
+* The cl_qmap_obj function returns the object stored in a map object.
+*
+* SYNOPSIS
+*/
+static inline void *cl_qmap_obj(const cl_map_obj_t * const p_map_obj)
+{
+ assert(p_map_obj);
+ return ((void *)p_map_obj->p_object);
+}
+
+/*
+* PARAMETERS
+* p_map_obj
+* [in] Pointer to a map object stucture whose object pointer to return.
+*
+* RETURN VALUE
+* Returns the value of the object pointer stored in the map object.
+*
+* SEE ALSO
+* Quick Map, cl_qmap_set_obj
+*********/
+
+/****f* Component Library: Quick Map/cl_qmap_key
+* NAME
+* cl_qmap_key
+*
+* DESCRIPTION
+* The cl_qmap_key function retrieves the key value of a map item.
+*
+* SYNOPSIS
+*/
+static inline uint64_t cl_qmap_key(const cl_map_item_t * const p_item)
+{
+ assert(p_item);
+ return (p_item->key);
+}
+
+/*
+* PARAMETERS
+* p_item
+* [in] Pointer to a map item whose key value to return.
+*
+* RETURN VALUE
+* Returns the 64-bit key value for the specified map item.
+*
+* NOTES
+* The key value is set in a call to cl_qmap_insert.
+*
+* SEE ALSO
+* Quick Map, cl_qmap_insert
+*********/
+
+/****f* Component Library: Quick Map/cl_qmap_init
+* NAME
+* cl_qmap_init
+*
+* DESCRIPTION
+* The cl_qmap_init function initialized a quick map for use.
+*
+* SYNOPSIS
+*/
+void cl_qmap_init(cl_qmap_t * const p_map);
+/*
+* PARAMETERS
+* p_map
+* [in] Pointer to a cl_qmap_t structure to initialize.
+*
+* RETURN VALUES
+* This function does not return a value.
+*
+* NOTES
+* Allows calling quick map manipulation functions.
+*
+* SEE ALSO
+* Quick Map, cl_qmap_insert, cl_qmap_remove
+*********/
+
+/****f* Component Library: Quick Map/cl_qmap_end
+* NAME
+* cl_qmap_end
+*
+* DESCRIPTION
+* The cl_qmap_end function returns the end of a quick map.
+*
+* SYNOPSIS
+*/
+static inline const cl_map_item_t *cl_qmap_end(const cl_qmap_t * const p_map)
+{
+ assert(p_map);
+ /* Nil is the end of the map. */
+ return (&p_map->nil);
+}
+
+/*
+* PARAMETERS
+* p_map
+* [in] Pointer to a cl_qmap_t structure whose end to return.
+*
+* RETURN VALUE
+* Pointer to the end of the map.
+*
+* NOTES
+* cl_qmap_end is useful for determining the validity of map items returned
+* by cl_qmap_head, cl_qmap_tail, cl_qmap_next, or cl_qmap_prev. If the
+* map item pointer returned by any of these functions compares to the end,
+* the end of the map was encoutered.
+* When using cl_qmap_head or cl_qmap_tail, this condition indicates that
+* the map is empty.
+*
+* SEE ALSO
+* Quick Map, cl_qmap_head, cl_qmap_tail, cl_qmap_next, cl_qmap_prev
+*********/
+
+/****f* Component Library: Quick Map/cl_qmap_head
+* NAME
+* cl_qmap_head
+*
+* DESCRIPTION
+* The cl_qmap_head function returns the map item with the lowest key
+* value stored in a quick map.
+*
+* SYNOPSIS
+*/
+static inline cl_map_item_t *cl_qmap_head(const cl_qmap_t * const p_map)
+{
+ assert(p_map);
+ return ((cl_map_item_t *) p_map->nil.pool_item.list_item.p_next);
+}
+
+/*
+* PARAMETERS
+* p_map
+* [in] Pointer to a cl_qmap_t structure whose item with the lowest
+* key is returned.
+*
+* RETURN VALUES
+* Pointer to the map item with the lowest key in the quick map.
+*
+* Pointer to the map end if the quick map was empty.
+*
+* NOTES
+* cl_qmap_head does not remove the item from the map.
+*
+* SEE ALSO
+* Quick Map, cl_qmap_tail, cl_qmap_next, cl_qmap_prev, cl_qmap_end,
+* cl_qmap_item_t
+*********/
+
+/****f* Component Library: Quick Map/cl_qmap_tail
+* NAME
+* cl_qmap_tail
+*
+* DESCRIPTION
+* The cl_qmap_tail function returns the map item with the highest key
+* value stored in a quick map.
+*
+* SYNOPSIS
+*/
+static inline cl_map_item_t *cl_qmap_tail(const cl_qmap_t * const p_map)
+{
+ assert(p_map);
+ return ((cl_map_item_t *) p_map->nil.pool_item.list_item.p_prev);
+}
+
+/*
+* PARAMETERS
+* p_map
+* [in] Pointer to a cl_qmap_t structure whose item with the
+* highest key is returned.
+*
+* RETURN VALUES
+* Pointer to the map item with the highest key in the quick map.
+*
+* Pointer to the map end if the quick map was empty.
+*
+* NOTES
+* cl_qmap_end does not remove the item from the map.
+*
+* SEE ALSO
+* Quick Map, cl_qmap_head, cl_qmap_next, cl_qmap_prev, cl_qmap_end,
+* cl_qmap_item_t
+*********/
+
+/****f* Component Library: Quick Map/cl_qmap_next
+* NAME
+* cl_qmap_next
+*
+* DESCRIPTION
+* The cl_qmap_next function returns the map item with the next higher
+* key value than a specified map item.
+*
+* SYNOPSIS
+*/
+static inline cl_map_item_t *cl_qmap_next(const cl_map_item_t * const p_item)
+{
+ assert(p_item);
+ return ((cl_map_item_t *) p_item->pool_item.list_item.p_next);
+}
+
+/*
+* PARAMETERS
+* p_item
+* [in] Pointer to a map item whose successor to return.
+*
+* RETURN VALUES
+* Pointer to the map item with the next higher key value in a quick map.
+*
+* Pointer to the map end if the specified item was the last item in
+* the quick map.
+*
+* SEE ALSO
+* Quick Map, cl_qmap_head, cl_qmap_tail, cl_qmap_prev, cl_qmap_end,
+* cl_map_item_t
+*********/
+
+/****f* Component Library: Quick Map/cl_qmap_prev
+* NAME
+* cl_qmap_prev
+*
+* DESCRIPTION
+* The cl_qmap_prev function returns the map item with the next lower
+* key value than a precified map item.
+*
+* SYNOPSIS
+*/
+static inline cl_map_item_t *cl_qmap_prev(const cl_map_item_t * const p_item)
+{
+ assert(p_item);
+ return ((cl_map_item_t *) p_item->pool_item.list_item.p_prev);
+}
+
+/*
+* PARAMETERS
+* p_item
+* [in] Pointer to a map item whose predecessor to return.
+*
+* RETURN VALUES
+* Pointer to the map item with the next lower key value in a quick map.
+*
+* Pointer to the map end if the specifid item was the first item in
+* the quick map.
+*
+* SEE ALSO
+* Quick Map, cl_qmap_head, cl_qmap_tail, cl_qmap_next, cl_qmap_end,
+* cl_map_item_t
+*********/
+
+/****f* Component Library: Quick Map/cl_qmap_insert
+* NAME
+* cl_qmap_insert
+*
+* DESCRIPTION
+* The cl_qmap_insert function inserts a map item into a quick map.
+* NOTE: Only if such a key does not alerady exist in the map !!!!
+*
+* SYNOPSIS
+*/
+cl_map_item_t *cl_qmap_insert(cl_qmap_t * const p_map,
+ const uint64_t key,
+ cl_map_item_t * const p_item);
+/*
+* PARAMETERS
+* p_map
+* [in] Pointer to a cl_qmap_t structure into which to add the item.
+*
+* key
+* [in] Value to assign to the item.
+*
+* p_item
+* [in] Pointer to a cl_map_item_t stucture to insert into the quick map.
+*
+* RETURN VALUE
+* Pointer to the item in the map with the specified key. If insertion
+* was successful, this is the pointer to the item. If an item with the
+* specified key already exists in the map, the pointer to that item is
+* returned - but the new key is NOT inserted...
+*
+* NOTES
+* Insertion operations may cause the quick map to rebalance.
+*
+* SEE ALSO
+* Quick Map, cl_qmap_remove, cl_map_item_t
+*********/
+
+/****f* Component Library: Quick Map/cl_qmap_get
+* NAME
+* cl_qmap_get
+*
+* DESCRIPTION
+* The cl_qmap_get function returns the map item associated with a key.
+*
+* SYNOPSIS
+*/
+cl_map_item_t *cl_qmap_get(const cl_qmap_t * const p_map,
+ const uint64_t key);
+/*
+* PARAMETERS
+* p_map
+* [in] Pointer to a cl_qmap_t structure from which to retrieve the
+* item with the specified key.
+*
+* key
+* [in] Key value used to search for the desired map item.
+*
+* RETURN VALUES
+* Pointer to the map item with the desired key value.
+*
+* Pointer to the map end if there was no item with the desired key value
+* stored in the quick map.
+*
+* NOTES
+* cl_qmap_get does not remove the item from the quick map.
+*
+* SEE ALSO
+* Quick Map, cl_qmap_get_next, cl_qmap_remove
+*********/
+
+/****f* Component Library: Quick Map/cl_qmap_get_next
+* NAME
+* cl_qmap_get_next
+*
+* DESCRIPTION
+* The cl_qmap_get_next function returns the first map item associated with a
+* key > the key specified.
+*
+* SYNOPSIS
+*/
+cl_map_item_t *cl_qmap_get_next(const cl_qmap_t * const p_map,
+ const uint64_t key);
+/*
+* PARAMETERS
+* p_map
+* [in] Pointer to a cl_qmap_t structure from which to retrieve the
+* first item with a key > the specified key.
+*
+* key
+* [in] Key value used to search for the desired map item.
+*
+* RETURN VALUES
+* Pointer to the first map item with a key > the desired key value.
+*
+* Pointer to the map end if there was no item with a key > the desired key
+* value stored in the quick map.
+*
+* NOTES
+* cl_qmap_get_next does not remove the item from the quick map.
+*
+* SEE ALSO
+* Quick Map, cl_qmap_get, cl_qmap_remove
+*********/
+
+/****f* Component Library: Quick Map/cl_qmap_remove_item
+* NAME
+* cl_qmap_remove_item
+*
+* DESCRIPTION
+* The cl_qmap_remove_item function removes the specified map item
+* from a quick map.
+*
+* SYNOPSIS
+*/
+void
+cl_qmap_remove_item(cl_qmap_t * const p_map,
+ cl_map_item_t * const p_item);
+/*
+* PARAMETERS
+* p_map
+* [in] Pointer to a cl_qmap_t structure from which to
+* remove item.
+*
+* p_item
+* [in] Pointer to a map item to remove from its quick map.
+*
+* RETURN VALUES
+* This function does not return a value.
+*
+* In a debug build, cl_qmap_remove_item asserts that the item being removed
+* is in the specified map.
+*
+* NOTES
+* Removes the map item pointed to by p_item from its quick map.
+*
+* SEE ALSO
+* Quick Map, cl_qmap_remove, cl_qmap_remove_all, cl_qmap_insert
+*********/
+
+/****f* Component Library: Quick Map/cl_qmap_remove
+* NAME
+* cl_qmap_remove
+*
+* DESCRIPTION
+* The cl_qmap_remove function removes the map item with the specified key
+* from a quick map.
+*
+* SYNOPSIS
+*/
+cl_map_item_t *cl_qmap_remove(cl_qmap_t * const p_map,
+ const uint64_t key);
+/*
+* PARAMETERS
+* p_map
+* [in] Pointer to a cl_qmap_t structure from which to remove the item
+* with the specified key.
+*
+* key
+* [in] Key value used to search for the map item to remove.
+*
+* RETURN VALUES
+* Pointer to the removed map item if it was found.
+*
+* Pointer to the map end if no item with the specified key exists in the
+* quick map.
+*
+* SEE ALSO
+* Quick Map, cl_qmap_remove_item, cl_qmap_remove_all, cl_qmap_insert
+*********/
+
+/****f* Component Library: Quick Map/cl_qmap_remove_all
+* NAME
+* cl_qmap_remove_all
+*
+* DESCRIPTION
+* The cl_qmap_remove_all function removes all items in a quick map,
+* leaving it empty.
+*
+* SYNOPSIS
+*/
+static inline void cl_qmap_remove_all(cl_qmap_t * const p_map)
+{
+ assert(p_map);
+
+ p_map->root.p_left = &p_map->nil;
+ p_map->nil.pool_item.list_item.p_next = &p_map->nil.pool_item.list_item;
+ p_map->nil.pool_item.list_item.p_prev = &p_map->nil.pool_item.list_item;
+ p_map->count = 0;
+}
+
+/*
+* PARAMETERS
+* p_map
+* [in] Pointer to a cl_qmap_t structure to empty.
+*
+* RETURN VALUES
+* This function does not return a value.
+*
+* SEE ALSO
+* Quick Map, cl_qmap_remove, cl_qmap_remove_item
+*********/
+
+/****f* Component Library: Quick Map/cl_qmap_merge
+* NAME
+* cl_qmap_merge
+*
+* DESCRIPTION
+* The cl_qmap_merge function moves all items from one map to another,
+* excluding duplicates.
+*
+* SYNOPSIS
+*/
+void
+cl_qmap_merge(cl_qmap_t * const p_dest_map,
+ cl_qmap_t * const p_src_map);
+/*
+* PARAMETERS
+* p_dest_map
+* [out] Pointer to a cl_qmap_t structure to which items should be added.
+*
+* p_src_map
+* [in/out] Pointer to a cl_qmap_t structure whose items to add
+* to p_dest_map.
+*
+* RETURN VALUES
+* This function does not return a value.
+*
+* NOTES
+* Items are evaluated based on their keys only.
+*
+* Upon return from cl_qmap_merge, the quick map referenced by p_src_map
+* contains all duplicate items.
+*
+* SEE ALSO
+* Quick Map, cl_qmap_delta
+*********/
+
+/****f* Component Library: Quick Map/cl_qmap_delta
+* NAME
+* cl_qmap_delta
+*
+* DESCRIPTION
+* The cl_qmap_delta function computes the differences between two maps.
+*
+* SYNOPSIS
+*/
+void
+cl_qmap_delta(cl_qmap_t * const p_map1,
+ cl_qmap_t * const p_map2,
+ cl_qmap_t * const p_new, cl_qmap_t * const p_old);
+/*
+* PARAMETERS
+* p_map1
+* [in/out] Pointer to the first of two cl_qmap_t structures whose
+* differences to compute.
+*
+* p_map2
+* [in/out] Pointer to the second of two cl_qmap_t structures whose
+* differences to compute.
+*
+* p_new
+* [out] Pointer to an empty cl_qmap_t structure that contains the
+* items unique to p_map2 upon return from the function.
+*
+* p_old
+* [out] Pointer to an empty cl_qmap_t structure that contains the
+* items unique to p_map1 upon return from the function.
+*
+* RETURN VALUES
+* This function does not return a value.
+*
+* NOTES
+* Items are evaluated based on their keys. Items that exist in both
+* p_map1 and p_map2 remain in their respective maps. Items that
+* exist only p_map1 are moved to p_old. Likewise, items that exist only
+* in p_map2 are moved to p_new. This function can be useful in evaluating
+* changes between two maps.
+*
+* Both maps pointed to by p_new and p_old must be empty on input. This
+* requirement removes the possibility of failures.
+*
+* SEE ALSO
+* Quick Map, cl_qmap_merge
+*********/
+
+/****f* Component Library: Quick Map/cl_qmap_apply_func
+* NAME
+* cl_qmap_apply_func
+*
+* DESCRIPTION
+* The cl_qmap_apply_func function executes a specified function
+* for every item stored in a quick map.
+*
+* SYNOPSIS
+*/
+void
+cl_qmap_apply_func(const cl_qmap_t * const p_map,
+ cl_pfn_qmap_apply_t pfn_func,
+ const void *const context);
+/*
+* PARAMETERS
+* p_map
+* [in] Pointer to a cl_qmap_t structure.
+*
+* pfn_func
+* [in] Function invoked for every item in the quick map.
+* See the cl_pfn_qmap_apply_t function type declaration for
+* details about the callback function.
+*
+* context
+* [in] Value to pass to the callback functions to provide context.
+*
+* RETURN VALUE
+* This function does not return a value.
+*
+* NOTES
+* The function provided must not perform any map operations, as these
+* would corrupt the quick map.
+*
+* SEE ALSO
+* Quick Map, cl_pfn_qmap_apply_t
+*********/
+
+#endif /* _CL_QMAP_H_ */