Hashtable.c 4.21 KB
Newer Older
Hisham Muhammad's avatar
Hisham Muhammad committed
1
/*
Hisham Muhammad's avatar
Hisham Muhammad committed
2
htop - Hashtable.c
Hisham Muhammad's avatar
Hisham Muhammad committed
3
(C) 2004-2011 Hisham H. Muhammad
Hisham Muhammad's avatar
Hisham Muhammad committed
4
5
6
7
8
9
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/

#include "Hashtable.h"

Hisham Muhammad's avatar
Hisham Muhammad committed
10
11
#include "debug.h"

Hisham Muhammad's avatar
Hisham Muhammad committed
12
#include <stdlib.h>
Hisham Muhammad's avatar
Hisham Muhammad committed
13
#include <assert.h>
Hisham Muhammad's avatar
Hisham Muhammad committed
14
15

/*{
Hisham Muhammad's avatar
Hisham Muhammad committed
16
17
#include <stdbool.h>

Hisham Muhammad's avatar
Hisham Muhammad committed
18
19
20
21
22
typedef struct Hashtable_ Hashtable;

typedef void(*Hashtable_PairFunction)(int, void*, void*);

typedef struct HashtableItem {
23
   unsigned int key;
Hisham Muhammad's avatar
Hisham Muhammad committed
24
25
26
27
28
29
30
31
32
33
34
35
   void* value;
   struct HashtableItem* next;
} HashtableItem;

struct Hashtable_ {
   int size;
   HashtableItem** buckets;
   int items;
   bool owner;
};
}*/

Hisham Muhammad's avatar
Hisham Muhammad committed
36
37
#ifdef DEBUG

38
static bool Hashtable_isConsistent(Hashtable* this) {
Hisham Muhammad's avatar
Hisham Muhammad committed
39
40
41
42
43
44
45
46
47
48
49
   int items = 0;
   for (int i = 0; i < this->size; i++) {
      HashtableItem* bucket = this->buckets[i];
      while (bucket) {
         items++;
         bucket = bucket->next;
      }
   }
   return items == this->items;
}

Hisham Muhammad's avatar
Hisham Muhammad committed
50
51
52
53
54
55
56
57
58
59
60
61
62
int Hashtable_count(Hashtable* this) {
   int items = 0;
   for (int i = 0; i < this->size; i++) {
      HashtableItem* bucket = this->buckets[i];
      while (bucket) {
         items++;
         bucket = bucket->next;
      }
   }
   assert(items == this->items);
   return items;
}

Hisham Muhammad's avatar
Hisham Muhammad committed
63
64
#endif

65
static HashtableItem* HashtableItem_new(unsigned int key, void* value) {
Hisham Muhammad's avatar
Hisham Muhammad committed
66
67
68
69
70
71
72
73
74
75
76
77
78
   HashtableItem* this;
   
   this = (HashtableItem*) malloc(sizeof(HashtableItem));
   this->key = key;
   this->value = value;
   this->next = NULL;
   return this;
}

Hashtable* Hashtable_new(int size, bool owner) {
   Hashtable* this;
   
   this = (Hashtable*) malloc(sizeof(Hashtable));
Hisham Muhammad's avatar
Hisham Muhammad committed
79
   this->items = 0;
Hisham Muhammad's avatar
Hisham Muhammad committed
80
81
82
   this->size = size;
   this->buckets = (HashtableItem**) calloc(sizeof(HashtableItem*), size);
   this->owner = owner;
Hisham Muhammad's avatar
Hisham Muhammad committed
83
   assert(Hashtable_isConsistent(this));
Hisham Muhammad's avatar
Hisham Muhammad committed
84
85
86
87
   return this;
}

void Hashtable_delete(Hashtable* this) {
Hisham Muhammad's avatar
Hisham Muhammad committed
88
   assert(Hashtable_isConsistent(this));
Hisham Muhammad's avatar
Hisham Muhammad committed
89
90
91
92
93
94
95
96
97
98
99
100
101
102
   for (int i = 0; i < this->size; i++) {
      HashtableItem* walk = this->buckets[i];
      while (walk != NULL) {
         if (this->owner)
            free(walk->value);
         HashtableItem* savedWalk = walk;
         walk = savedWalk->next;
         free(savedWalk);
      }
   }
   free(this->buckets);
   free(this);
}

103
104
void Hashtable_put(Hashtable* this, unsigned int key, void* value) {
   unsigned int index = key % this->size;
Hisham Muhammad's avatar
Hisham Muhammad committed
105
106
107
108
109
110
111
112
113
114
115
116
117
   HashtableItem** bucketPtr = &(this->buckets[index]);
   while (true)
      if (*bucketPtr == NULL) {
         *bucketPtr = HashtableItem_new(key, value);
         this->items++;
         break;
      } else if ((*bucketPtr)->key == key) {
         if (this->owner)
            free((*bucketPtr)->value);
         (*bucketPtr)->value = value;
         break;
      } else
         bucketPtr = &((*bucketPtr)->next);
Hisham Muhammad's avatar
Hisham Muhammad committed
118
   assert(Hashtable_isConsistent(this));
Hisham Muhammad's avatar
Hisham Muhammad committed
119
120
}

121
122
void* Hashtable_remove(Hashtable* this, unsigned int key) {
   unsigned int index = key % this->size;
Hisham Muhammad's avatar
Hisham Muhammad committed
123
124
125
126
127
128
129
130
131
132
   
   assert(Hashtable_isConsistent(this));

   HashtableItem** bucket; 
   for (bucket = &(this->buckets[index]); *bucket; bucket = &((*bucket)->next) ) {
      if ((*bucket)->key == key) {
         void* value = (*bucket)->value;
         HashtableItem* next = (*bucket)->next;
         free(*bucket);
         (*bucket) = next;
Hisham Muhammad's avatar
Hisham Muhammad committed
133
134
         this->items--;
         if (this->owner) {
Hisham Muhammad's avatar
Hisham Muhammad committed
135
136
            free(value);
            assert(Hashtable_isConsistent(this));
Hisham Muhammad's avatar
Hisham Muhammad committed
137
138
            return NULL;
         } else {
Hisham Muhammad's avatar
Hisham Muhammad committed
139
140
            assert(Hashtable_isConsistent(this));
            return value;
Hisham Muhammad's avatar
Hisham Muhammad committed
141
         }
Hisham Muhammad's avatar
Hisham Muhammad committed
142
143
144
145
      }
   }
   assert(Hashtable_isConsistent(this));
   return NULL;
Hisham Muhammad's avatar
Hisham Muhammad committed
146
}
Hisham Muhammad's avatar
Hisham Muhammad committed
147

148
149
inline void* Hashtable_get(Hashtable* this, unsigned int key) {
   unsigned int index = key % this->size;
Hisham Muhammad's avatar
Hisham Muhammad committed
150
   HashtableItem* bucketPtr = this->buckets[index];
151
   while (true) {
Hisham Muhammad's avatar
Hisham Muhammad committed
152
      if (bucketPtr == NULL) {
Hisham Muhammad's avatar
Hisham Muhammad committed
153
         assert(Hashtable_isConsistent(this));
Hisham Muhammad's avatar
Hisham Muhammad committed
154
155
         return NULL;
      } else if (bucketPtr->key == key) {
Hisham Muhammad's avatar
Hisham Muhammad committed
156
         assert(Hashtable_isConsistent(this));
Hisham Muhammad's avatar
Hisham Muhammad committed
157
158
159
         return bucketPtr->value;
      } else
         bucketPtr = bucketPtr->next;
160
   }
Hisham Muhammad's avatar
Hisham Muhammad committed
161
162
163
}

void Hashtable_foreach(Hashtable* this, Hashtable_PairFunction f, void* userData) {
Hisham Muhammad's avatar
Hisham Muhammad committed
164
   assert(Hashtable_isConsistent(this));
Hisham Muhammad's avatar
Hisham Muhammad committed
165
166
167
168
169
170
171
   for (int i = 0; i < this->size; i++) {
      HashtableItem* walk = this->buckets[i];
      while (walk != NULL) {
         f(walk->key, walk->value, userData);
         walk = walk->next;
      }
   }
Hisham Muhammad's avatar
Hisham Muhammad committed
172
   assert(Hashtable_isConsistent(this));
Hisham Muhammad's avatar
Hisham Muhammad committed
173
}