OB.DAAC Logo
NASA Logo
Ocean Color Science Software

ocssw V2022
shash.c
Go to the documentation of this file.
1 // implemented version numbers
2 #define SHASH_IMPLEMENTATION 1002000
3 #define SHASH_IMPLEMENTATION_STR "1.2.0"
4 #define SHASH_API_VERSION 1002000
5 #define SHASH_API_VERSION_STR "1.2.0"
6 #include "shash.h"
7 
8 #include <limits.h> /* For CHAR_BIT. */
9 #include <stdbool.h>
10 #include <stdint.h>
11 #include <stdlib.h>
12 #include <string.h>
13 
19 #ifndef SHASH_INITIAL_SIZE
20 #define SHASH_INITIAL_SIZE 64
21 #endif
22 
27 #ifndef SHASH_FILLPCT
28 #define SHASH_FILLPCT 66
29 #endif
30 
31 typedef struct shash_bucket shash_bucket;
32 
33 struct shash_bucket {
35  char *key;
36  char *value;
37  uint32_t shash;
38 };
39 
40 struct shash {
43  int filled;
44  int iter_i;
46 };
47 
48 // Murmur3 32-bit hash stolen from qlibc
49 // https://github.com/wolkykim/qlibc/blob/master/src/utilities/qhash.c
50 static uint32_t compute_hash(const char *key) {
51  if (key == NULL)
52  return 0;
53  size_t key_length = strlen(key);
54  if (key_length == 0) {
55  return 0;
56  }
57  const uint32_t c1 = 0xcc9e2d51;
58  const uint32_t c2 = 0x1b873593;
59  const unsigned nblocks = (unsigned) (key_length / 4);
60  const uint32_t *blocks = (const uint32_t *) (key);
61  const uint8_t *tail = (const uint8_t *) (key + (nblocks * 4));
62  uint32_t h = 0;
63  unsigned i;
64  uint32_t k;
65  for (i = 0; i < nblocks; i++) {
66  k = blocks[i];
67  k *= c1;
68  k = (k << 15) | (k >> (32 - 15));
69  k *= c2;
70  h ^= k;
71  h = (h << 13) | (h >> (32 - 13));
72  h = (h * 5) + 0xe6546b64;
73  }
74  k = 0;
75  switch (key_length & 3) {
76  case 3:
77  k ^= tail[2] << 16;
78  /* no break */
79  case 2:
80  k ^= tail[1] << 8;
81  /* no break */
82  case 1:
83  k ^= tail[0];
84  k *= c1;
85  k = (k << 15) | (k >> (32 - 15));
86  k *= c2;
87  h ^= k;
88  };
89  h ^= (uint32_t) key_length;
90  h ^= h >> 16;
91  h *= 0x85ebca6b;
92  h ^= h >> 13;
93  h *= 0xc2b2ae35;
94  h ^= h >> 16;
95  return h;
96 }
97 
98 static void shash_zero_out(shash_bucket **buckets, int start, int end) {
99  int i;
100  for (i = start; i <= end; i++) {
101  buckets[i] = NULL;
102  }
103 }
104 
106  (void) options;
107  shash *h = malloc(sizeof(shash));
108  if (h == NULL) {
109  return NULL;
110  }
111  h->buckets = (shash_bucket**) malloc(SHASH_INITIAL_SIZE * sizeof(shash_bucket*));
112  if (h->buckets == NULL) {
113  free(h);
114  return NULL;
115  }
116  h->filled = 0;
117  h->max_bucket = SHASH_INITIAL_SIZE - 1;
118  shash_rewind(h);
119  shash_zero_out(h->buckets, 0, h->max_bucket);
120  return h;
121 }
122 
123 static int shash_destroy_bucket(shash_bucket *bucket, bool follow) {
124  if (bucket != NULL) {
125  free(bucket->key);
126  free(bucket->value);
127  int ret = 1;
128  if (follow) {
129  ret += shash_destroy_bucket(bucket->next, true);
130  }
131  free(bucket);
132  return ret;
133  }
134  return 0;
135 }
137  int i, total_freed = 0;
138  for (i = 0; i <= h->max_bucket; i++) {
139  total_freed += shash_destroy_bucket(h->buckets[i], true);
140  }
141  free(h->buckets);
142  free(h);
143  return 0;
144 }
145 
146 int shash_remove(shash *h, const char *key) {
147  if (h == NULL) {
148  return -1;
149  }
150  uint32_t shash = compute_hash(key);
151  shash_bucket **bucket_ptr = &(h->buckets[shash & h->max_bucket]);
152  shash_bucket *cur_bucket = *bucket_ptr;
153 
154  int is_first;
155  for (is_first = 1; cur_bucket != NULL; is_first = 0, bucket_ptr = &cur_bucket->next, cur_bucket = *bucket_ptr) {
156  if (cur_bucket->shash == shash && strcmp(cur_bucket->key, key) == 0) {
157  *bucket_ptr = cur_bucket->next;
158  shash_destroy_bucket(cur_bucket, false);
159  if (is_first) {
160  h->filled--;
161  }
162  return 0;
163  }
164  }
165  return 1;
166 }
167 
168 static int shash_split(shash *h) {
169  int oldsize = h->max_bucket + 1;
170  int newsize = oldsize << 1;
171  shash_bucket **a = (shash_bucket**) realloc((shash_bucket*) h->buckets, newsize * sizeof(shash_bucket*));
172  if (a == NULL) {
173  return -1;
174  }
175  shash_zero_out(a, oldsize, --newsize);
176 
177  h->max_bucket = newsize;
178  h->buckets = a;
179 
180  shash_bucket **b, **oentry, *entry;
181 
182  int i;
183  for (i = 0; i < oldsize; i++, a++) {
184  if (*a == NULL)
185  continue;
186  b = a + oldsize;
187  for (oentry = a, entry = *a; entry != NULL; entry = *oentry) {
188  if ((entry->shash & newsize) != (unsigned) i) {
189  *oentry = entry->next;
190  entry->next = *b;
191 // if (*b == NULL)
192 // h->filled++;
193  *b = entry;
194  continue;
195  } else {
196  oentry = &entry->next;
197  }
198  }
199 // if (*a == NULL)
200 // h->filled--;
201  }
202  return 0;
203 }
204 
205 const char *shash_get(shash *h, const char *key) {
206  shash_bucket *entry;
207  shash_bucket **oentry;
208 
209  if (h == NULL) {
210  return NULL;
211  }
212 
213  uint32_t shash = compute_hash(key);
214  oentry = &(h->buckets[shash & h->max_bucket]);
215 
216  for (entry = *oentry; entry != NULL; entry = entry->next) {
217  if (entry->shash == shash && strcmp(entry->key, key) == 0) {
218  return entry->value;
219  }
220  }
221  return NULL;
222 }
223 
224 int shash_set(shash *h, const char *key, const char *value) {
225  shash_bucket *entry;
226  shash_bucket **oentry;
227 
228  if (h == NULL) {
229  return -1;
230  }
231 
232  uint32_t shash = compute_hash(key);
233  oentry = &(h->buckets[shash & h->max_bucket]);
234 
235  for (entry = *oentry; entry != NULL; entry = entry->next) {
236  if (entry->shash == shash && strcmp(entry->key, key) == 0) {
237  free(entry->value);
238  entry->value = strdup(value);
239  if (entry->value == NULL) {
240  shash_remove(h, key);
241  return -1;
242  }
243  return 1;
244  }
245  }
246  entry = (shash_bucket*) malloc(sizeof(shash_bucket));
247  if (entry == NULL) {
248  return -1;
249  }
250 
251  entry->key = strdup(key);
252  entry->value = strdup(value);
253  if (entry->key == NULL || entry->value == NULL) {
254  if (entry->key == NULL) {
255  free(entry->key);
256  }
257  if (entry->value == NULL) {
258  free(entry->value);
259  }
260  free(entry);
261  return -1;
262  }
263  entry->shash = shash;
264  entry->next = *oentry;
265  *oentry = entry;
266 
267  h->filled++;
268  if ((h->filled * 100 / (h->max_bucket + 1)) > SHASH_FILLPCT) {
269  if (shash_split(h)) {
270  return -1;
271  }
272  }
273 
274  return 0;
275 }
276 
278  h->iter_i = -1;
279  h->iter = NULL;
280  return h->filled;
281 }
282 
283 int shash_next(shash *h, const char **key, const char **value) {
284  if (h == NULL) {
285  return -1;
286  }
287  shash_bucket *b = h->iter;
288  do {
289  if (b != NULL) {
290  b = b->next;
291  }
292  if (b == NULL) {
293  h->iter_i++;
294  if (h->iter_i > h->max_bucket) {
295  h->iter_i = -1;
296  break;
297  }
298  b = h->buckets[h->iter_i];
299  }
300  } while (b == NULL);
301  h->iter = b;
302  if (b == NULL) {
303  if (key != NULL) {
304  *key = NULL;
305  }
306  if (value != NULL){
307  *value = NULL;
308  }
309  return 1;
310  }
311  if (key != NULL) {
312  *key = b->key;
313  }
314  if (value != NULL){
315  *value = b->value;
316  }
317  return 0;
318 }
319 
321  return h->filled;
322 }
323 
324 const char *shash_version() {
325  return "shash " SHASH_IMPLEMENTATION_STR ", API " SHASH_API_VERSION_STR;
326 }
shash_bucket * next
Definition: shash.c:34
int32 value
Definition: Granule.c:1235
int iter_i
Definition: shash.c:44
uint32_t shash
Definition: shash.c:37
char * key
Definition: shash.c:35
#define NULL
Definition: decode_rs.h:63
#define SHASH_FILLPCT
How full to get before doubling the size of the shash, 0-99.
Definition: shash.c:28
float h[MODELMAX]
Definition: atrem_corl1.h:131
shash * shash_create(uint32_t options)
Initialize a shash object.
Definition: shash.c:105
int shash_set(shash *h, const char *key, const char *value)
Add or overwrite a pointer, associating it with the given key.
Definition: shash.c:224
Implementation-specific, generic type to store the shash object.
Definition: shash.c:40
#define SHASH_IMPLEMENTATION_STR
Definition: shash.c:3
shash_bucket * iter
Definition: shash.c:45
const char * shash_version()
Returns the source code version and the implemented API version.
Definition: shash.c:324
int filled
Definition: shash.c:43
const char * shash_get(shash *h, const char *key)
Find a pointer associated with the given string.
Definition: shash.c:205
char * strdup(const char *)
int shash_next(shash *h, const char **key, const char **value)
Retrieves the next key-value pair in the shash. The order in which the pointers are returned shall be...
Definition: shash.c:283
int shash_size(shash *h)
Retrieves the number of key-value pairs in the hash object.
Definition: shash.c:320
#define SHASH_INITIAL_SIZE
Size to initialize shash to upon creation.
Definition: shash.c:20
@ tail
Definition: dataday.h:37
int shash_rewind(shash *h)
Rewind iterator for traversing all the keys and values.
Definition: shash.c:277
data_t b[NROOTS+1]
Definition: decode_rs.h:77
int max_bucket
Definition: shash.c:42
A simple dictionary library for storing strings.
int shash_destroy(shash *h)
Destroy a shash object, free'ing the memory used.
Definition: shash.c:136
#define SHASH_API_VERSION_STR
Definition: shash.c:5
int shash_remove(shash *h, const char *key)
Remove a pointer associated with the given string.
Definition: shash.c:146
int i
Definition: decode_rs.h:71
PGE01 indicating that PGE02 PGE01 V6 for and PGE01 V2 for MOD03 were used to produce the granule By convention adopted in all MODIS Terra PGE02 code versions are The fourth digit of the PGE02 version denotes the LUT version used to produce the granule The source of the metadata environment variable ProcessingCenter was changed from a QA LUT value to the Process Configuration A sign used in error in the second order term was changed to a
Definition: HISTORY.txt:424
shash_bucket ** buckets
Definition: shash.c:41
int k
Definition: decode_rs.h:73
char * value
Definition: shash.c:36