Skip to content

Commit 0197864

Browse files
committed
py/objset: Simplify set and frozenset by separating their locals dicts.
A lot of set's methods (the mutable ones) are not allowed to operate on a frozenset, and giving frozenset a separate locals dict with only the methods that it supports allows to simplify the logic that verifies if args are a set or a frozenset. Even though the new frozenset locals dict is relatively large (88 bytes on 32-bit archs) there is a much bigger saving coming from the removal of a const string for an error message, along with the removal of some checks for set or frozenset type. Changes in code size due to this patch are (for ports that changed at all): unix x64: -56 unix nanbox: -304 stm32: -64 esp8266: -124 cc3200: -40 Apart from the reduced code, frozenset now has better tab-completion because it only lists the valid methods. And the error message for accessing an invalid method is now more detailed (it includes the method name that wasn't found).
1 parent 8e0b9f4 commit 0197864

1 file changed

Lines changed: 30 additions & 41 deletions

File tree

py/objset.c

Lines changed: 30 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
*
44
* The MIT License (MIT)
55
*
6-
* Copyright (c) 2013, 2014 Damien P. George
6+
* Copyright (c) 2013-2017 Damien P. George
77
*
88
* Permission is hereby granted, free of charge, to any person obtaining a copy
99
* of this software and associated documentation files (the "Software"), to deal
@@ -57,23 +57,13 @@ STATIC bool is_set_or_frozenset(mp_obj_t o) {
5757
;
5858
}
5959

60+
// This macro is shorthand for mp_check_self to verify the argument is a set.
61+
#define check_set(o) mp_check_self(MP_OBJ_IS_TYPE(o, &mp_type_set))
62+
6063
// This macro is shorthand for mp_check_self to verify the argument is a
6164
// set or frozenset for methods that operate on both of these types.
6265
#define check_set_or_frozenset(o) mp_check_self(is_set_or_frozenset(o))
6366

64-
// This function is used to verify the argument for methods that modify
65-
// the set object, and raises an exception if the arg is a frozenset.
66-
STATIC void check_set(mp_obj_t o) {
67-
#if MICROPY_PY_BUILTINS_FROZENSET
68-
if (MP_OBJ_IS_TYPE(o, &mp_type_frozenset)) {
69-
// Mutable method called on frozenset; emulate CPython behavior, eg:
70-
// AttributeError: 'frozenset' object has no attribute 'add'
71-
mp_raise_msg(&mp_type_AttributeError, "'frozenset' has no such attribute");
72-
}
73-
#endif
74-
mp_check_self(MP_OBJ_IS_TYPE(o, &mp_type_set));
75-
}
76-
7767
STATIC void set_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
7868
(void)kind;
7969
mp_obj_set_t *self = MP_OBJ_TO_PTR(self_in);
@@ -188,26 +178,16 @@ STATIC mp_obj_t set_clear(mp_obj_t self_in) {
188178
}
189179
STATIC MP_DEFINE_CONST_FUN_OBJ_1(set_clear_obj, set_clear);
190180

191-
STATIC mp_obj_t set_copy_as_mutable(mp_obj_t self_in) {
181+
STATIC mp_obj_t set_copy(mp_obj_t self_in) {
182+
check_set_or_frozenset(self_in);
192183
mp_obj_set_t *self = MP_OBJ_TO_PTR(self_in);
193-
194184
mp_obj_set_t *other = m_new_obj(mp_obj_set_t);
195-
other->base.type = &mp_type_set;
185+
other->base.type = self->base.type;
196186
mp_set_init(&other->set, self->set.alloc);
197187
other->set.used = self->set.used;
198188
memcpy(other->set.table, self->set.table, self->set.alloc * sizeof(mp_obj_t));
199-
200189
return MP_OBJ_FROM_PTR(other);
201190
}
202-
203-
STATIC mp_obj_t set_copy(mp_obj_t self_in) {
204-
check_set_or_frozenset(self_in);
205-
206-
mp_obj_t other = set_copy_as_mutable(self_in);
207-
((mp_obj_base_t*)MP_OBJ_TO_PTR(other))->type = ((mp_obj_base_t*)MP_OBJ_TO_PTR(self_in))->type;
208-
209-
return other;
210-
}
211191
STATIC MP_DEFINE_CONST_FUN_OBJ_1(set_copy_obj, set_copy);
212192

213193
STATIC mp_obj_t set_discard(mp_obj_t self_in, mp_obj_t item) {
@@ -224,25 +204,23 @@ STATIC mp_obj_t set_diff_int(size_t n_args, const mp_obj_t *args, bool update) {
224204
check_set(args[0]);
225205
self = args[0];
226206
} else {
227-
check_set_or_frozenset(args[0]);
228-
self = set_copy_as_mutable(args[0]);
207+
self = set_copy(args[0]);
229208
}
230209

231-
232210
for (size_t i = 1; i < n_args; i++) {
233211
mp_obj_t other = args[i];
234212
if (self == other) {
235213
set_clear(self);
236214
} else {
215+
mp_set_t *self_set = &((mp_obj_set_t*)MP_OBJ_TO_PTR(self))->set;
237216
mp_obj_t iter = mp_getiter(other, NULL);
238217
mp_obj_t next;
239218
while ((next = mp_iternext(iter)) != MP_OBJ_STOP_ITERATION) {
240-
set_discard(self, next);
219+
mp_set_lookup(self_set, next, MP_MAP_LOOKUP_REMOVE_IF_FOUND);
241220
}
242221
}
243222
}
244223

245-
((mp_obj_base_t*)MP_OBJ_TO_PTR(self))->type = ((mp_obj_base_t*)MP_OBJ_TO_PTR(args[0]))->type;
246224
return self;
247225
}
248226

@@ -333,16 +311,16 @@ STATIC mp_obj_t set_issubset_internal(mp_obj_t self_in, mp_obj_t other_in, bool
333311
other = MP_OBJ_TO_PTR(set_make_new(&mp_type_set, 1, 0, &other_in));
334312
cleanup_other = true;
335313
}
336-
bool out = true;
314+
mp_obj_t out = mp_const_true;
337315
if (proper && self->set.used == other->set.used) {
338-
out = false;
316+
out = mp_const_false;
339317
} else {
340318
mp_obj_iter_buf_t iter_buf;
341319
mp_obj_t iter = set_getiter(MP_OBJ_FROM_PTR(self), &iter_buf);
342320
mp_obj_t next;
343321
while ((next = set_it_iternext(iter)) != MP_OBJ_STOP_ITERATION) {
344322
if (!mp_set_lookup(&other->set, next, MP_MAP_LOOKUP)) {
345-
out = false;
323+
out = mp_const_false;
346324
break;
347325
}
348326
}
@@ -354,7 +332,7 @@ STATIC mp_obj_t set_issubset_internal(mp_obj_t self_in, mp_obj_t other_in, bool
354332
if (cleanup_other) {
355333
set_clear(MP_OBJ_FROM_PTR(other));
356334
}
357-
return mp_obj_new_bool(out);
335+
return out;
358336
}
359337
STATIC mp_obj_t set_issubset(mp_obj_t self_in, mp_obj_t other_in) {
360338
return set_issubset_internal(self_in, other_in, false);
@@ -409,7 +387,7 @@ STATIC mp_obj_t set_remove(mp_obj_t self_in, mp_obj_t item) {
409387
STATIC MP_DEFINE_CONST_FUN_OBJ_2(set_remove_obj, set_remove);
410388

411389
STATIC mp_obj_t set_symmetric_difference_update(mp_obj_t self_in, mp_obj_t other_in) {
412-
check_set(self_in);
390+
check_set_or_frozenset(self_in); // can be frozenset due to call from set_symmetric_difference
413391
mp_obj_set_t *self = MP_OBJ_TO_PTR(self_in);
414392
mp_obj_t iter = mp_getiter(other_in, NULL);
415393
mp_obj_t next;
@@ -421,10 +399,8 @@ STATIC mp_obj_t set_symmetric_difference_update(mp_obj_t self_in, mp_obj_t other
421399
STATIC MP_DEFINE_CONST_FUN_OBJ_2(set_symmetric_difference_update_obj, set_symmetric_difference_update);
422400

423401
STATIC mp_obj_t set_symmetric_difference(mp_obj_t self_in, mp_obj_t other_in) {
424-
check_set_or_frozenset(self_in);
425-
mp_obj_t self_out = set_copy_as_mutable(self_in);
402+
mp_obj_t self_out = set_copy(self_in);
426403
set_symmetric_difference_update(self_out, other_in);
427-
((mp_obj_base_t*)MP_OBJ_TO_PTR(self_out))->type = ((mp_obj_base_t*)MP_OBJ_TO_PTR(self_in))->type;
428404
return self_out;
429405
}
430406
STATIC MP_DEFINE_CONST_FUN_OBJ_2(set_symmetric_difference_obj, set_symmetric_difference);
@@ -578,6 +554,19 @@ const mp_obj_type_t mp_type_set = {
578554
};
579555

580556
#if MICROPY_PY_BUILTINS_FROZENSET
557+
STATIC const mp_rom_map_elem_t frozenset_locals_dict_table[] = {
558+
{ MP_ROM_QSTR(MP_QSTR_copy), MP_ROM_PTR(&set_copy_obj) },
559+
{ MP_ROM_QSTR(MP_QSTR_difference), MP_ROM_PTR(&set_diff_obj) },
560+
{ MP_ROM_QSTR(MP_QSTR_intersection), MP_ROM_PTR(&set_intersect_obj) },
561+
{ MP_ROM_QSTR(MP_QSTR_isdisjoint), MP_ROM_PTR(&set_isdisjoint_obj) },
562+
{ MP_ROM_QSTR(MP_QSTR_issubset), MP_ROM_PTR(&set_issubset_obj) },
563+
{ MP_ROM_QSTR(MP_QSTR_issuperset), MP_ROM_PTR(&set_issuperset_obj) },
564+
{ MP_ROM_QSTR(MP_QSTR_symmetric_difference), MP_ROM_PTR(&set_symmetric_difference_obj) },
565+
{ MP_ROM_QSTR(MP_QSTR_union), MP_ROM_PTR(&set_union_obj) },
566+
{ MP_ROM_QSTR(MP_QSTR___contains__), MP_ROM_PTR(&mp_op_contains_obj) },
567+
};
568+
STATIC MP_DEFINE_CONST_DICT(frozenset_locals_dict, frozenset_locals_dict_table);
569+
581570
const mp_obj_type_t mp_type_frozenset = {
582571
{ &mp_type_type },
583572
.name = MP_QSTR_frozenset,
@@ -586,7 +575,7 @@ const mp_obj_type_t mp_type_frozenset = {
586575
.unary_op = set_unary_op,
587576
.binary_op = set_binary_op,
588577
.getiter = set_getiter,
589-
.locals_dict = (mp_obj_dict_t*)&set_locals_dict,
578+
.locals_dict = (mp_obj_dict_t*)&frozenset_locals_dict,
590579
};
591580
#endif
592581

0 commit comments

Comments
 (0)