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