| Hisham Muhammad | d6231ba | 2006-03-04 18:16:49 +0000 | [diff] [blame] | 1 | /* |
| Hisham Muhammad | 84281bd | 2011-12-26 21:35:57 +0000 | [diff] [blame] | 2 | htop - Hashtable.c |
| Hisham Muhammad | 300caa0 | 2011-05-26 16:35:07 +0000 | [diff] [blame] | 3 | (C) 2004-2011 Hisham H. Muhammad |
| Hisham Muhammad | d6231ba | 2006-03-04 18:16:49 +0000 | [diff] [blame] | 4 | Released under the GNU GPL, see the COPYING file |
| 5 | in the source distribution for its full text. |
| 6 | */ |
| 7 | |
| 8 | #include "Hashtable.h" |
| 9 | |
| Hisham Muhammad | 84281bd | 2011-12-26 21:35:57 +0000 | [diff] [blame] | 10 | #include <stdlib.h> |
| 11 | #include <assert.h> |
| 12 | |
| Hisham Muhammad | d6231ba | 2006-03-04 18:16:49 +0000 | [diff] [blame] | 13 | /*{ |
| Hisham Muhammad | 84281bd | 2011-12-26 21:35:57 +0000 | [diff] [blame] | 14 | #include <stdbool.h> |
| 15 | |
| Hisham Muhammad | d6231ba | 2006-03-04 18:16:49 +0000 | [diff] [blame] | 16 | typedef struct Hashtable_ Hashtable; |
| 17 | |
| 18 | typedef void(*Hashtable_PairFunction)(int, void*, void*); |
| Hisham Muhammad | d6231ba | 2006-03-04 18:16:49 +0000 | [diff] [blame] | 19 | |
| 20 | typedef struct HashtableItem { |
| Hisham Muhammad | a227b20 | 2007-04-05 19:53:23 +0000 | [diff] [blame] | 21 | unsigned int key; |
| Hisham Muhammad | d6231ba | 2006-03-04 18:16:49 +0000 | [diff] [blame] | 22 | void* value; |
| 23 | struct HashtableItem* next; |
| 24 | } HashtableItem; |
| 25 | |
| 26 | struct Hashtable_ { |
| 27 | int size; |
| 28 | HashtableItem** buckets; |
| 29 | int items; |
| Hisham Muhammad | d6231ba | 2006-03-04 18:16:49 +0000 | [diff] [blame] | 30 | bool owner; |
| 31 | }; |
| 32 | }*/ |
| 33 | |
| Hisham Muhammad | 110ce71 | 2006-11-08 20:09:48 +0000 | [diff] [blame] | 34 | #ifdef DEBUG |
| 35 | |
| Hisham Muhammad | da23c8c | 2008-03-09 08:58:38 +0000 | [diff] [blame] | 36 | static bool Hashtable_isConsistent(Hashtable* this) { |
| Hisham Muhammad | 110ce71 | 2006-11-08 20:09:48 +0000 | [diff] [blame] | 37 | int items = 0; |
| 38 | for (int i = 0; i < this->size; i++) { |
| 39 | HashtableItem* bucket = this->buckets[i]; |
| 40 | while (bucket) { |
| 41 | items++; |
| 42 | bucket = bucket->next; |
| 43 | } |
| 44 | } |
| 45 | return items == this->items; |
| 46 | } |
| 47 | |
| Hisham Muhammad | 3684849 | 2006-11-12 21:52:14 +0000 | [diff] [blame] | 48 | int Hashtable_count(Hashtable* this) { |
| 49 | int items = 0; |
| 50 | for (int i = 0; i < this->size; i++) { |
| 51 | HashtableItem* bucket = this->buckets[i]; |
| 52 | while (bucket) { |
| 53 | items++; |
| 54 | bucket = bucket->next; |
| 55 | } |
| 56 | } |
| 57 | assert(items == this->items); |
| 58 | return items; |
| 59 | } |
| 60 | |
| Hisham Muhammad | 110ce71 | 2006-11-08 20:09:48 +0000 | [diff] [blame] | 61 | #endif |
| 62 | |
| Hisham Muhammad | da23c8c | 2008-03-09 08:58:38 +0000 | [diff] [blame] | 63 | static HashtableItem* HashtableItem_new(unsigned int key, void* value) { |
| Hisham Muhammad | d6231ba | 2006-03-04 18:16:49 +0000 | [diff] [blame] | 64 | HashtableItem* this; |
| 65 | |
| 66 | this = (HashtableItem*) malloc(sizeof(HashtableItem)); |
| 67 | this->key = key; |
| 68 | this->value = value; |
| 69 | this->next = NULL; |
| 70 | return this; |
| 71 | } |
| 72 | |
| 73 | Hashtable* Hashtable_new(int size, bool owner) { |
| 74 | Hashtable* this; |
| 75 | |
| 76 | this = (Hashtable*) malloc(sizeof(Hashtable)); |
| Hisham Muhammad | 110ce71 | 2006-11-08 20:09:48 +0000 | [diff] [blame] | 77 | this->items = 0; |
| Hisham Muhammad | d6231ba | 2006-03-04 18:16:49 +0000 | [diff] [blame] | 78 | this->size = size; |
| Hisham Muhammad | 76a715e | 2014-01-16 18:51:16 -0200 | [diff] [blame] | 79 | this->buckets = (HashtableItem**) calloc(size, sizeof(HashtableItem*)); |
| Hisham Muhammad | d6231ba | 2006-03-04 18:16:49 +0000 | [diff] [blame] | 80 | this->owner = owner; |
| Hisham Muhammad | 110ce71 | 2006-11-08 20:09:48 +0000 | [diff] [blame] | 81 | assert(Hashtable_isConsistent(this)); |
| Hisham Muhammad | d6231ba | 2006-03-04 18:16:49 +0000 | [diff] [blame] | 82 | return this; |
| 83 | } |
| 84 | |
| Hisham Muhammad | d6231ba | 2006-03-04 18:16:49 +0000 | [diff] [blame] | 85 | void Hashtable_delete(Hashtable* this) { |
| Hisham Muhammad | 110ce71 | 2006-11-08 20:09:48 +0000 | [diff] [blame] | 86 | assert(Hashtable_isConsistent(this)); |
| Hisham Muhammad | d6231ba | 2006-03-04 18:16:49 +0000 | [diff] [blame] | 87 | for (int i = 0; i < this->size; i++) { |
| 88 | HashtableItem* walk = this->buckets[i]; |
| 89 | while (walk != NULL) { |
| 90 | if (this->owner) |
| 91 | free(walk->value); |
| 92 | HashtableItem* savedWalk = walk; |
| 93 | walk = savedWalk->next; |
| 94 | free(savedWalk); |
| 95 | } |
| 96 | } |
| 97 | free(this->buckets); |
| 98 | free(this); |
| 99 | } |
| 100 | |
| Hisham Muhammad | a227b20 | 2007-04-05 19:53:23 +0000 | [diff] [blame] | 101 | void Hashtable_put(Hashtable* this, unsigned int key, void* value) { |
| 102 | unsigned int index = key % this->size; |
| Hisham Muhammad | d6231ba | 2006-03-04 18:16:49 +0000 | [diff] [blame] | 103 | HashtableItem** bucketPtr = &(this->buckets[index]); |
| 104 | while (true) |
| 105 | if (*bucketPtr == NULL) { |
| 106 | *bucketPtr = HashtableItem_new(key, value); |
| 107 | this->items++; |
| 108 | break; |
| 109 | } else if ((*bucketPtr)->key == key) { |
| 110 | if (this->owner) |
| 111 | free((*bucketPtr)->value); |
| 112 | (*bucketPtr)->value = value; |
| 113 | break; |
| 114 | } else |
| 115 | bucketPtr = &((*bucketPtr)->next); |
| Hisham Muhammad | 110ce71 | 2006-11-08 20:09:48 +0000 | [diff] [blame] | 116 | assert(Hashtable_isConsistent(this)); |
| Hisham Muhammad | d6231ba | 2006-03-04 18:16:49 +0000 | [diff] [blame] | 117 | } |
| 118 | |
| Hisham Muhammad | a227b20 | 2007-04-05 19:53:23 +0000 | [diff] [blame] | 119 | void* Hashtable_remove(Hashtable* this, unsigned int key) { |
| 120 | unsigned int index = key % this->size; |
| Hisham Muhammad | 110ce71 | 2006-11-08 20:09:48 +0000 | [diff] [blame] | 121 | |
| 122 | assert(Hashtable_isConsistent(this)); |
| 123 | |
| 124 | HashtableItem** bucket; |
| 125 | for (bucket = &(this->buckets[index]); *bucket; bucket = &((*bucket)->next) ) { |
| 126 | if ((*bucket)->key == key) { |
| 127 | void* value = (*bucket)->value; |
| 128 | HashtableItem* next = (*bucket)->next; |
| 129 | free(*bucket); |
| 130 | (*bucket) = next; |
| Hisham Muhammad | d6231ba | 2006-03-04 18:16:49 +0000 | [diff] [blame] | 131 | this->items--; |
| 132 | if (this->owner) { |
| Hisham Muhammad | 110ce71 | 2006-11-08 20:09:48 +0000 | [diff] [blame] | 133 | free(value); |
| 134 | assert(Hashtable_isConsistent(this)); |
| Hisham Muhammad | d6231ba | 2006-03-04 18:16:49 +0000 | [diff] [blame] | 135 | return NULL; |
| 136 | } else { |
| Hisham Muhammad | 110ce71 | 2006-11-08 20:09:48 +0000 | [diff] [blame] | 137 | assert(Hashtable_isConsistent(this)); |
| 138 | return value; |
| Hisham Muhammad | d6231ba | 2006-03-04 18:16:49 +0000 | [diff] [blame] | 139 | } |
| Hisham Muhammad | 110ce71 | 2006-11-08 20:09:48 +0000 | [diff] [blame] | 140 | } |
| 141 | } |
| 142 | assert(Hashtable_isConsistent(this)); |
| 143 | return NULL; |
| Hisham Muhammad | d6231ba | 2006-03-04 18:16:49 +0000 | [diff] [blame] | 144 | } |
| Hisham Muhammad | 110ce71 | 2006-11-08 20:09:48 +0000 | [diff] [blame] | 145 | |
| Hisham Muhammad | a227b20 | 2007-04-05 19:53:23 +0000 | [diff] [blame] | 146 | inline void* Hashtable_get(Hashtable* this, unsigned int key) { |
| 147 | unsigned int index = key % this->size; |
| Hisham Muhammad | d6231ba | 2006-03-04 18:16:49 +0000 | [diff] [blame] | 148 | HashtableItem* bucketPtr = this->buckets[index]; |
| Hisham Muhammad | 5d48ab8 | 2006-07-11 06:13:32 +0000 | [diff] [blame] | 149 | while (true) { |
| Hisham Muhammad | d6231ba | 2006-03-04 18:16:49 +0000 | [diff] [blame] | 150 | if (bucketPtr == NULL) { |
| Hisham Muhammad | 110ce71 | 2006-11-08 20:09:48 +0000 | [diff] [blame] | 151 | assert(Hashtable_isConsistent(this)); |
| Hisham Muhammad | d6231ba | 2006-03-04 18:16:49 +0000 | [diff] [blame] | 152 | return NULL; |
| 153 | } else if (bucketPtr->key == key) { |
| Hisham Muhammad | 110ce71 | 2006-11-08 20:09:48 +0000 | [diff] [blame] | 154 | assert(Hashtable_isConsistent(this)); |
| Hisham Muhammad | d6231ba | 2006-03-04 18:16:49 +0000 | [diff] [blame] | 155 | return bucketPtr->value; |
| 156 | } else |
| 157 | bucketPtr = bucketPtr->next; |
| Hisham Muhammad | 5d48ab8 | 2006-07-11 06:13:32 +0000 | [diff] [blame] | 158 | } |
| Hisham Muhammad | d6231ba | 2006-03-04 18:16:49 +0000 | [diff] [blame] | 159 | } |
| 160 | |
| 161 | void Hashtable_foreach(Hashtable* this, Hashtable_PairFunction f, void* userData) { |
| Hisham Muhammad | 110ce71 | 2006-11-08 20:09:48 +0000 | [diff] [blame] | 162 | assert(Hashtable_isConsistent(this)); |
| Hisham Muhammad | d6231ba | 2006-03-04 18:16:49 +0000 | [diff] [blame] | 163 | for (int i = 0; i < this->size; i++) { |
| 164 | HashtableItem* walk = this->buckets[i]; |
| 165 | while (walk != NULL) { |
| 166 | f(walk->key, walk->value, userData); |
| 167 | walk = walk->next; |
| 168 | } |
| 169 | } |
| Hisham Muhammad | 110ce71 | 2006-11-08 20:09:48 +0000 | [diff] [blame] | 170 | assert(Hashtable_isConsistent(this)); |
| Hisham Muhammad | d6231ba | 2006-03-04 18:16:49 +0000 | [diff] [blame] | 171 | } |