xref: /aosp_15_r20/external/libnl/lib/hashtable.c (revision 4dc78e53d49367fa8e61b07018507c90983a077d)
1*4dc78e53SAndroid Build Coastguard Worker /* SPDX-License-Identifier: LGPL-2.1-only */
2*4dc78e53SAndroid Build Coastguard Worker /*
3*4dc78e53SAndroid Build Coastguard Worker  * Copyright (c) 2012 Cumulus Networks, Inc
4*4dc78e53SAndroid Build Coastguard Worker  */
5*4dc78e53SAndroid Build Coastguard Worker 
6*4dc78e53SAndroid Build Coastguard Worker #include "nl-default.h"
7*4dc78e53SAndroid Build Coastguard Worker 
8*4dc78e53SAndroid Build Coastguard Worker #include <netlink/object.h>
9*4dc78e53SAndroid Build Coastguard Worker #include <netlink/hash.h>
10*4dc78e53SAndroid Build Coastguard Worker #include <netlink/hashtable.h>
11*4dc78e53SAndroid Build Coastguard Worker 
12*4dc78e53SAndroid Build Coastguard Worker #include "nl-aux-core/nl-core.h"
13*4dc78e53SAndroid Build Coastguard Worker 
14*4dc78e53SAndroid Build Coastguard Worker /**
15*4dc78e53SAndroid Build Coastguard Worker  * @ingroup core_types
16*4dc78e53SAndroid Build Coastguard Worker  * @defgroup hashtable Hashtable
17*4dc78e53SAndroid Build Coastguard Worker  * @{
18*4dc78e53SAndroid Build Coastguard Worker  */
19*4dc78e53SAndroid Build Coastguard Worker 
20*4dc78e53SAndroid Build Coastguard Worker /**
21*4dc78e53SAndroid Build Coastguard Worker  * Allocate hashtable
22*4dc78e53SAndroid Build Coastguard Worker  * @arg size		Size of hashtable in number of elements
23*4dc78e53SAndroid Build Coastguard Worker  *
24*4dc78e53SAndroid Build Coastguard Worker  * @return Allocated hashtable or NULL.
25*4dc78e53SAndroid Build Coastguard Worker  */
nl_hash_table_alloc(int size)26*4dc78e53SAndroid Build Coastguard Worker nl_hash_table_t *nl_hash_table_alloc(int size)
27*4dc78e53SAndroid Build Coastguard Worker {
28*4dc78e53SAndroid Build Coastguard Worker 	nl_hash_table_t *ht;
29*4dc78e53SAndroid Build Coastguard Worker 
30*4dc78e53SAndroid Build Coastguard Worker 	ht = calloc(1, sizeof (*ht));
31*4dc78e53SAndroid Build Coastguard Worker 	if (!ht)
32*4dc78e53SAndroid Build Coastguard Worker 		goto errout;
33*4dc78e53SAndroid Build Coastguard Worker 
34*4dc78e53SAndroid Build Coastguard Worker 	ht->nodes = calloc(size, sizeof (*ht->nodes));
35*4dc78e53SAndroid Build Coastguard Worker 	if (!ht->nodes) {
36*4dc78e53SAndroid Build Coastguard Worker 		free(ht);
37*4dc78e53SAndroid Build Coastguard Worker 		goto errout;
38*4dc78e53SAndroid Build Coastguard Worker 	}
39*4dc78e53SAndroid Build Coastguard Worker 
40*4dc78e53SAndroid Build Coastguard Worker 	ht->size = size;
41*4dc78e53SAndroid Build Coastguard Worker 
42*4dc78e53SAndroid Build Coastguard Worker 	return ht;
43*4dc78e53SAndroid Build Coastguard Worker errout:
44*4dc78e53SAndroid Build Coastguard Worker 	return NULL;
45*4dc78e53SAndroid Build Coastguard Worker }
46*4dc78e53SAndroid Build Coastguard Worker 
47*4dc78e53SAndroid Build Coastguard Worker /**
48*4dc78e53SAndroid Build Coastguard Worker  * Free hashtable including all nodes
49*4dc78e53SAndroid Build Coastguard Worker  * @arg ht		Hashtable
50*4dc78e53SAndroid Build Coastguard Worker  *
51*4dc78e53SAndroid Build Coastguard Worker  * @note Reference counter of all objects in the hashtable will be decremented.
52*4dc78e53SAndroid Build Coastguard Worker  */
nl_hash_table_free(nl_hash_table_t * ht)53*4dc78e53SAndroid Build Coastguard Worker void nl_hash_table_free(nl_hash_table_t *ht)
54*4dc78e53SAndroid Build Coastguard Worker {
55*4dc78e53SAndroid Build Coastguard Worker 	int i;
56*4dc78e53SAndroid Build Coastguard Worker 
57*4dc78e53SAndroid Build Coastguard Worker 	for(i = 0; i < ht->size; i++) {
58*4dc78e53SAndroid Build Coastguard Worker 		nl_hash_node_t *node = ht->nodes[i];
59*4dc78e53SAndroid Build Coastguard Worker 		nl_hash_node_t *saved_node;
60*4dc78e53SAndroid Build Coastguard Worker 
61*4dc78e53SAndroid Build Coastguard Worker 		while (node) {
62*4dc78e53SAndroid Build Coastguard Worker 			saved_node = node;
63*4dc78e53SAndroid Build Coastguard Worker 			node = node->next;
64*4dc78e53SAndroid Build Coastguard Worker 			nl_object_put(saved_node->obj);
65*4dc78e53SAndroid Build Coastguard Worker 			free(saved_node);
66*4dc78e53SAndroid Build Coastguard Worker 		}
67*4dc78e53SAndroid Build Coastguard Worker 	}
68*4dc78e53SAndroid Build Coastguard Worker 
69*4dc78e53SAndroid Build Coastguard Worker 	free(ht->nodes);
70*4dc78e53SAndroid Build Coastguard Worker 	free(ht);
71*4dc78e53SAndroid Build Coastguard Worker }
72*4dc78e53SAndroid Build Coastguard Worker 
73*4dc78e53SAndroid Build Coastguard Worker /**
74*4dc78e53SAndroid Build Coastguard Worker  * Lookup identical object in hashtable
75*4dc78e53SAndroid Build Coastguard Worker  * @arg ht		Hashtable
76*4dc78e53SAndroid Build Coastguard Worker  * @arg	obj		Object to lookup
77*4dc78e53SAndroid Build Coastguard Worker  *
78*4dc78e53SAndroid Build Coastguard Worker  * Generates hashkey for `obj` and traverses the corresponding chain calling
79*4dc78e53SAndroid Build Coastguard Worker  * `nl_object_identical()` on each trying to find a match.
80*4dc78e53SAndroid Build Coastguard Worker  *
81*4dc78e53SAndroid Build Coastguard Worker  * @return Pointer to object if match was found or NULL.
82*4dc78e53SAndroid Build Coastguard Worker  */
nl_hash_table_lookup(nl_hash_table_t * ht,struct nl_object * obj)83*4dc78e53SAndroid Build Coastguard Worker struct nl_object* nl_hash_table_lookup(nl_hash_table_t *ht,
84*4dc78e53SAndroid Build Coastguard Worker 				       struct nl_object *obj)
85*4dc78e53SAndroid Build Coastguard Worker {
86*4dc78e53SAndroid Build Coastguard Worker 	nl_hash_node_t *node;
87*4dc78e53SAndroid Build Coastguard Worker 	uint32_t key_hash;
88*4dc78e53SAndroid Build Coastguard Worker 
89*4dc78e53SAndroid Build Coastguard Worker 	nl_object_keygen(obj, &key_hash, ht->size);
90*4dc78e53SAndroid Build Coastguard Worker 	node = ht->nodes[key_hash];
91*4dc78e53SAndroid Build Coastguard Worker 
92*4dc78e53SAndroid Build Coastguard Worker 	while (node) {
93*4dc78e53SAndroid Build Coastguard Worker 		if (nl_object_identical(node->obj, obj))
94*4dc78e53SAndroid Build Coastguard Worker 			return node->obj;
95*4dc78e53SAndroid Build Coastguard Worker 		node = node->next;
96*4dc78e53SAndroid Build Coastguard Worker 	}
97*4dc78e53SAndroid Build Coastguard Worker 
98*4dc78e53SAndroid Build Coastguard Worker 	return NULL;
99*4dc78e53SAndroid Build Coastguard Worker }
100*4dc78e53SAndroid Build Coastguard Worker 
101*4dc78e53SAndroid Build Coastguard Worker /**
102*4dc78e53SAndroid Build Coastguard Worker  * Add object to hashtable
103*4dc78e53SAndroid Build Coastguard Worker  * @arg ht		Hashtable
104*4dc78e53SAndroid Build Coastguard Worker  * @arg obj		Object to add
105*4dc78e53SAndroid Build Coastguard Worker  *
106*4dc78e53SAndroid Build Coastguard Worker  * Adds `obj` to the hashtable. Object type must support hashing, otherwise all
107*4dc78e53SAndroid Build Coastguard Worker  * objects will be added to the chain `0`.
108*4dc78e53SAndroid Build Coastguard Worker  *
109*4dc78e53SAndroid Build Coastguard Worker  * @note The reference counter of the object is incremented.
110*4dc78e53SAndroid Build Coastguard Worker  *
111*4dc78e53SAndroid Build Coastguard Worker  * @return 0 on success or a negative error code
112*4dc78e53SAndroid Build Coastguard Worker  * @retval -NLE_EXIST Identical object already present in hashtable
113*4dc78e53SAndroid Build Coastguard Worker  */
nl_hash_table_add(nl_hash_table_t * ht,struct nl_object * obj)114*4dc78e53SAndroid Build Coastguard Worker int nl_hash_table_add(nl_hash_table_t *ht, struct nl_object *obj)
115*4dc78e53SAndroid Build Coastguard Worker {
116*4dc78e53SAndroid Build Coastguard Worker 	nl_hash_node_t *node;
117*4dc78e53SAndroid Build Coastguard Worker 	uint32_t key_hash;
118*4dc78e53SAndroid Build Coastguard Worker 
119*4dc78e53SAndroid Build Coastguard Worker 	nl_object_keygen(obj, &key_hash, ht->size);
120*4dc78e53SAndroid Build Coastguard Worker 	node = ht->nodes[key_hash];
121*4dc78e53SAndroid Build Coastguard Worker 
122*4dc78e53SAndroid Build Coastguard Worker 	while (node) {
123*4dc78e53SAndroid Build Coastguard Worker 		if (nl_object_identical(node->obj, obj)) {
124*4dc78e53SAndroid Build Coastguard Worker 			NL_DBG(2, "Warning: Add to hashtable found duplicate...\n");
125*4dc78e53SAndroid Build Coastguard Worker 			return -NLE_EXIST;
126*4dc78e53SAndroid Build Coastguard Worker 		}
127*4dc78e53SAndroid Build Coastguard Worker 		node = node->next;
128*4dc78e53SAndroid Build Coastguard Worker 	}
129*4dc78e53SAndroid Build Coastguard Worker 
130*4dc78e53SAndroid Build Coastguard Worker 	NL_DBG (5, "adding cache entry of obj %p in table %p, with hash 0x%x\n",
131*4dc78e53SAndroid Build Coastguard Worker 		obj, ht, key_hash);
132*4dc78e53SAndroid Build Coastguard Worker 
133*4dc78e53SAndroid Build Coastguard Worker 	node = malloc(sizeof(nl_hash_node_t));
134*4dc78e53SAndroid Build Coastguard Worker 	if (!node)
135*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_NOMEM;
136*4dc78e53SAndroid Build Coastguard Worker 	nl_object_get(obj);
137*4dc78e53SAndroid Build Coastguard Worker 	node->obj = obj;
138*4dc78e53SAndroid Build Coastguard Worker 	node->key = key_hash;
139*4dc78e53SAndroid Build Coastguard Worker 	node->key_size = sizeof(uint32_t);
140*4dc78e53SAndroid Build Coastguard Worker 	node->next = ht->nodes[key_hash];
141*4dc78e53SAndroid Build Coastguard Worker 	ht->nodes[key_hash] = node;
142*4dc78e53SAndroid Build Coastguard Worker 
143*4dc78e53SAndroid Build Coastguard Worker 	return 0;
144*4dc78e53SAndroid Build Coastguard Worker }
145*4dc78e53SAndroid Build Coastguard Worker 
146*4dc78e53SAndroid Build Coastguard Worker /**
147*4dc78e53SAndroid Build Coastguard Worker  * Remove object from hashtable
148*4dc78e53SAndroid Build Coastguard Worker  * @arg ht		Hashtable
149*4dc78e53SAndroid Build Coastguard Worker  * @arg obj		Object to remove
150*4dc78e53SAndroid Build Coastguard Worker  *
151*4dc78e53SAndroid Build Coastguard Worker  * Remove `obj` from hashtable if it exists.
152*4dc78e53SAndroid Build Coastguard Worker  *
153*4dc78e53SAndroid Build Coastguard Worker  * @note Reference counter of object will be decremented.
154*4dc78e53SAndroid Build Coastguard Worker  *
155*4dc78e53SAndroid Build Coastguard Worker  * @return 0 on success or a negative error code.
156*4dc78e53SAndroid Build Coastguard Worker  * @retval -NLE_OBJ_NOTFOUND Object not present in hashtable.
157*4dc78e53SAndroid Build Coastguard Worker  */
nl_hash_table_del(nl_hash_table_t * ht,struct nl_object * obj)158*4dc78e53SAndroid Build Coastguard Worker int nl_hash_table_del(nl_hash_table_t *ht, struct nl_object *obj)
159*4dc78e53SAndroid Build Coastguard Worker {
160*4dc78e53SAndroid Build Coastguard Worker 	nl_hash_node_t *node, *prev;
161*4dc78e53SAndroid Build Coastguard Worker 	uint32_t key_hash;
162*4dc78e53SAndroid Build Coastguard Worker 
163*4dc78e53SAndroid Build Coastguard Worker 	nl_object_keygen(obj, &key_hash, ht->size);
164*4dc78e53SAndroid Build Coastguard Worker 	prev = node = ht->nodes[key_hash];
165*4dc78e53SAndroid Build Coastguard Worker 
166*4dc78e53SAndroid Build Coastguard Worker 	while (node) {
167*4dc78e53SAndroid Build Coastguard Worker 		if (nl_object_identical(node->obj, obj)) {
168*4dc78e53SAndroid Build Coastguard Worker 			nl_object_put(obj);
169*4dc78e53SAndroid Build Coastguard Worker 
170*4dc78e53SAndroid Build Coastguard Worker 			NL_DBG (5, "deleting cache entry of obj %p in table %p, with"
171*4dc78e53SAndroid Build Coastguard Worker 			        " hash 0x%x\n", obj, ht, key_hash);
172*4dc78e53SAndroid Build Coastguard Worker 
173*4dc78e53SAndroid Build Coastguard Worker 			if (node == ht->nodes[key_hash])
174*4dc78e53SAndroid Build Coastguard Worker 				ht->nodes[key_hash] = node->next;
175*4dc78e53SAndroid Build Coastguard Worker 			else
176*4dc78e53SAndroid Build Coastguard Worker 				prev->next = node->next;
177*4dc78e53SAndroid Build Coastguard Worker 
178*4dc78e53SAndroid Build Coastguard Worker 			free(node);
179*4dc78e53SAndroid Build Coastguard Worker 
180*4dc78e53SAndroid Build Coastguard Worker 			return 0;
181*4dc78e53SAndroid Build Coastguard Worker 		}
182*4dc78e53SAndroid Build Coastguard Worker 		prev = node;
183*4dc78e53SAndroid Build Coastguard Worker 		node = node->next;
184*4dc78e53SAndroid Build Coastguard Worker 	}
185*4dc78e53SAndroid Build Coastguard Worker 
186*4dc78e53SAndroid Build Coastguard Worker 	return -NLE_OBJ_NOTFOUND;
187*4dc78e53SAndroid Build Coastguard Worker }
188*4dc78e53SAndroid Build Coastguard Worker 
nl_hash(void * k,size_t length,uint32_t initval)189*4dc78e53SAndroid Build Coastguard Worker uint32_t nl_hash(void *k, size_t length, uint32_t initval)
190*4dc78e53SAndroid Build Coastguard Worker {
191*4dc78e53SAndroid Build Coastguard Worker 	return(__nl_hash((char *) k, length, initval));
192*4dc78e53SAndroid Build Coastguard Worker }
193*4dc78e53SAndroid Build Coastguard Worker 
194*4dc78e53SAndroid Build Coastguard Worker /** @} */
195