Viewing: heap.h

/* SPDX-License-Identifier: GPL-2.0 */

/*
 * Copyright (c) 2011 Intel Corporation
 */

/*
 * Author: Eric Barton <eeb@whamcloud.com>
 * Author: Liang Zhen <liang@whamcloud.com>
 */

#ifndef __LIBCFS_HEAP_H__
#define __LIBCFS_HEAP_H__

/** \defgroup heap Binary heap
 *
 * The binary heap is a scalable data structure created using a binary tree. It
 * is capable of maintaining large sets of elements sorted usually by one or
 * more element properties, but really based on anything that can be used as a
 * binary predicate in order to determine the relevant ordering of any two nodes
 * that belong to the set. There is no search operation, rather the intention is
 * for the element of the lowest priority which will always be at the root of
 * the tree (as this is an implementation of a min-heap) to be removed by users
 * for consumption.
 *
 * Users of the heap should embed a \e struct binheap_node object instance
 * on every object of the set that they wish the binary heap instance to handle,
 * and (at a minimum) provide a struct binheap_ops::hop_compare()
 * implementation which is used by the heap as the binary predicate during its
 * internal sorting operations.
 *
 * The current implementation enforces no locking scheme, and so assumes the
 * user caters for locking between calls to insert, delete and lookup
 * operations. Since the only consumer for the data structure at this point
 * are NRS policies, and these operate on a per-CPT basis, binary heap instances
 * are tied to a specific CPT.
 * @{
 */

#define CBH_SHIFT	9
#define CBH_SIZE       (1 << CBH_SHIFT)		    /* # ptrs per level */
#define CBH_MASK       (CBH_SIZE - 1)
#define CBH_NOB        (CBH_SIZE * sizeof(struct binheap_node *))

#define CBH_POISON	0xdeadbeef

/**
 * Binary heap flags.
 */
enum {
	CBH_FLAG_ATOMIC_GROW	= 1,
};

struct binheap;

/**
 * Binary heap operations.
 */
struct binheap_ops {
	/**
	 * Called right before inserting a node into the binary heap.
	 *
	 * Implementing this operation is optional.
	 *
	 * \param[in] h The heap
	 * \param[in] e The node
	 *
	 * \retval 0 success
	 * \retval != 0 error
	 */
	int		(*hop_enter)(struct binheap *h,
				     struct binheap_node *e);
	/**
	 * Called right after removing a node from the binary heap.
	 *
	 * Implementing this operation is optional.
	 *
	 * \param[in] h The heap
	 * \param[in] e The node
	 */
	void		(*hop_exit)(struct binheap *h,
				    struct binheap_node *e);
	/**
	 * A binary predicate which is called during internal heap sorting
	 * operations, and used in order to determine the relevant ordering of
	 * two heap nodes.
	 *
	 * Implementing this operation is mandatory.
	 *
	 * \param[in] a The first heap node
	 * \param[in] b The second heap node
	 *
	 * \retval 0 Node a > node b
	 * \retval 1 Node a < node b
	 *
	 * \see binheap_bubble()
	 * \see cfs_biheap_sink()
	 */
	int		(*hop_compare)(struct binheap_node *a,
				       struct binheap_node *b);
};

/**
 * Binary heap object.
 *
 * Sorts elements of type \e struct binheap_node
 */
struct binheap {
	/** Triple indirect */
	struct binheap_node  ****cbh_elements3;
	/** double indirect */
	struct binheap_node   ***cbh_elements2;
	/** single indirect */
	struct binheap_node    **cbh_elements1;
	/** # elements referenced */
	unsigned int		cbh_nelements;
	/** high water mark */
	unsigned int		cbh_hwm;
	/** user flags */
	unsigned int		cbh_flags;
	/** operations table */
	struct binheap_ops *cbh_ops;
	/** private data */
	void		       *cbh_private;
	/** associated CPT table */
	struct cfs_cpt_table   *cbh_cptab;
	/** associated CPT id of this struct binheap::cbh_cptab */
	int			cbh_cptid;
};

void binheap_destroy(struct binheap *h);
struct binheap *
binheap_create(struct binheap_ops *ops, unsigned int flags,
		   unsigned int count, void *arg, struct cfs_cpt_table *cptab,
		   int cptid);
struct binheap_node *
binheap_find(struct binheap *h, unsigned int idx);
int binheap_insert(struct binheap *h, struct binheap_node *e);
void binheap_remove(struct binheap *h, struct binheap_node *e);
void binheap_relocate(struct binheap *h, struct binheap_node *e);

static inline int
binheap_size(struct binheap *h)
{
	return h->cbh_nelements;
}

static inline int
binheap_is_empty(struct binheap *h)
{
	return h->cbh_nelements == 0;
}

static inline struct binheap_node *
binheap_root(struct binheap *h)
{
	return binheap_find(h, 0);
}

static inline struct binheap_node *
binheap_remove_root(struct binheap *h)
{
	struct binheap_node *e = binheap_find(h, 0);

	if (e != NULL)
		binheap_remove(h, e);
	return e;
}

/** @} heap */

#endif /* __LIBCFS_HEAP_H__ */