Skip to content

Commit 9a58d76

Browse files
committed
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.
1 parent 698ec21 commit 9a58d76

2 files changed

Lines changed: 51 additions & 21 deletions

File tree

py/map.c

Lines changed: 48 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,24 @@ int get_doubling_prime_greater_or_equal_to(int x) {
2828
/* map */
2929

3030
void mp_map_init(mp_map_t *map, int n) {
31-
map->alloc = get_doubling_prime_greater_or_equal_to(n + 1);
31+
if (n == 0) {
32+
map->alloc = 0;
33+
map->table = NULL;
34+
} else {
35+
map->alloc = get_doubling_prime_greater_or_equal_to(n + 1);
36+
map->table = m_new0(mp_map_elem_t, map->alloc);
37+
}
3238
map->used = 0;
3339
map->all_keys_are_qstrs = 1;
34-
map->table = m_new0(mp_map_elem_t, map->alloc);
40+
map->table_is_fixed_array = 0;
41+
}
42+
43+
void mp_map_init_fixed_table(mp_map_t *map, int n, const mp_obj_t *table) {
44+
map->alloc = n;
45+
map->used = n;
46+
map->all_keys_are_qstrs = 1;
47+
map->table_is_fixed_array = 1;
48+
map->table = (mp_map_elem_t*)table;
3549
}
3650

3751
mp_map_t *mp_map_new(int n) {
@@ -42,7 +56,9 @@ mp_map_t *mp_map_new(int n) {
4256

4357
// Differentiate from mp_map_clear() - semantics is different
4458
void mp_map_deinit(mp_map_t *map) {
45-
m_del(mp_map_elem_t, map->table, map->alloc);
59+
if (!map->table_is_fixed_array) {
60+
m_del(mp_map_elem_t, map->table, map->alloc);
61+
}
4662
map->used = map->alloc = 0;
4763
}
4864

@@ -52,15 +68,14 @@ void mp_map_free(mp_map_t *map) {
5268
}
5369

5470
void mp_map_clear(mp_map_t *map) {
71+
if (!map->table_is_fixed_array) {
72+
m_del(mp_map_elem_t, map->table, map->alloc);
73+
}
74+
map->alloc = 0;
5575
map->used = 0;
5676
map->all_keys_are_qstrs = 1;
57-
machine_uint_t a = map->alloc;
58-
map->alloc = 0;
59-
map->table = m_renew(mp_map_elem_t, map->table, a, map->alloc);
60-
mp_map_elem_t nul = {NULL, NULL};
61-
for (uint i=0; i<map->alloc; i++) {
62-
map->table[i] = nul;
63-
}
77+
map->table_is_fixed_array = 0;
78+
map->table = NULL;
6479
}
6580

6681
static void mp_map_rehash(mp_map_t *map) {
@@ -79,21 +94,37 @@ static void mp_map_rehash(mp_map_t *map) {
7994
}
8095

8196
mp_map_elem_t* mp_map_lookup(mp_map_t *map, mp_obj_t index, mp_map_lookup_kind_t lookup_kind) {
97+
// if the map is a fixed array then we must do a brute force linear search
98+
if (map->table_is_fixed_array) {
99+
if (lookup_kind != MP_MAP_LOOKUP) {
100+
return NULL;
101+
}
102+
for (mp_map_elem_t *elem = &map->table[0], *top = &map->table[map->used]; elem < top; elem++) {
103+
if (elem->key == index || (!map->all_keys_are_qstrs && mp_obj_equal(elem->key, index))) {
104+
return elem;
105+
}
106+
}
107+
return NULL;
108+
}
109+
110+
// map is a hash table (not a fixed array), so do a hash lookup
111+
82112
machine_uint_t hash;
83113
hash = mp_obj_hash(index);
84114
if (map->alloc == 0) {
85-
if (lookup_kind == MP_MAP_LOOKUP_ADD_IF_NOT_FOUND) {
115+
if (lookup_kind & MP_MAP_LOOKUP_ADD_IF_NOT_FOUND) {
86116
mp_map_rehash(map);
87117
} else {
88118
return NULL;
89119
}
90120
}
121+
91122
uint pos = hash % map->alloc;
92123
for (;;) {
93124
mp_map_elem_t *elem = &map->table[pos];
94125
if (elem->key == NULL) {
95126
// not in table
96-
if (lookup_kind == MP_MAP_LOOKUP_ADD_IF_NOT_FOUND) {
127+
if (lookup_kind & MP_MAP_LOOKUP_ADD_IF_NOT_FOUND) {
97128
if (map->used + 1 >= map->alloc) {
98129
// not enough room in table, rehash it
99130
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
117148
elem->key = index;
118149
}
119150
*/
120-
if (lookup_kind == MP_MAP_LOOKUP_REMOVE_IF_FOUND) {
151+
if (lookup_kind & MP_MAP_LOOKUP_REMOVE_IF_FOUND) {
121152
map->used--;
122153
// this leaks this memory (but see dict_get_helper)
123154
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
195226
} else {
196227
return MP_OBJ_NULL;
197228
}
198-
} else if (lookup_kind & MP_MAP_LOOKUP_FIRST || mp_obj_equal(elem, index)) {
229+
} else if ((lookup_kind & MP_MAP_LOOKUP_FIRST) || mp_obj_equal(elem, index)) {
199230
// found it
200231
if (lookup_kind & MP_MAP_LOOKUP_REMOVE_IF_FOUND) {
201232
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
210241
}
211242

212243
void mp_set_clear(mp_set_t *set) {
213-
set->used = 0;
214-
machine_uint_t a = set->alloc;
244+
m_del(mp_obj_t, set->table, set->alloc);
215245
set->alloc = 0;
216-
set->table = m_renew(mp_obj_t, set->table, a, set->alloc);
217-
for (uint i=0; i<set->alloc; i++) {
218-
set->table[i] = NULL;
219-
}
246+
set->used = 0;
247+
set->table = NULL;
220248
}

py/map.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ typedef struct _mp_map_elem_t {
66
typedef struct _mp_map_t {
77
struct {
88
machine_uint_t all_keys_are_qstrs : 1;
9-
machine_uint_t used : (8 * sizeof(machine_uint_t) - 1);
9+
machine_uint_t table_is_fixed_array : 1;
10+
machine_uint_t used : (8 * sizeof(machine_uint_t) - 2);
1011
};
1112
machine_uint_t alloc;
1213
mp_map_elem_t *table;
@@ -27,6 +28,7 @@ typedef enum _mp_map_lookup_kind_t {
2728

2829
int get_doubling_prime_greater_or_equal_to(int x);
2930
void mp_map_init(mp_map_t *map, int n);
31+
void mp_map_init_fixed_table(mp_map_t *map, int n, const mp_obj_t *table);
3032
mp_map_t *mp_map_new(int n);
3133
void mp_map_deinit(mp_map_t *map);
3234
void mp_map_free(mp_map_t *map);

0 commit comments

Comments
 (0)