169 lines
3.7 KiB
C
169 lines
3.7 KiB
C
#include <assert.h>
|
|
#include <string.h>
|
|
|
|
#include "system.h"
|
|
#include "hash_set.h"
|
|
|
|
void hash_set_init(HashSet *set)
|
|
{
|
|
set->items = NULL;
|
|
set->count = 0;
|
|
set->capacity = 0;
|
|
}
|
|
|
|
void hash_set_free(HashSet *set)
|
|
{
|
|
sys_free(set->items);
|
|
set->items = NULL;
|
|
}
|
|
|
|
void hash_set_clear(HashSet *set)
|
|
{
|
|
free(set->items);
|
|
set->items = NULL;
|
|
set->count = 0;
|
|
set->capacity = 0;
|
|
}
|
|
|
|
int hash_set_insert(HashSet *set, SHA256 hash)
|
|
{
|
|
// Avoid duplicates
|
|
for (int i = 0; i < set->count; i++)
|
|
if (!memcmp(&set->items[i], &hash, sizeof(SHA256)))
|
|
return 0; // Already present
|
|
|
|
if (set->count == set->capacity) {
|
|
|
|
int new_capacity;
|
|
if (set->items == NULL)
|
|
new_capacity = 16;
|
|
else
|
|
new_capacity = 2 * set->capacity;
|
|
|
|
SHA256 *new_items = sys_realloc(set->items, new_capacity * sizeof(SHA256));
|
|
if (new_items == NULL)
|
|
return -1;
|
|
|
|
set->items = new_items;
|
|
set->capacity = new_capacity;
|
|
}
|
|
|
|
set->items[set->count++] = hash;
|
|
return 0;
|
|
}
|
|
|
|
bool hash_set_remove(HashSet *set, SHA256 hash)
|
|
{
|
|
for (int i = 0; i < set->count; i++)
|
|
if (!memcmp(&hash, &set->items[i], sizeof(SHA256))) {
|
|
set->items[i] = set->items[--set->count];
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool hash_set_contains(HashSet *set, SHA256 hash)
|
|
{
|
|
for (int i = 0; i < set->count; i++)
|
|
if (!memcmp(&hash, &set->items[i], sizeof(SHA256)))
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
int hash_set_merge(HashSet *dst, HashSet src)
|
|
{
|
|
HashSet ret;
|
|
hash_set_init(&ret);
|
|
|
|
for (int i = 0; i < dst->count; i++) {
|
|
if (hash_set_insert(&ret, dst->items[i]) < 0)
|
|
goto error;
|
|
}
|
|
|
|
for (int i = 0; i < src.count; i++) {
|
|
if (hash_set_insert(&ret, src.items[i]) < 0)
|
|
goto error;
|
|
}
|
|
|
|
hash_set_free(dst);
|
|
*dst = ret;
|
|
return 0;
|
|
|
|
error:
|
|
hash_set_free(&ret);
|
|
return -1;
|
|
}
|
|
|
|
void hash_set_remove_set(HashSet *dst, HashSet src)
|
|
{
|
|
for (int i = 0; i < src.count; i++)
|
|
hash_set_remove(dst, src.items[i]);
|
|
}
|
|
|
|
void timed_hash_set_init(TimedHashSet *set)
|
|
{
|
|
set->items = NULL;
|
|
set->count = 0;
|
|
set->capacity = 0;
|
|
}
|
|
|
|
void timed_hash_set_free(TimedHashSet *set)
|
|
{
|
|
sys_free(set->items);
|
|
set->items = NULL;
|
|
}
|
|
|
|
int timed_hash_set_find(TimedHashSet *set, SHA256 hash)
|
|
{
|
|
for (int i = 0; i < set->count; i++)
|
|
if (!memcmp(&set->items[i].hash, &hash, sizeof(SHA256)))
|
|
return i;
|
|
return -1;
|
|
}
|
|
|
|
int timed_hash_set_insert(TimedHashSet *set, SHA256 hash, Time time)
|
|
{
|
|
// Check if already in set
|
|
int idx = timed_hash_set_find(set, hash);
|
|
if (idx >= 0) {
|
|
// Already marked, keep the original time
|
|
return 0;
|
|
}
|
|
|
|
if (set->count == set->capacity) {
|
|
int new_capacity;
|
|
if (set->capacity == 0)
|
|
new_capacity = 8;
|
|
else
|
|
new_capacity = 2 * set->capacity;
|
|
|
|
TimedHash *new_items = sys_malloc(new_capacity * sizeof(TimedHash));
|
|
if (new_items == NULL)
|
|
return -1;
|
|
|
|
if (set->capacity > 0) {
|
|
memcpy(new_items, set->items, set->count * sizeof(set->items[0]));
|
|
sys_free(set->items);
|
|
}
|
|
|
|
set->items = new_items;
|
|
set->capacity = new_capacity;
|
|
}
|
|
|
|
set->items[set->count++] = (TimedHash) { hash, time };
|
|
return 0;
|
|
}
|
|
|
|
void timed_hash_set_remove(TimedHashSet *set, SHA256 hash)
|
|
{
|
|
int idx = timed_hash_set_find(set, hash);
|
|
if (idx >= 0) {
|
|
// Remove by shifting remaining items
|
|
if (idx < set->count - 1) {
|
|
memmove(&set->items[idx], &set->items[idx + 1],
|
|
(set->count - idx - 1) * sizeof(set->items[0]));
|
|
}
|
|
set->count--;
|
|
}
|
|
}
|