1
0
mirror of https://github.com/janet-lang/janet synced 2024-06-24 06:03:17 +00:00
janet/dict.c
2017-03-07 15:29:40 -05:00

131 lines
4.2 KiB
C

#include "dict.h"
#include "util.h"
#include "value.h"
/* Initialize a dictionary */
GstDict *gst_dict_init(GstDict *dict, uint32_t capacity) {
GstDictBucket *buckets = gst_raw_calloc(1, sizeof(GstDictBucket) * capacity);
if (data == NULL)
return NULL;
dict->buckets = buckets;
dict->capacity = capacity;
dict->count = 0;
return dict;
}
/* Deinitialize a dictionary */
GstDict *gst_dict_free(GstDict *dict) {
gst_raw_free(dict->buckets);
}
/* Rehash a dictionary */
GstDict *gst_dict_rehash(GstDict *dict, uint32_t newCapacity) {
GstDictBucket *newBuckets = gst_raw_calloc(1, sizeof(GstDictBucket) * newCapacity);
GstDictBucket *buckets = dict->buckets;
uint32_t i, j;
if (newBuckets == NULL)
return NULL;
for (i = 0; i < dict->capacity; ++i) {
int index;
if (!(buckets[i].flags & GST_DICT_FLAG_OCCUPIED)) continue;
if (buckets[i].flags & GST_DICT_FLAG_TOMBSTONE) continue;
index = gst_hash(buckets[i].key) % newCapacity;
for (j = index; j < dict->capacity; ++j) {
if (newBuckets[j].flags & GST_DICT_FLAG_OCCUPIED) continue;
newBuckets[j] = buckets[i];
goto done;
}
for (j = 0; j < index; ++j) {
if (newBuckets[j].flags & GST_DICT_FLAG_OCCUPIED) continue;
newBuckets[j] = buckets[i];
goto done;
}
/* Error - could not rehash a bucket - this should never happen */
gst_raw_free(newBuckets);
return NULL;
/* Successfully rehashed bucket */
done:
}
dict->capacity = newCapacity;
return dict;
}
/* Find a bucket with a given key */
static int gst_dict_find(GstDict *dict, GstValue key, GstDictBucket **out) {
uint32_t index, i;
GstDictBucket *buckets = dict->buckets;
index = gst_hash(key) % dict->capacity;
for (i = index; i < dict->capacity; ++i) {
if (buckets[i].flags & GST_DICT_FLAGS_TOMBSTONE) continue;
if (!(buckets[i].flags & GST_DICT_FLAGS_OCCUPIED)) continue;
if (!gst_equals(key, buckets[i].key)) continue;
*out = buckets + i;
return 1;
}
for (i = 0; i < index; ++i) {
if (buckets[i].flags & GST_DICT_FLAGS_TOMBSTONE) continue;
if (!(buckets[i].flags & GST_DICT_FLAGS_OCCUPIED)) continue;
if (!gst_equals(key, buckets[i].key)) continue;
*out = buckets + i;
return 1;
}
return 0;
}
/* Get item from dictionary */
int gst_dict_get(GstDict *dict, GstValue key, GstValue *value) {
GstDictBucket *bucket;
int found = gst_dict_find(dict, key, &bucket);
if (found)
*value = bucket->value;
return found;
}
/* Add item to dictionary */
GstDict *gst_dict_put(GstDict *dict, GstValue key, GstValue value) {
/* Check if we need to increase capacity. The load factor is low
* because we are using linear probing */
uint32_t index, i;
uint32_t newCap = dict->count * 2 + 1;
GstBucket *buckets;
if (newCap > dict->capacity) {
dict = gst_dict_rehash(dict, newCap);
if (!dict) return dict;
}
index = gst_hash(key) % dict->capacity;
buckets = dict->buckets;
for (i = index; i < dict->capacity; ++i) {
if ((buckets[i].flags & GST_DICT_FLAGS_TOMBSTONE) ||
!(buckets[i].flags & GST_DICT_FLAGS_OCCUPIED))
continue;
dict->buckets[i].key = key;
dict->buckets[i].value = value;
dict->buckets[i].flags &= GST_DICT_FLAGS_OCCUPIED;
dict->count++;
return dict;
}
for (i = 0; i < index; ++i) {
if ((buckets[i].flags & GST_DICT_FLAGS_TOMBSTONE) ||
!(buckets[i].flags & GST_DICT_FLAGS_OCCUPIED))
continue;
dict->buckets[i].key = key;
dict->buckets[i].value = value;
dict->buckets[i].flags &= GST_DICT_FLAGS_OCCUPIED;
dict->count++;
return dict;
}
/* Error - should never get here */
return NULL;
}
/* Remove item from dictionary */
int gst_dict_remove(GstDict *dict, GstValue key) {
GstDictBucket *bucket;
int found = gst_dict_find(dict, key, &bucket);
if (found) {
bucket->flags |= GST_DICT_FLAGS_TOMBSTONE;
dict->count--;
}
return found;
}