Skip to content

Commit ea8d06c

Browse files
committed
py: Add MP_OBJ_STOP_ITERATION and make good use of it.
Also make consistent use of MP_OBJ_NOT_SUPPORTED and MP_OBJ_NULL. This helps a lot in debugging and understanding of function API.
1 parent 1e935d8 commit ea8d06c

28 files changed

+131
-122
lines changed

py/builtin.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_abs_obj, mp_builtin_abs);
103103
STATIC mp_obj_t mp_builtin_all(mp_obj_t o_in) {
104104
mp_obj_t iterable = mp_getiter(o_in);
105105
mp_obj_t item;
106-
while ((item = mp_iternext(iterable)) != MP_OBJ_NULL) {
106+
while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) {
107107
if (!mp_obj_is_true(item)) {
108108
return mp_const_false;
109109
}
@@ -116,7 +116,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_all_obj, mp_builtin_all);
116116
STATIC mp_obj_t mp_builtin_any(mp_obj_t o_in) {
117117
mp_obj_t iterable = mp_getiter(o_in);
118118
mp_obj_t item;
119-
while ((item = mp_iternext(iterable)) != MP_OBJ_NULL) {
119+
while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) {
120120
if (mp_obj_is_true(item)) {
121121
return mp_const_true;
122122
}
@@ -244,7 +244,7 @@ STATIC mp_obj_t mp_builtin_max(uint n_args, const mp_obj_t *args) {
244244
mp_obj_t iterable = mp_getiter(args[0]);
245245
mp_obj_t max_obj = NULL;
246246
mp_obj_t item;
247-
while ((item = mp_iternext(iterable)) != MP_OBJ_NULL) {
247+
while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) {
248248
if (max_obj == NULL || mp_binary_op(MP_BINARY_OP_LESS, max_obj, item)) {
249249
max_obj = item;
250250
}
@@ -273,7 +273,7 @@ STATIC mp_obj_t mp_builtin_min(uint n_args, const mp_obj_t *args) {
273273
mp_obj_t iterable = mp_getiter(args[0]);
274274
mp_obj_t min_obj = NULL;
275275
mp_obj_t item;
276-
while ((item = mp_iternext(iterable)) != MP_OBJ_NULL) {
276+
while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) {
277277
if (min_obj == NULL || mp_binary_op(MP_BINARY_OP_LESS, item, min_obj)) {
278278
min_obj = item;
279279
}
@@ -298,7 +298,7 @@ MP_DEFINE_CONST_FUN_OBJ_VAR(mp_builtin_min_obj, 1, mp_builtin_min);
298298

299299
STATIC mp_obj_t mp_builtin_next(mp_obj_t o) {
300300
mp_obj_t ret = mp_iternext_allow_raise(o);
301-
if (ret == MP_OBJ_NULL) {
301+
if (ret == MP_OBJ_STOP_ITERATION) {
302302
nlr_raise(mp_obj_new_exception(&mp_type_StopIteration));
303303
} else {
304304
return ret;
@@ -381,7 +381,7 @@ STATIC mp_obj_t mp_builtin_sum(uint n_args, const mp_obj_t *args) {
381381
}
382382
mp_obj_t iterable = mp_getiter(args[0]);
383383
mp_obj_t item;
384-
while ((item = mp_iternext(iterable)) != MP_OBJ_NULL) {
384+
while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) {
385385
value = mp_binary_op(MP_BINARY_OP_ADD, value, item);
386386
}
387387
return value;

py/obj.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ int mp_obj_is_true(mp_obj_t arg) {
9090
mp_obj_type_t *type = mp_obj_get_type(arg);
9191
if (type->unary_op != NULL) {
9292
mp_obj_t result = type->unary_op(MP_UNARY_OP_BOOL, arg);
93-
if (result != MP_OBJ_NULL) {
93+
if (result != MP_OBJ_NOT_SUPPORTED) {
9494
return result == mp_const_true;
9595
}
9696
}
@@ -180,7 +180,7 @@ bool mp_obj_equal(mp_obj_t o1, mp_obj_t o2) {
180180
mp_obj_type_t *type = mp_obj_get_type(o1);
181181
if (type->binary_op != NULL) {
182182
mp_obj_t r = type->binary_op(MP_BINARY_OP_EQUAL, o1, o2);
183-
if (r != MP_OBJ_NULL) {
183+
if (r != MP_OBJ_NOT_SUPPORTED) {
184184
return r == mp_const_true ? true : false;
185185
}
186186
}

py/obj.h

Lines changed: 29 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
// A Micro Python object is a machine word having the following form:
2+
// - xxxx...xxx1 : a small int, bits 1 and above are the value
3+
// - xxxx...xx10 : a qstr, bits 2 and above are the value
4+
// - xxxx...xx00 : a pointer to an mp_obj_base_t (unless a fake object)
5+
16
// All Micro Python objects are at least this type
27
// It must be of pointer size
38

@@ -10,32 +15,39 @@ typedef machine_const_ptr_t mp_const_obj_t;
1015
typedef machine_int_t mp_small_int_t;
1116

1217
// Anything that wants to be a Micro Python object must have
13-
// mp_obj_base_t as its first member (except NULL and small ints)
18+
// mp_obj_base_t as its first member (except small ints and qstrs)
1419

1520
struct _mp_obj_type_t;
1621
struct _mp_obj_base_t {
1722
const struct _mp_obj_type_t *type;
1823
};
1924
typedef struct _mp_obj_base_t mp_obj_base_t;
2025

21-
// The NULL object is used to indicate the absence of an object
22-
// It *cannot* be used when an mp_obj_t is expected, except where explicitly allowed
23-
24-
#define MP_OBJ_NULL ((mp_obj_t)0)
25-
26-
// The SENTINEL object is used for various internal purposes where one needs
27-
// an object which is unique from all other objects, including MP_OBJ_NULL.
28-
29-
#define MP_OBJ_SENTINEL ((mp_obj_t)8)
30-
31-
// The NOT_SUPPORTED object is a return value that indicates an unsupported operation.
32-
33-
#define MP_OBJ_NOT_SUPPORTED ((mp_obj_t)16)
26+
// These fake objects are used to indicate certain things in arguments or return
27+
// values, and should only be used when explicitly allowed.
28+
//
29+
// - MP_OBJ_NULL : used to indicate the absence of an object.
30+
// - MP_OBJ_NOT_SUPPORTED : a return value that indicates an unsupported operation.
31+
// - MP_OBJ_STOP_ITERATION : used instead of throwing a StopIteration, for efficiency.
32+
// - MP_OBJ_SENTINEL : used for various internal purposes where one needs
33+
// an object which is unique from all other objects, including MP_OBJ_NULL.
34+
//
35+
// For debugging purposes they are all different. For non-debug mode, we alias
36+
// as many as we can to MP_OBJ_NULL because it's cheaper to load/compare 0.
37+
38+
#if NDEBUG
39+
#define MP_OBJ_NULL ((mp_obj_t)0)
40+
#define MP_OBJ_NOT_SUPPORTED ((mp_obj_t)0)
41+
#define MP_OBJ_STOP_ITERATION ((mp_obj_t)0)
42+
#define MP_OBJ_SENTINEL ((mp_obj_t)4)
43+
#else
44+
#define MP_OBJ_NULL ((mp_obj_t)0)
45+
#define MP_OBJ_NOT_SUPPORTED ((mp_obj_t)4)
46+
#define MP_OBJ_STOP_ITERATION ((mp_obj_t)8)
47+
#define MP_OBJ_SENTINEL ((mp_obj_t)12)
48+
#endif
3449

3550
// These macros check for small int, qstr or object, and access small int and qstr values
36-
// - xxxx...xxx1: a small int, bits 1 and above are the value
37-
// - xxxx...xx10: a qstr, bits 2 and above are the value
38-
// - xxxx...xx00: a pointer to an mp_obj_base_t
3951

4052
// In SMALL_INT, next-to-highest bits is used as sign, so both must match for value in range
4153
#define MP_SMALL_INT_MIN ((mp_small_int_t)(((machine_int_t)WORD_MSBIT_HIGH) >> 1))

py/objarray.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ STATIC mp_obj_t array_construct(char typecode, mp_obj_t initializer) {
6363
mp_obj_t iterable = mp_getiter(initializer);
6464
mp_obj_t item;
6565
int i = 0;
66-
while ((item = mp_iternext(iterable)) != MP_OBJ_NULL) {
66+
while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) {
6767
if (len == 0) {
6868
array_append(array, item);
6969
} else {
@@ -108,7 +108,7 @@ STATIC mp_obj_t array_unary_op(int op, mp_obj_t o_in) {
108108
switch (op) {
109109
case MP_UNARY_OP_BOOL: return MP_BOOL(o->len != 0);
110110
case MP_UNARY_OP_LEN: return MP_OBJ_NEW_SMALL_INT(o->len);
111-
default: return MP_OBJ_NULL; // op not supported
111+
default: return MP_OBJ_NOT_SUPPORTED;
112112
}
113113
}
114114

@@ -227,7 +227,7 @@ STATIC mp_obj_t array_it_iternext(mp_obj_t self_in) {
227227
if (self->cur < self->array->len) {
228228
return mp_binary_get_val_array(self->array->typecode, self->array->items, self->cur++);
229229
} else {
230-
return MP_OBJ_NULL;
230+
return MP_OBJ_STOP_ITERATION;
231231
}
232232
}
233233

py/objbool.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,7 @@ STATIC mp_obj_t bool_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
4848
if (MP_BINARY_OP_OR <= op && op <= MP_BINARY_OP_NOT_EQUAL) {
4949
return mp_binary_op(op, MP_OBJ_NEW_SMALL_INT((machine_int_t)mp_obj_is_true(lhs_in)), rhs_in);
5050
}
51-
// operation not supported
52-
return MP_OBJ_NULL;
51+
return MP_OBJ_NOT_SUPPORTED;
5352
}
5453

5554
const mp_obj_type_t mp_type_bool = {

py/objcomplex.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ STATIC mp_obj_t complex_unary_op(int op, mp_obj_t o_in) {
9898
case MP_UNARY_OP_BOOL: return MP_BOOL(o->real != 0 || o->imag != 0);
9999
case MP_UNARY_OP_POSITIVE: return o_in;
100100
case MP_UNARY_OP_NEGATIVE: return mp_obj_new_complex(-o->real, -o->imag);
101-
default: return MP_OBJ_NULL; // op not supported
101+
default: return MP_OBJ_NOT_SUPPORTED;
102102
}
103103
}
104104

@@ -208,7 +208,7 @@ mp_obj_t mp_obj_complex_binary_op(int op, mp_float_t lhs_real, mp_float_t lhs_im
208208
case MP_BINARY_OP_EQUAL: return MP_BOOL(lhs_real == rhs_real && lhs_imag == rhs_imag);
209209

210210
default:
211-
return MP_OBJ_NULL; // op not supported
211+
return MP_OBJ_NOT_SUPPORTED;
212212
}
213213
return mp_obj_new_complex(lhs_real, lhs_imag);
214214
}

py/objdict.c

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ STATIC void dict_print(void (*print)(void *env, const char *fmt, ...), void *env
2222
print(env, "{");
2323
mp_obj_t *dict_iter = mp_obj_new_dict_iterator(self, 0);
2424
mp_map_elem_t *next = NULL;
25-
while ((next = dict_it_iternext_elem(dict_iter)) != NULL) {
25+
while ((next = dict_it_iternext_elem(dict_iter)) != MP_OBJ_STOP_ITERATION) {
2626
if (!first) {
2727
print(env, ", ");
2828
}
@@ -52,7 +52,7 @@ STATIC mp_obj_t dict_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp
5252
mp_obj_t dict = mp_obj_new_dict(0);
5353
// TODO: support arbitrary seq as a pair
5454
mp_obj_t item;
55-
while ((item = mp_iternext(iterable)) != MP_OBJ_NULL) {
55+
while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) {
5656
mp_obj_t *sub_items;
5757
mp_obj_get_array_fixed_n(item, 2, &sub_items);
5858
mp_obj_dict_store(dict, sub_items[0], sub_items[1]);
@@ -77,7 +77,7 @@ STATIC mp_obj_t dict_unary_op(int op, mp_obj_t self_in) {
7777
switch (op) {
7878
case MP_UNARY_OP_BOOL: return MP_BOOL(self->map.used != 0);
7979
case MP_UNARY_OP_LEN: return MP_OBJ_NEW_SMALL_INT((machine_int_t)self->map.used);
80-
default: return MP_OBJ_NULL; // op not supported for None
80+
default: return MP_OBJ_NOT_SUPPORTED;
8181
}
8282
}
8383

@@ -114,7 +114,7 @@ STATIC mp_obj_t dict_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
114114
}
115115
default:
116116
// op not supported
117-
return NULL;
117+
return MP_OBJ_NOT_SUPPORTED;
118118
}
119119
}
120120

@@ -160,16 +160,16 @@ STATIC mp_map_elem_t *dict_it_iternext_elem(mp_obj_t self_in) {
160160
}
161161
}
162162

163-
return NULL;
163+
return MP_OBJ_STOP_ITERATION;
164164
}
165165

166166
mp_obj_t dict_it_iternext(mp_obj_t self_in) {
167167
mp_map_elem_t *next = dict_it_iternext_elem(self_in);
168168

169-
if (next != NULL) {
169+
if (next != MP_OBJ_STOP_ITERATION) {
170170
return next->key;
171171
} else {
172-
return MP_OBJ_NULL;
172+
return MP_OBJ_STOP_ITERATION;
173173
}
174174
}
175175

@@ -237,7 +237,7 @@ STATIC mp_obj_t dict_fromkeys(uint n_args, const mp_obj_t *args) {
237237
self = mp_obj_new_dict(MP_OBJ_SMALL_INT_VALUE(len));
238238
}
239239

240-
while ((next = mp_iternext(iter)) != MP_OBJ_NULL) {
240+
while ((next = mp_iternext(iter)) != MP_OBJ_STOP_ITERATION) {
241241
mp_map_lookup(&self->map, next, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = value;
242242
}
243243

@@ -328,14 +328,14 @@ STATIC mp_obj_t dict_update(mp_obj_t self_in, mp_obj_t iterable) {
328328
/* TODO: check for the "keys" method */
329329
mp_obj_t iter = mp_getiter(iterable);
330330
mp_obj_t next = NULL;
331-
while ((next = mp_iternext(iter)) != MP_OBJ_NULL) {
331+
while ((next = mp_iternext(iter)) != MP_OBJ_STOP_ITERATION) {
332332
mp_obj_t inneriter = mp_getiter(next);
333333
mp_obj_t key = mp_iternext(inneriter);
334334
mp_obj_t value = mp_iternext(inneriter);
335335
mp_obj_t stop = mp_iternext(inneriter);
336-
if (key == MP_OBJ_NULL
337-
|| value == MP_OBJ_NULL
338-
|| stop != MP_OBJ_NULL) {
336+
if (key == MP_OBJ_STOP_ITERATION
337+
|| value == MP_OBJ_STOP_ITERATION
338+
|| stop != MP_OBJ_STOP_ITERATION) {
339339
nlr_raise(mp_obj_new_exception_msg(
340340
&mp_type_ValueError,
341341
"dictionary update sequence has the wrong length"));
@@ -381,7 +381,7 @@ STATIC mp_obj_t dict_view_it_iternext(mp_obj_t self_in) {
381381
mp_obj_dict_view_it_t *self = self_in;
382382
mp_map_elem_t *next = dict_it_iternext_elem(self->iter);
383383

384-
if (next != NULL) {
384+
if (next != MP_OBJ_STOP_ITERATION) {
385385
switch (self->kind) {
386386
case MP_DICT_VIEW_ITEMS:
387387
{
@@ -397,7 +397,7 @@ STATIC mp_obj_t dict_view_it_iternext(mp_obj_t self_in) {
397397
return mp_const_none;
398398
}
399399
} else {
400-
return MP_OBJ_NULL;
400+
return MP_OBJ_STOP_ITERATION;
401401
}
402402
}
403403

@@ -426,7 +426,7 @@ STATIC void dict_view_print(void (*print)(void *env, const char *fmt, ...), void
426426
print(env, "([");
427427
mp_obj_t *self_iter = dict_view_getiter(self);
428428
mp_obj_t *next = NULL;
429-
while ((next = dict_view_it_iternext(self_iter)) != MP_OBJ_NULL) {
429+
while ((next = dict_view_it_iternext(self_iter)) != MP_OBJ_STOP_ITERATION) {
430430
if (!first) {
431431
print(env, ", ");
432432
}

py/objenumerate.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,8 @@ STATIC mp_obj_t enumerate_iternext(mp_obj_t self_in) {
3838
assert(MP_OBJ_IS_TYPE(self_in, &mp_type_enumerate));
3939
mp_obj_enumerate_t *self = self_in;
4040
mp_obj_t next = mp_iternext(self->iter);
41-
if (next == MP_OBJ_NULL) {
42-
return MP_OBJ_NULL;
41+
if (next == MP_OBJ_STOP_ITERATION) {
42+
return MP_OBJ_STOP_ITERATION;
4343
} else {
4444
mp_obj_t items[] = {MP_OBJ_NEW_SMALL_INT(self->cur++), next};
4545
return mp_obj_new_tuple(2, items);

py/objfilter.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ STATIC mp_obj_t filter_iternext(mp_obj_t self_in) {
3030
assert(MP_OBJ_IS_TYPE(self_in, &mp_type_filter));
3131
mp_obj_filter_t *self = self_in;
3232
mp_obj_t next;
33-
while ((next = mp_iternext(self->iter)) != MP_OBJ_NULL) {
33+
while ((next = mp_iternext(self->iter)) != MP_OBJ_STOP_ITERATION) {
3434
mp_obj_t val;
3535
if (self->fun != mp_const_none) {
3636
val = mp_call_function_n_kw(self->fun, 1, 0, &next);
@@ -41,7 +41,7 @@ STATIC mp_obj_t filter_iternext(mp_obj_t self_in) {
4141
return next;
4242
}
4343
}
44-
return MP_OBJ_NULL;
44+
return MP_OBJ_STOP_ITERATION;
4545
}
4646

4747
const mp_obj_type_t mp_type_filter = {

py/objfloat.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ mp_obj_t mp_obj_float_binary_op(int op, mp_float_t lhs_val, mp_obj_t rhs_in) {
140140
case MP_BINARY_OP_MORE_EQUAL: return MP_BOOL(lhs_val >= rhs_val);
141141

142142
default:
143-
return MP_OBJ_NULL; // op not supported
143+
return MP_OBJ_NOT_SUPPORTED;
144144
}
145145
return mp_obj_new_float(lhs_val);
146146
}

0 commit comments

Comments
 (0)