xref: /freebsd/sys/netpfil/ipfw/dn_heap.h (revision 95ee2897e98f5d444f26ed2334cc7c439f9c16c6)
13b3a8eb9SGleb Smirnoff /*-
24d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
3fe267a55SPedro F. Giffuni  *
43b3a8eb9SGleb Smirnoff  * Copyright (c) 1998-2010 Luigi Rizzo, Universita` di Pisa
53b3a8eb9SGleb Smirnoff  * All rights reserved
63b3a8eb9SGleb Smirnoff  *
73b3a8eb9SGleb Smirnoff  * Redistribution and use in source and binary forms, with or without
83b3a8eb9SGleb Smirnoff  * modification, are permitted provided that the following conditions
93b3a8eb9SGleb Smirnoff  * are met:
103b3a8eb9SGleb Smirnoff  * 1. Redistributions of source code must retain the above copyright
113b3a8eb9SGleb Smirnoff  *    notice, this list of conditions and the following disclaimer.
123b3a8eb9SGleb Smirnoff  * 2. Redistributions in binary form must reproduce the above copyright
133b3a8eb9SGleb Smirnoff  *    notice, this list of conditions and the following disclaimer in the
143b3a8eb9SGleb Smirnoff  *    documentation and/or other materials provided with the distribution.
153b3a8eb9SGleb Smirnoff  *
163b3a8eb9SGleb Smirnoff  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
173b3a8eb9SGleb Smirnoff  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
183b3a8eb9SGleb Smirnoff  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
193b3a8eb9SGleb Smirnoff  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
203b3a8eb9SGleb Smirnoff  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
213b3a8eb9SGleb Smirnoff  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
223b3a8eb9SGleb Smirnoff  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
233b3a8eb9SGleb Smirnoff  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
243b3a8eb9SGleb Smirnoff  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
253b3a8eb9SGleb Smirnoff  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
263b3a8eb9SGleb Smirnoff  * SUCH DAMAGE.
273b3a8eb9SGleb Smirnoff  */
283b3a8eb9SGleb Smirnoff 
293b3a8eb9SGleb Smirnoff /*
303b3a8eb9SGleb Smirnoff  * Binary heap and hash tables, header file
313b3a8eb9SGleb Smirnoff  */
323b3a8eb9SGleb Smirnoff 
333b3a8eb9SGleb Smirnoff #ifndef _IP_DN_HEAP_H
343b3a8eb9SGleb Smirnoff #define _IP_DN_HEAP_H
353b3a8eb9SGleb Smirnoff 
363b3a8eb9SGleb Smirnoff #define DN_KEY_LT(a,b)     ((int64_t)((a)-(b)) < 0)
373b3a8eb9SGleb Smirnoff #define DN_KEY_LEQ(a,b)    ((int64_t)((a)-(b)) <= 0)
383b3a8eb9SGleb Smirnoff 
393b3a8eb9SGleb Smirnoff /*
403b3a8eb9SGleb Smirnoff  * This module implements a binary heap supporting random extraction.
413b3a8eb9SGleb Smirnoff  *
423b3a8eb9SGleb Smirnoff  * A heap entry contains an uint64_t key and a pointer to object.
433b3a8eb9SGleb Smirnoff  * DN_KEY_LT(a,b) returns true if key 'a' is smaller than 'b'
443b3a8eb9SGleb Smirnoff  *
453b3a8eb9SGleb Smirnoff  * The heap is a struct dn_heap plus a dynamically allocated
463b3a8eb9SGleb Smirnoff  * array of dn_heap_entry entries. 'size' represents the size of
473b3a8eb9SGleb Smirnoff  * the array, 'elements' count entries in use. The topmost
483b3a8eb9SGleb Smirnoff  * element has the smallest key.
493b3a8eb9SGleb Smirnoff  * The heap supports ordered insert, and extract from the top.
503b3a8eb9SGleb Smirnoff  * To extract an object from the middle of the heap, we the object
513b3a8eb9SGleb Smirnoff  * must reserve an 'int32_t' to store the position of the object
523b3a8eb9SGleb Smirnoff  * in the heap itself, and the location of this field must be
533b3a8eb9SGleb Smirnoff  * passed as an argument to heap_init() -- use -1 if the feature
543b3a8eb9SGleb Smirnoff  * is not used.
553b3a8eb9SGleb Smirnoff  */
563b3a8eb9SGleb Smirnoff struct dn_heap_entry {
573b3a8eb9SGleb Smirnoff 	uint64_t key;	/* sorting key, smallest comes first */
583b3a8eb9SGleb Smirnoff 	void *object;	/* object pointer */
593b3a8eb9SGleb Smirnoff };
603b3a8eb9SGleb Smirnoff 
613b3a8eb9SGleb Smirnoff struct dn_heap {
623b3a8eb9SGleb Smirnoff 	int size;	/* the size of the array */
633b3a8eb9SGleb Smirnoff 	int elements;	/* elements in use */
643b3a8eb9SGleb Smirnoff 	int ofs;	/* offset in the object of heap index */
653b3a8eb9SGleb Smirnoff 	struct dn_heap_entry *p;	/* array of "size" entries */
663b3a8eb9SGleb Smirnoff };
673b3a8eb9SGleb Smirnoff 
683b3a8eb9SGleb Smirnoff enum {
693b3a8eb9SGleb Smirnoff 	HEAP_SCAN_DEL = 1,
703b3a8eb9SGleb Smirnoff 	HEAP_SCAN_END = 2,
713b3a8eb9SGleb Smirnoff };
723b3a8eb9SGleb Smirnoff 
733b3a8eb9SGleb Smirnoff /*
743b3a8eb9SGleb Smirnoff  * heap_init() reinitializes the heap setting the size and the offset
753b3a8eb9SGleb Smirnoff  *	of the index for random extraction (use -1 if not used).
763b3a8eb9SGleb Smirnoff  *	The 'elements' counter is set to 0.
773b3a8eb9SGleb Smirnoff  *
783b3a8eb9SGleb Smirnoff  * SET_HEAP_OFS() indicates where, in the object, is stored the index
793b3a8eb9SGleb Smirnoff  *	for random extractions from the heap.
803b3a8eb9SGleb Smirnoff  *
813b3a8eb9SGleb Smirnoff  * heap_free() frees the memory associated to a heap.
823b3a8eb9SGleb Smirnoff  *
833b3a8eb9SGleb Smirnoff  * heap_insert() adds a key-pointer pair to the heap
843b3a8eb9SGleb Smirnoff  *
853b3a8eb9SGleb Smirnoff  * HEAP_TOP() returns a pointer to the top element of the heap,
86a4641f4eSPedro F. Giffuni  *	but makes no checks on its existence (XXX should we change ?)
873b3a8eb9SGleb Smirnoff  *
88bc64f428SEnji Cooper  * heap_extract() removes the entry at the top, returning the pointer.
893b3a8eb9SGleb Smirnoff  *	(the key should have been read before).
903b3a8eb9SGleb Smirnoff  *
913b3a8eb9SGleb Smirnoff  * heap_scan() invokes a callback on each entry of the heap.
923b3a8eb9SGleb Smirnoff  *	The callback can return a combination of HEAP_SCAN_DEL and
933b3a8eb9SGleb Smirnoff  *	HEAP_SCAN_END. HEAP_SCAN_DEL means the current element must
943b3a8eb9SGleb Smirnoff  *	be removed, and HEAP_SCAN_END means to terminate the scan.
953b3a8eb9SGleb Smirnoff  *	heap_scan() returns the number of elements removed.
963b3a8eb9SGleb Smirnoff  *	Because the order is not guaranteed, we should use heap_scan()
973b3a8eb9SGleb Smirnoff  *	only as a last resort mechanism.
983b3a8eb9SGleb Smirnoff  */
993b3a8eb9SGleb Smirnoff #define HEAP_TOP(h)	((h)->p)
1003b3a8eb9SGleb Smirnoff #define SET_HEAP_OFS(h, n)	do { (h)->ofs = n; } while (0)
1013b3a8eb9SGleb Smirnoff int     heap_init(struct dn_heap *h, int size, int ofs);
1023b3a8eb9SGleb Smirnoff int     heap_insert(struct dn_heap *h, uint64_t key1, void *p);
103*0ba9cb5eSKristof Provost bool    heap_extract(struct dn_heap *h, void *obj);
1043b3a8eb9SGleb Smirnoff void heap_free(struct dn_heap *h);
1053b3a8eb9SGleb Smirnoff int heap_scan(struct dn_heap *, int (*)(void *, uintptr_t), uintptr_t);
1063b3a8eb9SGleb Smirnoff 
1073b3a8eb9SGleb Smirnoff /*------------------------------------------------------
1083b3a8eb9SGleb Smirnoff  * This module implements a generic hash table with support for
1093b3a8eb9SGleb Smirnoff  * running callbacks on the entire table. To avoid allocating
1103b3a8eb9SGleb Smirnoff  * memory during hash table operations, objects must reserve
1113b3a8eb9SGleb Smirnoff  * space for a link field. XXX if the heap is moderately full,
1123b3a8eb9SGleb Smirnoff  * an SLIST suffices, and we can tolerate the cost of a hash
1133b3a8eb9SGleb Smirnoff  * computation on each removal.
1143b3a8eb9SGleb Smirnoff  *
1153b3a8eb9SGleb Smirnoff  * dn_ht_init() initializes the table, setting the number of
1163b3a8eb9SGleb Smirnoff  *	buckets, the offset of the link field, the main callbacks.
1173b3a8eb9SGleb Smirnoff  *	Callbacks are:
1183b3a8eb9SGleb Smirnoff  *
1193b3a8eb9SGleb Smirnoff  *	hash(key, flags, arg) called to return a bucket index.
1203b3a8eb9SGleb Smirnoff  *	match(obj, key, flags, arg) called to determine if key
1213b3a8eb9SGleb Smirnoff  *		matches the current 'obj' in the heap
1223b3a8eb9SGleb Smirnoff  *	newh(key, flags, arg) optional, used to allocate a new
1233b3a8eb9SGleb Smirnoff  *		object during insertions.
1243b3a8eb9SGleb Smirnoff  *
1253b3a8eb9SGleb Smirnoff  * dn_ht_free() frees the heap or unlink elements.
1263b3a8eb9SGleb Smirnoff  *	DNHT_REMOVE unlink elements, 0 frees the heap.
1273b3a8eb9SGleb Smirnoff  *	You need two calls to do both.
1283b3a8eb9SGleb Smirnoff  *
1293b3a8eb9SGleb Smirnoff  * dn_ht_find() is the main lookup function, which can also be
1303b3a8eb9SGleb Smirnoff  *	used to insert or delete elements in the hash table.
1313b3a8eb9SGleb Smirnoff  *	The final 'arg' is passed to all callbacks.
1323b3a8eb9SGleb Smirnoff  *
1333b3a8eb9SGleb Smirnoff  * dn_ht_scan() is used to invoke a callback on all entries of
1343b3a8eb9SGleb Smirnoff  *	the heap, or possibly on just one bucket. The callback
1353b3a8eb9SGleb Smirnoff  *	is invoked with a pointer to the object, and must return
1363b3a8eb9SGleb Smirnoff  *	one of DNHT_SCAN_DEL or DNHT_SCAN_END to request the
1373b3a8eb9SGleb Smirnoff  *	removal of the object from the heap and the end of the
1383b3a8eb9SGleb Smirnoff  *	scan, respectively.
1393b3a8eb9SGleb Smirnoff  *
1403b3a8eb9SGleb Smirnoff  * dn_ht_scan_bucket() is similar to dn_ht_scan(), except that it scans
1413b3a8eb9SGleb Smirnoff  *	only the specific bucket of the table. The bucket is a in-out
1423b3a8eb9SGleb Smirnoff  *	parameter and return a valid bucket number if the original
1433b3a8eb9SGleb Smirnoff  *	is invalid.
1443b3a8eb9SGleb Smirnoff  *
1453b3a8eb9SGleb Smirnoff  * A combination of flags can be used to modify the operation
1463b3a8eb9SGleb Smirnoff  * of the dn_ht_find(), and of the callbacks:
1473b3a8eb9SGleb Smirnoff  *
1483b3a8eb9SGleb Smirnoff  * DNHT_KEY_IS_OBJ	means the key is the object pointer.
149a4641f4eSPedro F. Giffuni  *	It is usually of interest for the hash and match functions.
1503b3a8eb9SGleb Smirnoff  *
1513b3a8eb9SGleb Smirnoff  * DNHT_MATCH_PTR	during a lookup, match pointers instead
1523b3a8eb9SGleb Smirnoff  *	of calling match(). Normally used when removing specific
1533b3a8eb9SGleb Smirnoff  *	entries. Does not imply KEY_IS_OBJ as the latter _is_ used
1543b3a8eb9SGleb Smirnoff  *	by the match function.
1553b3a8eb9SGleb Smirnoff  *
1563b3a8eb9SGleb Smirnoff  * DNHT_INSERT		insert the element if not found.
1573b3a8eb9SGleb Smirnoff  *	Calls new() to allocates a new object unless
1583b3a8eb9SGleb Smirnoff  *	DNHT_KEY_IS_OBJ is set.
1593b3a8eb9SGleb Smirnoff  *
1603b3a8eb9SGleb Smirnoff  * DNHT_UNIQUE		only insert if object not found.
1613b3a8eb9SGleb Smirnoff  *	XXX should it imply DNHT_INSERT ?
1623b3a8eb9SGleb Smirnoff  *
1633b3a8eb9SGleb Smirnoff  * DNHT_REMOVE		remove objects if we find them.
1643b3a8eb9SGleb Smirnoff  */
1653b3a8eb9SGleb Smirnoff struct dn_ht;	/* should be opaque */
1663b3a8eb9SGleb Smirnoff 
1673b3a8eb9SGleb Smirnoff struct dn_ht *dn_ht_init(struct dn_ht *, int buckets, int ofs,
1683b3a8eb9SGleb Smirnoff         uint32_t (*hash)(uintptr_t, int, void *),
1693b3a8eb9SGleb Smirnoff         int (*match)(void *, uintptr_t, int, void *),
1703b3a8eb9SGleb Smirnoff         void *(*newh)(uintptr_t, int, void *));
1713b3a8eb9SGleb Smirnoff void dn_ht_free(struct dn_ht *, int flags);
1723b3a8eb9SGleb Smirnoff 
1733b3a8eb9SGleb Smirnoff void *dn_ht_find(struct dn_ht *, uintptr_t, int, void *);
1743b3a8eb9SGleb Smirnoff int dn_ht_scan(struct dn_ht *, int (*)(void *, void *), void *);
1753b3a8eb9SGleb Smirnoff int dn_ht_scan_bucket(struct dn_ht *, int * , int (*)(void *, void *), void *);
1763b3a8eb9SGleb Smirnoff int dn_ht_entries(struct dn_ht *);
1773b3a8eb9SGleb Smirnoff 
1783b3a8eb9SGleb Smirnoff enum {  /* flags values.
1793b3a8eb9SGleb Smirnoff 	 * first two are returned by the scan callback to indicate
1803b3a8eb9SGleb Smirnoff 	 * to delete the matching element or to end the scan
1813b3a8eb9SGleb Smirnoff 	 */
1823b3a8eb9SGleb Smirnoff         DNHT_SCAN_DEL	= 0x0001,
1833b3a8eb9SGleb Smirnoff         DNHT_SCAN_END	= 0x0002,
1843b3a8eb9SGleb Smirnoff         DNHT_KEY_IS_OBJ	= 0x0004,	/* key is the obj pointer */
1853b3a8eb9SGleb Smirnoff         DNHT_MATCH_PTR	= 0x0008,	/* match by pointer, not match() */
1863b3a8eb9SGleb Smirnoff         DNHT_INSERT	= 0x0010,	/* insert if not found */
1873b3a8eb9SGleb Smirnoff         DNHT_UNIQUE	= 0x0020,	/* report error if already there */
1883b3a8eb9SGleb Smirnoff         DNHT_REMOVE	= 0x0040,	/* remove on find or dn_ht_free */
1893b3a8eb9SGleb Smirnoff };
1903b3a8eb9SGleb Smirnoff 
1913b3a8eb9SGleb Smirnoff #endif /* _IP_DN_HEAP_H */
192