mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-06-27 21:40:34 +02:00
Add address map and set
This commit is contained in:
parent
b0b4c4d893
commit
d425620d37
5 changed files with 655 additions and 0 deletions
210
address-map.h
Normal file
210
address-map.h
Normal file
|
@ -0,0 +1,210 @@
|
|||
#ifndef ADDRESS_MAP_H
|
||||
#define ADDRESS_MAP_H
|
||||
|
||||
#include <malloc.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "address-hash.h"
|
||||
|
||||
struct hash_map_entry {
|
||||
uintptr_t k;
|
||||
uintptr_t v;
|
||||
};
|
||||
|
||||
struct hash_map {
|
||||
struct hash_map_entry *data;
|
||||
size_t size; // total number of slots
|
||||
size_t n_items; // number of items in set
|
||||
uint8_t *bits; // bitvector indicating set slots
|
||||
};
|
||||
|
||||
static void hash_map_clear(struct hash_map *map) {
|
||||
memset(map->bits, 0, map->size / 8);
|
||||
map->n_items = 0;
|
||||
}
|
||||
|
||||
// Size must be a power of 2.
|
||||
static void hash_map_init(struct hash_map *map, size_t size) {
|
||||
map->size = size;
|
||||
map->data = malloc(sizeof(struct hash_map_entry) * size);
|
||||
map->bits = malloc(size / 8);
|
||||
hash_map_clear(map);
|
||||
}
|
||||
static void hash_map_destroy(struct hash_map *map) {
|
||||
free(map->data);
|
||||
free(map->bits);
|
||||
}
|
||||
|
||||
static size_t hash_map_slot_index(struct hash_map *map, size_t idx) {
|
||||
return idx & (map->size - 1);
|
||||
}
|
||||
static struct hash_map_entry* hash_map_slot_entry(struct hash_map *map,
|
||||
size_t idx) {
|
||||
return &map->data[hash_map_slot_index(map, idx)];
|
||||
}
|
||||
static int hash_map_slot_is_empty(struct hash_map *map, size_t idx) {
|
||||
idx = hash_map_slot_index(map, idx);
|
||||
return (map->bits[idx / 8] & (1 << (idx % 8))) == 0;
|
||||
}
|
||||
static void hash_map_slot_acquire(struct hash_map *map, size_t idx) {
|
||||
idx = hash_map_slot_index(map, idx);
|
||||
map->bits[idx / 8] |= (1 << (idx % 8));
|
||||
map->n_items++;
|
||||
}
|
||||
static void hash_map_slot_release(struct hash_map *map, size_t idx) {
|
||||
idx = hash_map_slot_index(map, idx);
|
||||
map->bits[idx / 8] &= ~(1 << (idx % 8));
|
||||
map->n_items--;
|
||||
}
|
||||
static size_t hash_map_slot_distance(struct hash_map *map, size_t idx) {
|
||||
return hash_map_slot_index(map, idx - hash_map_slot_entry(map, idx)->k);
|
||||
}
|
||||
static int hash_map_should_shrink(struct hash_map *map) {
|
||||
return map->size > 8 && map->n_items <= (map->size >> 3);
|
||||
}
|
||||
static int hash_map_should_grow(struct hash_map *map) {
|
||||
return map->n_items >= map->size - (map->size >> 3);
|
||||
}
|
||||
|
||||
static void hash_map_do_insert(struct hash_map *map, uintptr_t k, uintptr_t v) {
|
||||
size_t displacement = 0;
|
||||
while (!hash_map_slot_is_empty(map, k + displacement)
|
||||
&& displacement < hash_map_slot_distance(map, k + displacement))
|
||||
displacement++;
|
||||
while (!hash_map_slot_is_empty(map, k + displacement)
|
||||
&& displacement == hash_map_slot_distance(map, k + displacement)) {
|
||||
if (hash_map_slot_entry(map, k + displacement)->k == k) {
|
||||
hash_map_slot_entry(map, k + displacement)->v = v;
|
||||
return;
|
||||
}
|
||||
displacement++;
|
||||
}
|
||||
size_t idx = k + displacement;
|
||||
size_t slots_to_move = 0;
|
||||
while (!hash_map_slot_is_empty(map, idx + slots_to_move))
|
||||
slots_to_move++;
|
||||
hash_map_slot_acquire(map, idx + slots_to_move);
|
||||
while (slots_to_move--)
|
||||
*hash_map_slot_entry(map, idx + slots_to_move + 1) =
|
||||
*hash_map_slot_entry(map, idx + slots_to_move);
|
||||
*hash_map_slot_entry(map, idx) = (struct hash_map_entry){ k, v };
|
||||
}
|
||||
|
||||
static void hash_map_populate(struct hash_map *dst, struct hash_map *src) {
|
||||
for (size_t i = 0; i < src->size; i++)
|
||||
if (!hash_map_slot_is_empty(src, i))
|
||||
hash_map_do_insert(dst, hash_map_slot_entry(src, i)->k,
|
||||
hash_map_slot_entry(src, i)->v);
|
||||
}
|
||||
static void hash_map_grow(struct hash_map *map) {
|
||||
struct hash_map fresh;
|
||||
hash_map_init(&fresh, map->size << 1);
|
||||
hash_map_populate(&fresh, map);
|
||||
hash_map_destroy(map);
|
||||
memcpy(map, &fresh, sizeof(fresh));
|
||||
}
|
||||
static void hash_map_shrink(struct hash_map *map) {
|
||||
struct hash_map fresh;
|
||||
hash_map_init(&fresh, map->size >> 1);
|
||||
hash_map_populate(&fresh, map);
|
||||
hash_map_destroy(map);
|
||||
memcpy(map, &fresh, sizeof(fresh));
|
||||
}
|
||||
|
||||
static void hash_map_insert(struct hash_map *map, uintptr_t k, uintptr_t v) {
|
||||
if (hash_map_should_grow(map))
|
||||
hash_map_grow(map);
|
||||
hash_map_do_insert(map, k, v);
|
||||
}
|
||||
static void hash_map_remove(struct hash_map *map, uintptr_t k) {
|
||||
size_t slot = k;
|
||||
while (!hash_map_slot_is_empty(map, slot) && hash_map_slot_entry(map, slot)->k != k)
|
||||
slot++;
|
||||
if (hash_map_slot_is_empty(map, slot))
|
||||
__builtin_trap();
|
||||
while (!hash_map_slot_is_empty(map, slot + 1)
|
||||
&& hash_map_slot_distance(map, slot + 1)) {
|
||||
*hash_map_slot_entry(map, slot) = *hash_map_slot_entry(map, slot + 1);
|
||||
slot++;
|
||||
}
|
||||
hash_map_slot_release(map, slot);
|
||||
if (hash_map_should_shrink(map))
|
||||
hash_map_shrink(map);
|
||||
}
|
||||
static int hash_map_contains(struct hash_map *map, uintptr_t k) {
|
||||
for (size_t slot = k; !hash_map_slot_is_empty(map, slot); slot++) {
|
||||
if (hash_map_slot_entry(map, slot)->k == k)
|
||||
return 1;
|
||||
if (hash_map_slot_distance(map, slot) < (slot - k))
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
static uintptr_t hash_map_lookup(struct hash_map *map, uintptr_t k, uintptr_t default_) {
|
||||
for (size_t slot = k; !hash_map_slot_is_empty(map, slot); slot++) {
|
||||
if (hash_map_slot_entry(map, slot)->k == k)
|
||||
return hash_map_slot_entry(map, slot)->v;
|
||||
if (hash_map_slot_distance(map, slot) < (slot - k))
|
||||
break;
|
||||
}
|
||||
return default_;
|
||||
}
|
||||
static inline void hash_map_for_each (struct hash_map *map,
|
||||
void (*f)(uintptr_t, uintptr_t, void*),
|
||||
void *data) __attribute__((always_inline));
|
||||
static inline void hash_map_for_each(struct hash_map *map,
|
||||
void (*f)(uintptr_t, uintptr_t, void*),
|
||||
void *data) {
|
||||
for (size_t i = 0; i < map->size; i++)
|
||||
if (!hash_map_slot_is_empty(map, i))
|
||||
f(hash_map_slot_entry(map, i)->k, hash_map_slot_entry(map, i)->v, data);
|
||||
}
|
||||
|
||||
struct address_map {
|
||||
struct hash_map hash_map;
|
||||
};
|
||||
|
||||
static void address_map_init(struct address_map *map) {
|
||||
hash_map_init(&map->hash_map, 8);
|
||||
}
|
||||
static void address_map_destroy(struct address_map *map) {
|
||||
hash_map_destroy(&map->hash_map);
|
||||
}
|
||||
static void address_map_clear(struct address_map *map) {
|
||||
hash_map_clear(&map->hash_map);
|
||||
}
|
||||
|
||||
static void address_map_add(struct address_map *map, uintptr_t addr, uintptr_t v) {
|
||||
hash_map_insert(&map->hash_map, hash_address(addr), v);
|
||||
}
|
||||
static void address_map_remove(struct address_map *map, uintptr_t addr) {
|
||||
hash_map_remove(&map->hash_map, hash_address(addr));
|
||||
}
|
||||
static int address_map_contains(struct address_map *map, uintptr_t addr) {
|
||||
return hash_map_contains(&map->hash_map, hash_address(addr));
|
||||
}
|
||||
static uintptr_t address_map_lookup(struct address_map *map, uintptr_t addr,
|
||||
uintptr_t default_) {
|
||||
return hash_map_lookup(&map->hash_map, hash_address(addr), default_);
|
||||
}
|
||||
|
||||
struct address_map_for_each_data {
|
||||
void (*f)(uintptr_t, uintptr_t, void *);
|
||||
void *data;
|
||||
};
|
||||
static void address_map_do_for_each(uintptr_t k, uintptr_t v, void *data) {
|
||||
struct address_map_for_each_data *for_each_data = data;
|
||||
for_each_data->f(unhash_address(k), v, for_each_data->data);
|
||||
}
|
||||
static inline void address_map_for_each (struct address_map *map,
|
||||
void (*f)(uintptr_t, uintptr_t, void*),
|
||||
void *data) __attribute__((always_inline));
|
||||
static inline void address_map_for_each (struct address_map *map,
|
||||
void (*f)(uintptr_t, uintptr_t, void*),
|
||||
void *data) {
|
||||
struct address_map_for_each_data for_each_data = { f, data };
|
||||
hash_map_for_each(&map->hash_map, address_map_do_for_each, &for_each_data);
|
||||
}
|
||||
|
||||
#endif // ADDRESS_MAP_H
|
Loading…
Add table
Add a link
Reference in a new issue