Commit 9a58d760 authored by Damien George's avatar Damien George
Browse files

py: Allow mp_map_t to be initialised by a fixed-size, const table.

This allows keyword maps to be created directly from stack data.
parent 698ec21e
...@@ -28,10 +28,24 @@ int get_doubling_prime_greater_or_equal_to(int x) { ...@@ -28,10 +28,24 @@ int get_doubling_prime_greater_or_equal_to(int x) {
/* map */ /* map */
void mp_map_init(mp_map_t *map, int n) { void mp_map_init(mp_map_t *map, int n) {
map->alloc = get_doubling_prime_greater_or_equal_to(n + 1); if (n == 0) {
map->alloc = 0;
map->table = NULL;
} else {
map->alloc = get_doubling_prime_greater_or_equal_to(n + 1);
map->table = m_new0(mp_map_elem_t, map->alloc);
}
map->used = 0; map->used = 0;
map->all_keys_are_qstrs = 1; map->all_keys_are_qstrs = 1;
map->table = m_new0(mp_map_elem_t, map->alloc); map->table_is_fixed_array = 0;
}
void mp_map_init_fixed_table(mp_map_t *map, int n, const mp_obj_t *table) {
map->alloc = n;
map->used = n;
map->all_keys_are_qstrs = 1;
map->table_is_fixed_array = 1;
map->table = (mp_map_elem_t*)table;
} }
mp_map_t *mp_map_new(int n) { mp_map_t *mp_map_new(int n) {
...@@ -42,7 +56,9 @@ mp_map_t *mp_map_new(int n) { ...@@ -42,7 +56,9 @@ mp_map_t *mp_map_new(int n) {
// Differentiate from mp_map_clear() - semantics is different // Differentiate from mp_map_clear() - semantics is different
void mp_map_deinit(mp_map_t *map) { void mp_map_deinit(mp_map_t *map) {
m_del(mp_map_elem_t, map->table, map->alloc); if (!map->table_is_fixed_array) {
m_del(mp_map_elem_t, map->table, map->alloc);
}
map->used = map->alloc = 0; map->used = map->alloc = 0;
} }
...@@ -52,15 +68,14 @@ void mp_map_free(mp_map_t *map) { ...@@ -52,15 +68,14 @@ void mp_map_free(mp_map_t *map) {
} }
void mp_map_clear(mp_map_t *map) { void mp_map_clear(mp_map_t *map) {
if (!map->table_is_fixed_array) {
m_del(mp_map_elem_t, map->table, map->alloc);
}
map->alloc = 0;
map->used = 0; map->used = 0;
map->all_keys_are_qstrs = 1; map->all_keys_are_qstrs = 1;
machine_uint_t a = map->alloc; map->table_is_fixed_array = 0;
map->alloc = 0; map->table = NULL;
map->table = m_renew(mp_map_elem_t, map->table, a, map->alloc);
mp_map_elem_t nul = {NULL, NULL};
for (uint i=0; i<map->alloc; i++) {
map->table[i] = nul;
}
} }
static void mp_map_rehash(mp_map_t *map) { static void mp_map_rehash(mp_map_t *map) {
...@@ -79,21 +94,37 @@ static void mp_map_rehash(mp_map_t *map) { ...@@ -79,21 +94,37 @@ static void mp_map_rehash(mp_map_t *map) {
} }
mp_map_elem_t* mp_map_lookup(mp_map_t *map, mp_obj_t index, mp_map_lookup_kind_t lookup_kind) { mp_map_elem_t* mp_map_lookup(mp_map_t *map, mp_obj_t index, mp_map_lookup_kind_t lookup_kind) {
// if the map is a fixed array then we must do a brute force linear search
if (map->table_is_fixed_array) {
if (lookup_kind != MP_MAP_LOOKUP) {
return NULL;
}
for (mp_map_elem_t *elem = &map->table[0], *top = &map->table[map->used]; elem < top; elem++) {
if (elem->key == index || (!map->all_keys_are_qstrs && mp_obj_equal(elem->key, index))) {
return elem;
}
}
return NULL;
}
// map is a hash table (not a fixed array), so do a hash lookup
machine_uint_t hash; machine_uint_t hash;
hash = mp_obj_hash(index); hash = mp_obj_hash(index);
if (map->alloc == 0) { if (map->alloc == 0) {
if (lookup_kind == MP_MAP_LOOKUP_ADD_IF_NOT_FOUND) { if (lookup_kind & MP_MAP_LOOKUP_ADD_IF_NOT_FOUND) {
mp_map_rehash(map); mp_map_rehash(map);
} else { } else {
return NULL; return NULL;
} }
} }
uint pos = hash % map->alloc; uint pos = hash % map->alloc;
for (;;) { for (;;) {
mp_map_elem_t *elem = &map->table[pos]; mp_map_elem_t *elem = &map->table[pos];
if (elem->key == NULL) { if (elem->key == NULL) {
// not in table // not in table
if (lookup_kind == MP_MAP_LOOKUP_ADD_IF_NOT_FOUND) { if (lookup_kind & MP_MAP_LOOKUP_ADD_IF_NOT_FOUND) {
if (map->used + 1 >= map->alloc) { if (map->used + 1 >= map->alloc) {
// not enough room in table, rehash it // not enough room in table, rehash it
mp_map_rehash(map); mp_map_rehash(map);
...@@ -117,7 +148,7 @@ mp_map_elem_t* mp_map_lookup(mp_map_t *map, mp_obj_t index, mp_map_lookup_kind_t ...@@ -117,7 +148,7 @@ mp_map_elem_t* mp_map_lookup(mp_map_t *map, mp_obj_t index, mp_map_lookup_kind_t
elem->key = index; elem->key = index;
} }
*/ */
if (lookup_kind == MP_MAP_LOOKUP_REMOVE_IF_FOUND) { if (lookup_kind & MP_MAP_LOOKUP_REMOVE_IF_FOUND) {
map->used--; map->used--;
// this leaks this memory (but see dict_get_helper) // this leaks this memory (but see dict_get_helper)
mp_map_elem_t *retval = m_new(mp_map_elem_t, 1); mp_map_elem_t *retval = m_new(mp_map_elem_t, 1);
...@@ -195,7 +226,7 @@ mp_obj_t mp_set_lookup(mp_set_t *set, mp_obj_t index, mp_map_lookup_kind_t looku ...@@ -195,7 +226,7 @@ mp_obj_t mp_set_lookup(mp_set_t *set, mp_obj_t index, mp_map_lookup_kind_t looku
} else { } else {
return MP_OBJ_NULL; return MP_OBJ_NULL;
} }
} else if (lookup_kind & MP_MAP_LOOKUP_FIRST || mp_obj_equal(elem, index)) { } else if ((lookup_kind & MP_MAP_LOOKUP_FIRST) || mp_obj_equal(elem, index)) {
// found it // found it
if (lookup_kind & MP_MAP_LOOKUP_REMOVE_IF_FOUND) { if (lookup_kind & MP_MAP_LOOKUP_REMOVE_IF_FOUND) {
set->used--; set->used--;
...@@ -210,11 +241,8 @@ mp_obj_t mp_set_lookup(mp_set_t *set, mp_obj_t index, mp_map_lookup_kind_t looku ...@@ -210,11 +241,8 @@ mp_obj_t mp_set_lookup(mp_set_t *set, mp_obj_t index, mp_map_lookup_kind_t looku
} }
void mp_set_clear(mp_set_t *set) { void mp_set_clear(mp_set_t *set) {
set->used = 0; m_del(mp_obj_t, set->table, set->alloc);
machine_uint_t a = set->alloc;
set->alloc = 0; set->alloc = 0;
set->table = m_renew(mp_obj_t, set->table, a, set->alloc); set->used = 0;
for (uint i=0; i<set->alloc; i++) { set->table = NULL;
set->table[i] = NULL;
}
} }
...@@ -6,7 +6,8 @@ typedef struct _mp_map_elem_t { ...@@ -6,7 +6,8 @@ typedef struct _mp_map_elem_t {
typedef struct _mp_map_t { typedef struct _mp_map_t {
struct { struct {
machine_uint_t all_keys_are_qstrs : 1; machine_uint_t all_keys_are_qstrs : 1;
machine_uint_t used : (8 * sizeof(machine_uint_t) - 1); machine_uint_t table_is_fixed_array : 1;
machine_uint_t used : (8 * sizeof(machine_uint_t) - 2);
}; };
machine_uint_t alloc; machine_uint_t alloc;
mp_map_elem_t *table; mp_map_elem_t *table;
...@@ -27,6 +28,7 @@ typedef enum _mp_map_lookup_kind_t { ...@@ -27,6 +28,7 @@ typedef enum _mp_map_lookup_kind_t {
int get_doubling_prime_greater_or_equal_to(int x); int get_doubling_prime_greater_or_equal_to(int x);
void mp_map_init(mp_map_t *map, int n); void mp_map_init(mp_map_t *map, int n);
void mp_map_init_fixed_table(mp_map_t *map, int n, const mp_obj_t *table);
mp_map_t *mp_map_new(int n); mp_map_t *mp_map_new(int n);
void mp_map_deinit(mp_map_t *map); void mp_map_deinit(mp_map_t *map);
void mp_map_free(mp_map_t *map); void mp_map_free(mp_map_t *map);
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment