mirror of
https://github.com/janet-lang/janet
synced 2024-11-10 10:49:54 +00:00
131 lines
4.2 KiB
C
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;
|
|
}
|