Mon 14 Oct 23:06:38 CEST 2024
This commit is contained in:
		
							parent
							
								
									28d3407af5
								
							
						
					
					
						commit
						45aa067b85
					
				
							
								
								
									
										185
									
								
								kernel/hash_set.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										185
									
								
								kernel/hash_set.c
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,185 @@ | ||||||
|  | /*
 | ||||||
|  | Copyright (C) 2016-2019 The University of Notre Dame | ||||||
|  | This software is distributed under the GNU General Public License. | ||||||
|  | See the file LICENSE for details. | ||||||
|  | */ | ||||||
|  | 
 | ||||||
|  | #include "string.h" | ||||||
|  | #include "hash_set.h" | ||||||
|  | #include "kmalloc.h" | ||||||
|  | 
 | ||||||
|  | #define HASHTABLE_PRIME 31 | ||||||
|  | #define HASHTABLE_GOLDEN_RATIO 0x61C88647 | ||||||
|  | 
 | ||||||
|  | struct hash_set { | ||||||
|  | 	unsigned total_buckets; | ||||||
|  | 	unsigned num_entries; | ||||||
|  | 	struct hash_set_node **head; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct hash_set_node { | ||||||
|  | 	unsigned key; | ||||||
|  | 	void *data; | ||||||
|  | 	struct hash_set_node *next; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | unsigned hash_string(char *string, unsigned range_min, unsigned range_max) | ||||||
|  | { | ||||||
|  | 	unsigned hash = HASHTABLE_PRIME; | ||||||
|  | 	char *curr = string; | ||||||
|  | 	while(*curr) { | ||||||
|  | 		hash = HASHTABLE_PRIME * hash + *curr; | ||||||
|  | 		curr++; | ||||||
|  | 	} | ||||||
|  | 	return (hash % (range_max - range_min)) + range_min; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static unsigned hash_uint(unsigned key, unsigned buckets) | ||||||
|  | { | ||||||
|  | 	return key * HASHTABLE_GOLDEN_RATIO % buckets; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static unsigned hash_set_list_add(struct hash_set_node **head, struct hash_set_node *node) | ||||||
|  | { | ||||||
|  | 	struct hash_set_node *prev = 0, *curr = *head; | ||||||
|  | 	if(!curr) { | ||||||
|  | 		*head = node; | ||||||
|  | 		return 0; | ||||||
|  | 	} | ||||||
|  | 	while(curr && (curr->key < node->key)) { | ||||||
|  | 		prev = curr; | ||||||
|  | 		curr = curr->next; | ||||||
|  | 	} | ||||||
|  | 	if(!prev && curr->key != node->key) { | ||||||
|  | 		node->next = *head; | ||||||
|  | 		*head = node; | ||||||
|  | 		return 0; | ||||||
|  | 	} else if(!curr) { | ||||||
|  | 		prev->next = node; | ||||||
|  | 		return 0; | ||||||
|  | 	} else if(curr->key != node->key) { | ||||||
|  | 		node->next = curr->next; | ||||||
|  | 		curr->next = node; | ||||||
|  | 		return 0; | ||||||
|  | 	} | ||||||
|  | 	return -1; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static struct hash_set_node *hash_set_list_lookup(struct hash_set_node *head, unsigned key) | ||||||
|  | { | ||||||
|  | 	struct hash_set_node *curr = head; | ||||||
|  | 	while(curr && (curr->key < key)) { | ||||||
|  | 		curr = curr->next; | ||||||
|  | 	} | ||||||
|  | 	return (curr && (curr->key == key)) ? curr : 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static unsigned hash_set_list_delete(struct hash_set_node **head, unsigned key) | ||||||
|  | { | ||||||
|  | 	struct hash_set_node *prev = 0, *curr = *head; | ||||||
|  | 	while(curr && (curr->key < key)) { | ||||||
|  | 		prev = curr; | ||||||
|  | 		curr = curr->next; | ||||||
|  | 	} | ||||||
|  | 	if(curr && (curr->key == key)) { | ||||||
|  | 		if(prev) | ||||||
|  | 			prev->next = curr->next; | ||||||
|  | 		if(curr == *head) | ||||||
|  | 			*head = curr->next; | ||||||
|  | 		kfree(curr); | ||||||
|  | 		return 0; | ||||||
|  | 	} | ||||||
|  | 	return -1; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | struct hash_set *hash_set_create(unsigned buckets) | ||||||
|  | { | ||||||
|  | 	struct hash_set_node **set_nodes = kmalloc(sizeof(struct hash_set_node *) * buckets); | ||||||
|  | 	struct hash_set *set = kmalloc(sizeof(struct hash_set)); | ||||||
|  | 	memset(set_nodes, 0, sizeof(struct hash_set_node *) * buckets); | ||||||
|  | 
 | ||||||
|  | 	set->total_buckets = buckets; | ||||||
|  | 	set->head = set_nodes; | ||||||
|  | 	set->num_entries = 0; | ||||||
|  | 
 | ||||||
|  | 	if(!set || !set_nodes) { | ||||||
|  | 		hash_set_delete(set); | ||||||
|  | 		return 0; | ||||||
|  | 	} | ||||||
|  | 	return set; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static unsigned hash_set_list_dealloc(struct hash_set_node *head) | ||||||
|  | { | ||||||
|  | 	struct hash_set_node *next = head, *curr = head; | ||||||
|  | 	while(curr) { | ||||||
|  | 		next = curr->next; | ||||||
|  | 		kfree(curr); | ||||||
|  | 		curr = next; | ||||||
|  | 	} | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void hash_set_delete(struct hash_set *set) | ||||||
|  | { | ||||||
|  | 	struct hash_set_node **set_nodes = set->head; | ||||||
|  | 	if(set) | ||||||
|  | 		kfree(set); | ||||||
|  | 	if(set_nodes) { | ||||||
|  | 		unsigned i; | ||||||
|  | 		for(i = 0; i < set->total_buckets; i++) | ||||||
|  | 			hash_set_list_dealloc(set->head[i]); | ||||||
|  | 		kfree(set_nodes); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | unsigned hash_set_add(struct hash_set *set, unsigned key, void *data) | ||||||
|  | { | ||||||
|  | 	unsigned hash_key = hash_uint(key, set->total_buckets); | ||||||
|  | 	struct hash_set_node *node = kmalloc(sizeof(struct hash_set_node)); | ||||||
|  | 	node->key = key; | ||||||
|  | 	node->data = data; | ||||||
|  | 	node->next = 0; | ||||||
|  | 	unsigned ret = hash_set_list_add(&(set->head[hash_key]), node); | ||||||
|  | 	if(ret == 0) | ||||||
|  | 		set->num_entries++; | ||||||
|  | 	return ret; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void * hash_set_lookup(struct hash_set * set, unsigned key) | ||||||
|  | { | ||||||
|  | 	unsigned hash_key = hash_uint(key, set->total_buckets); | ||||||
|  | 	struct hash_set_node *result = hash_set_list_lookup(set->head[hash_key], key); | ||||||
|  | 	if(result) { | ||||||
|  | 		return result->data; | ||||||
|  | 	} else { | ||||||
|  | 		return 0; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | unsigned hash_set_remove(struct hash_set *set, unsigned key) | ||||||
|  | { | ||||||
|  | 	unsigned hash_key = hash_uint(key, set->total_buckets); | ||||||
|  | 	unsigned result = hash_set_list_delete(&(set->head[hash_key]), key); | ||||||
|  | 	if(result == 0) | ||||||
|  | 		set->num_entries--; | ||||||
|  | 	return result; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | unsigned hash_set_entries( struct hash_set *set ) | ||||||
|  | { | ||||||
|  | 	return set->num_entries; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void hash_set_print(struct hash_set *set) | ||||||
|  | { | ||||||
|  | 	unsigned i; | ||||||
|  | 	printf("printing hash set:\n"); | ||||||
|  | 	for(i = 0; i < set->total_buckets; i++) { | ||||||
|  | 		struct hash_set_node *start = set->head[i]; | ||||||
|  | 		while(start) { | ||||||
|  | 			printf("%u: %u\n", i, start->key); | ||||||
|  | 			start = start->next; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user