203 lines
5.5 KiB
C
203 lines
5.5 KiB
C
|
|
#define _POSIX_C_SOURCE 200809L
|
||
|
|
#include "runtime.h"
|
||
|
|
#include <stdlib.h>
|
||
|
|
#include <string.h>
|
||
|
|
|
||
|
|
#define ARRAYLIST_INITIAL_CAPACITY 16
|
||
|
|
|
||
|
|
RavaArrayList_t* rava_arraylist_create(void) {
|
||
|
|
RavaArrayList_t *list = calloc(1, sizeof(RavaArrayList_t));
|
||
|
|
list->collection_type = RAVA_COLLECTION_ARRAYLIST;
|
||
|
|
list->data = calloc(ARRAYLIST_INITIAL_CAPACITY, sizeof(RavaValue_t));
|
||
|
|
list->size = 0;
|
||
|
|
list->capacity = ARRAYLIST_INITIAL_CAPACITY;
|
||
|
|
return list;
|
||
|
|
}
|
||
|
|
|
||
|
|
void rava_arraylist_destroy(RavaArrayList_t *list) {
|
||
|
|
if (!list) return;
|
||
|
|
free(list->data);
|
||
|
|
free(list);
|
||
|
|
}
|
||
|
|
|
||
|
|
void rava_arraylist_add(RavaArrayList_t *list, RavaValue_t value) {
|
||
|
|
if (list->size >= list->capacity) {
|
||
|
|
list->capacity *= 2;
|
||
|
|
list->data = realloc(list->data, list->capacity * sizeof(RavaValue_t));
|
||
|
|
}
|
||
|
|
list->data[list->size++] = value;
|
||
|
|
}
|
||
|
|
|
||
|
|
RavaValue_t rava_arraylist_get(RavaArrayList_t *list, size_t index) {
|
||
|
|
if (index >= list->size) {
|
||
|
|
return rava_value_null();
|
||
|
|
}
|
||
|
|
return list->data[index];
|
||
|
|
}
|
||
|
|
|
||
|
|
void rava_arraylist_set(RavaArrayList_t *list, size_t index, RavaValue_t value) {
|
||
|
|
if (index < list->size) {
|
||
|
|
list->data[index] = value;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
size_t rava_arraylist_size(RavaArrayList_t *list) {
|
||
|
|
return list->size;
|
||
|
|
}
|
||
|
|
|
||
|
|
RavaValue_t rava_arraylist_remove(RavaArrayList_t *list, size_t index) {
|
||
|
|
if (index >= list->size) {
|
||
|
|
return rava_value_null();
|
||
|
|
}
|
||
|
|
RavaValue_t removed = list->data[index];
|
||
|
|
for (size_t i = index; i < list->size - 1; i++) {
|
||
|
|
list->data[i] = list->data[i + 1];
|
||
|
|
}
|
||
|
|
list->size--;
|
||
|
|
return removed;
|
||
|
|
}
|
||
|
|
|
||
|
|
void rava_arraylist_clear(RavaArrayList_t *list) {
|
||
|
|
list->size = 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool rava_arraylist_isempty(RavaArrayList_t *list) {
|
||
|
|
return list->size == 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
static unsigned int _rava_hash_string(const char *str) {
|
||
|
|
unsigned int hash = 5381;
|
||
|
|
int c;
|
||
|
|
while ((c = *str++)) {
|
||
|
|
hash = ((hash << 5) + hash) + c;
|
||
|
|
}
|
||
|
|
return hash;
|
||
|
|
}
|
||
|
|
|
||
|
|
RavaHashMap_t* rava_hashmap_create(void) {
|
||
|
|
RavaHashMap_t *map = calloc(1, sizeof(RavaHashMap_t));
|
||
|
|
map->collection_type = RAVA_COLLECTION_HASHMAP;
|
||
|
|
map->bucket_count = RAVA_HASHMAP_BUCKET_SIZE;
|
||
|
|
map->buckets = calloc(map->bucket_count, sizeof(RavaHashMapEntry_t));
|
||
|
|
map->size = 0;
|
||
|
|
return map;
|
||
|
|
}
|
||
|
|
|
||
|
|
void rava_hashmap_destroy(RavaHashMap_t *map) {
|
||
|
|
if (!map) return;
|
||
|
|
for (size_t i = 0; i < map->bucket_count; i++) {
|
||
|
|
if (map->buckets[i].occupied) {
|
||
|
|
free(map->buckets[i].key);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
free(map->buckets);
|
||
|
|
free(map);
|
||
|
|
}
|
||
|
|
|
||
|
|
static void _rava_hashmap_resize(RavaHashMap_t *map) {
|
||
|
|
size_t old_count = map->bucket_count;
|
||
|
|
RavaHashMapEntry_t *old_buckets = map->buckets;
|
||
|
|
|
||
|
|
map->bucket_count *= 2;
|
||
|
|
map->buckets = calloc(map->bucket_count, sizeof(RavaHashMapEntry_t));
|
||
|
|
map->size = 0;
|
||
|
|
|
||
|
|
for (size_t i = 0; i < old_count; i++) {
|
||
|
|
if (old_buckets[i].occupied) {
|
||
|
|
rava_hashmap_put(map, old_buckets[i].key, old_buckets[i].value);
|
||
|
|
free(old_buckets[i].key);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
free(old_buckets);
|
||
|
|
}
|
||
|
|
|
||
|
|
void rava_hashmap_put(RavaHashMap_t *map, const char *key, RavaValue_t value) {
|
||
|
|
if (map->size >= map->bucket_count * 7 / 10) {
|
||
|
|
_rava_hashmap_resize(map);
|
||
|
|
}
|
||
|
|
|
||
|
|
unsigned int hash = _rava_hash_string(key);
|
||
|
|
size_t index = hash % map->bucket_count;
|
||
|
|
|
||
|
|
while (map->buckets[index].occupied) {
|
||
|
|
if (strcmp(map->buckets[index].key, key) == 0) {
|
||
|
|
map->buckets[index].value = value;
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
index = (index + 1) % map->bucket_count;
|
||
|
|
}
|
||
|
|
|
||
|
|
map->buckets[index].key = strdup(key);
|
||
|
|
map->buckets[index].value = value;
|
||
|
|
map->buckets[index].occupied = true;
|
||
|
|
map->size++;
|
||
|
|
}
|
||
|
|
|
||
|
|
RavaValue_t rava_hashmap_get(RavaHashMap_t *map, const char *key) {
|
||
|
|
unsigned int hash = _rava_hash_string(key);
|
||
|
|
size_t index = hash % map->bucket_count;
|
||
|
|
size_t start = index;
|
||
|
|
|
||
|
|
while (map->buckets[index].occupied) {
|
||
|
|
if (strcmp(map->buckets[index].key, key) == 0) {
|
||
|
|
return map->buckets[index].value;
|
||
|
|
}
|
||
|
|
index = (index + 1) % map->bucket_count;
|
||
|
|
if (index == start) break;
|
||
|
|
}
|
||
|
|
|
||
|
|
return rava_value_null();
|
||
|
|
}
|
||
|
|
|
||
|
|
RavaValue_t rava_hashmap_remove(RavaHashMap_t *map, const char *key) {
|
||
|
|
unsigned int hash = _rava_hash_string(key);
|
||
|
|
size_t index = hash % map->bucket_count;
|
||
|
|
size_t start = index;
|
||
|
|
|
||
|
|
while (map->buckets[index].occupied) {
|
||
|
|
if (strcmp(map->buckets[index].key, key) == 0) {
|
||
|
|
RavaValue_t removed = map->buckets[index].value;
|
||
|
|
free(map->buckets[index].key);
|
||
|
|
map->buckets[index].key = NULL;
|
||
|
|
map->buckets[index].occupied = false;
|
||
|
|
map->size--;
|
||
|
|
return removed;
|
||
|
|
}
|
||
|
|
index = (index + 1) % map->bucket_count;
|
||
|
|
if (index == start) break;
|
||
|
|
}
|
||
|
|
|
||
|
|
return rava_value_null();
|
||
|
|
}
|
||
|
|
|
||
|
|
size_t rava_hashmap_size(RavaHashMap_t *map) {
|
||
|
|
return map->size;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool rava_hashmap_containskey(RavaHashMap_t *map, const char *key) {
|
||
|
|
unsigned int hash = _rava_hash_string(key);
|
||
|
|
size_t index = hash % map->bucket_count;
|
||
|
|
size_t start = index;
|
||
|
|
|
||
|
|
while (map->buckets[index].occupied) {
|
||
|
|
if (strcmp(map->buckets[index].key, key) == 0) {
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
index = (index + 1) % map->bucket_count;
|
||
|
|
if (index == start) break;
|
||
|
|
}
|
||
|
|
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
void rava_hashmap_clear(RavaHashMap_t *map) {
|
||
|
|
for (size_t i = 0; i < map->bucket_count; i++) {
|
||
|
|
if (map->buckets[i].occupied) {
|
||
|
|
free(map->buckets[i].key);
|
||
|
|
map->buckets[i].key = NULL;
|
||
|
|
map->buckets[i].occupied = false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
map->size = 0;
|
||
|
|
}
|