objset.c 18.7 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/*
 * This file is part of the Micro Python project, http://micropython.org/
 *
 * The MIT License (MIT)
 *
 * Copyright (c) 2013, 2014 Damien P. George
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

xbe's avatar
xbe committed
27
#include <stdbool.h>
John R. Lenton's avatar
John R. Lenton committed
28
#include <string.h>
29
30
#include <assert.h>

31
#include "mpconfig.h"
32
33
#include "nlr.h"
#include "misc.h"
34
#include "qstr.h"
35
#include "obj.h"
36
#include "runtime.h"
37
#include "runtime0.h"
38
#include "builtin.h"
39
40
41
42
43
44

typedef struct _mp_obj_set_t {
    mp_obj_base_t base;
    mp_set_t set;
} mp_obj_set_t;

John R. Lenton's avatar
John R. Lenton committed
45
46
47
48
49
50
typedef struct _mp_obj_set_it_t {
    mp_obj_base_t base;
    mp_obj_set_t *set;
    machine_uint_t cur;
} mp_obj_set_it_t;

51
STATIC mp_obj_t set_it_iternext(mp_obj_t self_in);
John R. Lenton's avatar
John R. Lenton committed
52

53
STATIC bool is_set_or_frozenset(mp_obj_t o) {
54
55
56
57
58
    return MP_OBJ_IS_TYPE(o, &mp_type_set)
#if MICROPY_ENABLE_FROZENSET
        || MP_OBJ_IS_TYPE(o, &mp_type_frozenset)
#endif
    ;
59
60
}

61
#if MICROPY_ENABLE_FROZENSET
62
63
64
65
66
STATIC void check_set_or_frozenset(mp_obj_t o) {
    if (!is_set_or_frozenset(o)) {
        nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'set' object required"));
    }
}
67
68
69
#else
#define check_set_or_frozenset(o) check_set(o)
#endif
70
71
72
73
74

STATIC void check_set(mp_obj_t o) {
    if (!MP_OBJ_IS_TYPE(o, &mp_type_set)) {
        // Emulate CPython behavior
        // AttributeError: 'frozenset' object has no attribute 'add'
75
        #if MICROPY_ENABLE_FROZENSET
76
77
78
        if (MP_OBJ_IS_TYPE(o, &mp_type_frozenset)) {
            nlr_raise(mp_obj_new_exception_msg(&mp_type_AttributeError, "'frozenset' has no such attribute"));
        }
79
        #endif
80
81
82
83
        nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'set' object required"));
    }
}

84
STATIC void set_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
85
    mp_obj_set_t *self = self_in;
86
    #if MICROPY_ENABLE_FROZENSET
87
    bool is_frozen = MP_OBJ_IS_TYPE(self_in, &mp_type_frozenset);
88
    #endif
89
    if (self->set.used == 0) {
90
        #if MICROPY_ENABLE_FROZENSET
91
92
93
        if (is_frozen) {
            print(env, "frozen");
        }
94
        #endif
95
96
97
        print(env, "set()");
        return;
    }
98
    bool first = true;
99
    #if MICROPY_ENABLE_FROZENSET
100
101
102
    if (is_frozen) {
        print(env, "frozenset(");
    }
103
    #endif
104
105
    print(env, "{");
    for (int i = 0; i < self->set.alloc; i++) {
106
        if (MP_SET_SLOT_IS_FILLED(&self->set, i)) {
107
108
109
110
            if (!first) {
                print(env, ", ");
            }
            first = false;
111
            mp_obj_print_helper(print, env, self->set.table[i], PRINT_REPR);
112
113
114
        }
    }
    print(env, "}");
115
    #if MICROPY_ENABLE_FROZENSET
116
117
118
    if (is_frozen) {
        print(env, ")");
    }
119
    #endif
120
121
}

122

123
STATIC mp_obj_t set_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) {
124
    mp_arg_check_num(n_args, n_kw, 0, 1, false);
125

126
    switch (n_args) {
127
128
129
130
131
132
133
        case 0: {
            // create a new, empty set
            mp_obj_set_t *set = mp_obj_new_set(0, NULL);
            // set actual set/frozenset type
            set->base.type = type_in;
            return set;
        }
134
135

        case 1:
136
        default: { // can only be 0 or 1 arg
137
            // 1 argument, an iterable from which we make a new set
138
            mp_obj_set_t *set = mp_obj_new_set(0, NULL);
Damien George's avatar
Damien George committed
139
            mp_obj_t iterable = mp_getiter(args[0]);
140
            mp_obj_t item;
141
            while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) {
142
143
                mp_obj_set_store(set, item);
            }
144
145
            // Set actual set/frozenset type
            set->base.type = type_in;
146
147
148
149
150
            return set;
        }
    }
}

151
const mp_obj_type_t mp_type_set_it = {
152
    { &mp_type_type },
153
    .name = MP_QSTR_iterator,
154
    .getiter = mp_identity,
John R. Lenton's avatar
John R. Lenton committed
155
156
157
    .iternext = set_it_iternext,
};

158
STATIC mp_obj_t set_it_iternext(mp_obj_t self_in) {
159
    assert(MP_OBJ_IS_TYPE(self_in, &mp_type_set_it));
John R. Lenton's avatar
John R. Lenton committed
160
161
    mp_obj_set_it_t *self = self_in;
    machine_uint_t max = self->set->set.alloc;
162
    mp_set_t *set = &self->set->set;
John R. Lenton's avatar
John R. Lenton committed
163
164

    for (machine_uint_t i = self->cur; i < max; i++) {
165
        if (MP_SET_SLOT_IS_FILLED(set, i)) {
John R. Lenton's avatar
John R. Lenton committed
166
            self->cur = i + 1;
167
            return set->table[i];
John R. Lenton's avatar
John R. Lenton committed
168
169
170
        }
    }

171
    return MP_OBJ_STOP_ITERATION;
John R. Lenton's avatar
John R. Lenton committed
172
173
}

174
STATIC mp_obj_t set_getiter(mp_obj_t set_in) {
John R. Lenton's avatar
John R. Lenton committed
175
    mp_obj_set_it_t *o = m_new_obj(mp_obj_set_it_t);
176
    o->base.type = &mp_type_set_it;
John R. Lenton's avatar
John R. Lenton committed
177
178
179
180
181
    o->set = (mp_obj_set_t *)set_in;
    o->cur = 0;
    return o;
}

John R. Lenton's avatar
John R. Lenton committed
182
183
184
185

/******************************************************************************/
/* set methods                                                                */

186
STATIC mp_obj_t set_add(mp_obj_t self_in, mp_obj_t item) {
187
    check_set(self_in);
John R. Lenton's avatar
John R. Lenton committed
188
    mp_obj_set_t *self = self_in;
John R. Lenton's avatar
John R. Lenton committed
189
    mp_set_lookup(&self->set, item, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND);
John R. Lenton's avatar
John R. Lenton committed
190
191
    return mp_const_none;
}
192
STATIC MP_DEFINE_CONST_FUN_OBJ_2(set_add_obj, set_add);
John R. Lenton's avatar
John R. Lenton committed
193

194
STATIC mp_obj_t set_clear(mp_obj_t self_in) {
195
    check_set(self_in);
John R. Lenton's avatar
John R. Lenton committed
196
197
198
199
200
201
    mp_obj_set_t *self = self_in;

    mp_set_clear(&self->set);

    return mp_const_none;
}
202
STATIC MP_DEFINE_CONST_FUN_OBJ_1(set_clear_obj, set_clear);
John R. Lenton's avatar
John R. Lenton committed
203

204
STATIC mp_obj_t set_copy_as_mutable(mp_obj_t self_in) {
John R. Lenton's avatar
John R. Lenton committed
205
206
207
    mp_obj_set_t *self = self_in;

    mp_obj_set_t *other = m_new_obj(mp_obj_set_t);
208
    other->base.type = &mp_type_set;
209
    mp_set_init(&other->set, self->set.alloc);
John R. Lenton's avatar
John R. Lenton committed
210
211
212
213
214
    other->set.used = self->set.used;
    memcpy(other->set.table, self->set.table, self->set.alloc * sizeof(mp_obj_t));

    return other;
}
215
216
217
218
219
220
221
222
223
224

STATIC mp_obj_t set_copy(mp_obj_t self_in) {
    check_set_or_frozenset(self_in);
    mp_obj_set_t *self = self_in;

    mp_obj_set_t *other = set_copy_as_mutable(self);
    other->base.type = self->base.type;

    return other;
}
225
STATIC MP_DEFINE_CONST_FUN_OBJ_1(set_copy_obj, set_copy);
John R. Lenton's avatar
John R. Lenton committed
226

227
STATIC mp_obj_t set_discard(mp_obj_t self_in, mp_obj_t item) {
228
    check_set(self_in);
John R. Lenton's avatar
John R. Lenton committed
229
230
231
232
    mp_obj_set_t *self = self_in;
    mp_set_lookup(&self->set, item, MP_MAP_LOOKUP_REMOVE_IF_FOUND);
    return mp_const_none;
}
233
STATIC MP_DEFINE_CONST_FUN_OBJ_2(set_discard_obj, set_discard);
John R. Lenton's avatar
John R. Lenton committed
234

235
STATIC mp_obj_t set_diff_int(int n_args, const mp_obj_t *args, bool update) {
236
    assert(n_args > 0);
237

238
239
    mp_obj_set_t *self;
    if (update) {
240
        check_set(args[0]);
241
242
        self = args[0];
    } else {
243
244
        check_set_or_frozenset(args[0]);
        self = set_copy_as_mutable(args[0]);
245
246
247
248
249
250
251
252
    }


    for (int i = 1; i < n_args; i++) {
        mp_obj_t other = args[i];
        if (self == other) {
            set_clear(self);
        } else {
Damien George's avatar
Damien George committed
253
            mp_obj_t iter = mp_getiter(other);
254
            mp_obj_t next;
255
            while ((next = mp_iternext(iter)) != MP_OBJ_STOP_ITERATION) {
256
257
258
259
260
                set_discard(self, next);
            }
        }
    }

261
    self->base.type = ((mp_obj_set_t*)args[0])->base.type;
262
263
264
    return self;
}

265
STATIC mp_obj_t set_diff(uint n_args, const mp_obj_t *args) {
266
267
    return set_diff_int(n_args, args, false);
}
268
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR(set_diff_obj, 1, set_diff);
269

270
STATIC mp_obj_t set_diff_update(uint n_args, const mp_obj_t *args) {
271
272
273
    set_diff_int(n_args, args, true);
    return mp_const_none;
}
274
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR(set_diff_update_obj, 1, set_diff_update);
275

276
STATIC mp_obj_t set_intersect_int(mp_obj_t self_in, mp_obj_t other, bool update) {
277
278
279
280
281
282
    if (update) {
        check_set(self_in);
    } else {
        check_set_or_frozenset(self_in);
    }

283
284
285
286
287
288
289
    if (self_in == other) {
        return update ? mp_const_none : set_copy(self_in);
    }

    mp_obj_set_t *self = self_in;
    mp_obj_set_t *out = mp_obj_new_set(0, NULL);

Damien George's avatar
Damien George committed
290
    mp_obj_t iter = mp_getiter(other);
291
    mp_obj_t next;
292
    while ((next = mp_iternext(iter)) != MP_OBJ_STOP_ITERATION) {
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
        if (mp_set_lookup(&self->set, next, MP_MAP_LOOKUP)) {
            set_add(out, next);
        }
    }

    if (update) {
        m_del(mp_obj_t, self->set.table, self->set.alloc);
        self->set.alloc = out->set.alloc;
        self->set.used = out->set.used;
        self->set.table = out->set.table;
    }

    return update ? mp_const_none : out;
}

308
STATIC mp_obj_t set_intersect(mp_obj_t self_in, mp_obj_t other) {
309
310
    return set_intersect_int(self_in, other, false);
}
311
STATIC MP_DEFINE_CONST_FUN_OBJ_2(set_intersect_obj, set_intersect);
312

313
STATIC mp_obj_t set_intersect_update(mp_obj_t self_in, mp_obj_t other) {
314
315
    return set_intersect_int(self_in, other, true);
}
316
STATIC MP_DEFINE_CONST_FUN_OBJ_2(set_intersect_update_obj, set_intersect_update);
317

318
STATIC mp_obj_t set_isdisjoint(mp_obj_t self_in, mp_obj_t other) {
319
    check_set_or_frozenset(self_in);
John R. Lenton's avatar
John R. Lenton committed
320
321
    mp_obj_set_t *self = self_in;

Damien George's avatar
Damien George committed
322
    mp_obj_t iter = mp_getiter(other);
John R. Lenton's avatar
John R. Lenton committed
323
    mp_obj_t next;
324
    while ((next = mp_iternext(iter)) != MP_OBJ_STOP_ITERATION) {
John R. Lenton's avatar
John R. Lenton committed
325
326
327
328
329
330
        if (mp_set_lookup(&self->set, next, MP_MAP_LOOKUP)) {
            return mp_const_false;
        }
    }
    return mp_const_true;
}
331
STATIC MP_DEFINE_CONST_FUN_OBJ_2(set_isdisjoint_obj, set_isdisjoint);
John R. Lenton's avatar
John R. Lenton committed
332

333
STATIC mp_obj_t set_issubset_internal(mp_obj_t self_in, mp_obj_t other_in, bool proper) {
John R. Lenton's avatar
John R. Lenton committed
334
335
    mp_obj_set_t *self;
    bool cleanup_self = false;
336
    if (is_set_or_frozenset(self_in)) {
John R. Lenton's avatar
John R. Lenton committed
337
338
        self = self_in;
    } else {
339
        self = set_make_new((mp_obj_t)&mp_type_set, 1, 0, &self_in);
John R. Lenton's avatar
John R. Lenton committed
340
341
342
343
344
        cleanup_self = true;
    }

    mp_obj_set_t *other;
    bool cleanup_other = false;
345
    if (is_set_or_frozenset(other_in)) {
John R. Lenton's avatar
John R. Lenton committed
346
347
        other = other_in;
    } else {
348
        other = set_make_new((mp_obj_t)&mp_type_set, 1, 0, &other_in);
John R. Lenton's avatar
John R. Lenton committed
349
350
        cleanup_other = true;
    }
John R. Lenton's avatar
John R. Lenton committed
351
352
353
354
355
356
    bool out = true;
    if (proper && self->set.used == other->set.used) {
        out = false;
    } else {
        mp_obj_t iter = set_getiter(self);
        mp_obj_t next;
357
        while ((next = set_it_iternext(iter)) != MP_OBJ_STOP_ITERATION) {
John R. Lenton's avatar
John R. Lenton committed
358
359
360
361
            if (!mp_set_lookup(&other->set, next, MP_MAP_LOOKUP)) {
                out = false;
                break;
            }
John R. Lenton's avatar
John R. Lenton committed
362
363
        }
    }
364
    // TODO: Should free objects altogether
John R. Lenton's avatar
John R. Lenton committed
365
366
367
368
369
370
    if (cleanup_self) {
        set_clear(self);
    }
    if (cleanup_other) {
        set_clear(other);
    }
John R. Lenton's avatar
John R. Lenton committed
371
372
    return MP_BOOL(out);
}
373
STATIC mp_obj_t set_issubset(mp_obj_t self_in, mp_obj_t other_in) {
John R. Lenton's avatar
John R. Lenton committed
374
    return set_issubset_internal(self_in, other_in, false);
John R. Lenton's avatar
John R. Lenton committed
375
}
376
STATIC MP_DEFINE_CONST_FUN_OBJ_2(set_issubset_obj, set_issubset);
John R. Lenton's avatar
John R. Lenton committed
377

378
STATIC mp_obj_t set_issubset_proper(mp_obj_t self_in, mp_obj_t other_in) {
John R. Lenton's avatar
John R. Lenton committed
379
380
381
    return set_issubset_internal(self_in, other_in, true);
}

382
STATIC mp_obj_t set_issuperset(mp_obj_t self_in, mp_obj_t other_in) {
John R. Lenton's avatar
John R. Lenton committed
383
    return set_issubset_internal(other_in, self_in, false);
John R. Lenton's avatar
John R. Lenton committed
384
}
385
STATIC MP_DEFINE_CONST_FUN_OBJ_2(set_issuperset_obj, set_issuperset);
John R. Lenton's avatar
John R. Lenton committed
386

387
STATIC mp_obj_t set_issuperset_proper(mp_obj_t self_in, mp_obj_t other_in) {
John R. Lenton's avatar
John R. Lenton committed
388
389
390
    return set_issubset_internal(other_in, self_in, true);
}

391
STATIC mp_obj_t set_equal(mp_obj_t self_in, mp_obj_t other_in) {
392
    check_set_or_frozenset(self_in);
John R. Lenton's avatar
John R. Lenton committed
393
    mp_obj_set_t *self = self_in;
394
    if (!is_set_or_frozenset(other_in)) {
John R. Lenton's avatar
John R. Lenton committed
395
396
397
398
399
400
401
402
403
        return mp_const_false;
    }
    mp_obj_set_t *other = other_in;
    if (self->set.used != other->set.used) {
        return mp_const_false;
    }
    return set_issubset(self_in, other_in);
}

404
STATIC mp_obj_t set_pop(mp_obj_t self_in) {
405
    check_set(self_in);
John R. Lenton's avatar
John R. Lenton committed
406
    mp_obj_set_t *self = self_in;
407
408
    mp_obj_t obj = mp_set_remove_first(&self->set);
    if (obj == MP_OBJ_NULL) {
409
        nlr_raise(mp_obj_new_exception_msg(&mp_type_KeyError, "pop from an empty set"));
John R. Lenton's avatar
John R. Lenton committed
410
411
412
    }
    return obj;
}
413
STATIC MP_DEFINE_CONST_FUN_OBJ_1(set_pop_obj, set_pop);
John R. Lenton's avatar
John R. Lenton committed
414

415
STATIC mp_obj_t set_remove(mp_obj_t self_in, mp_obj_t item) {
416
    check_set(self_in);
John R. Lenton's avatar
John R. Lenton committed
417
418
    mp_obj_set_t *self = self_in;
    if (mp_set_lookup(&self->set, item, MP_MAP_LOOKUP_REMOVE_IF_FOUND) == MP_OBJ_NULL) {
419
        nlr_raise(mp_obj_new_exception(&mp_type_KeyError));
John R. Lenton's avatar
John R. Lenton committed
420
421
422
    }
    return mp_const_none;
}
423
STATIC MP_DEFINE_CONST_FUN_OBJ_2(set_remove_obj, set_remove);
424

425
STATIC mp_obj_t set_symmetric_difference_update(mp_obj_t self_in, mp_obj_t other_in) {
426
    check_set(self_in);
John R. Lenton's avatar
John R. Lenton committed
427
    mp_obj_set_t *self = self_in;
Damien George's avatar
Damien George committed
428
    mp_obj_t iter = mp_getiter(other_in);
John R. Lenton's avatar
John R. Lenton committed
429
    mp_obj_t next;
430
    while ((next = mp_iternext(iter)) != MP_OBJ_STOP_ITERATION) {
John R. Lenton's avatar
John R. Lenton committed
431
432
433
434
        mp_set_lookup(&self->set, next, MP_MAP_LOOKUP_REMOVE_IF_FOUND | MP_MAP_LOOKUP_ADD_IF_NOT_FOUND);
    }
    return mp_const_none;
}
435
STATIC MP_DEFINE_CONST_FUN_OBJ_2(set_symmetric_difference_update_obj, set_symmetric_difference_update);
John R. Lenton's avatar
John R. Lenton committed
436

437
STATIC mp_obj_t set_symmetric_difference(mp_obj_t self_in, mp_obj_t other_in) {
438
439
440
441
442
    check_set_or_frozenset(self_in);
    mp_obj_set_t *self_out = set_copy_as_mutable(self_in);
    set_symmetric_difference_update(self_out, other_in);
    self_out->base.type = ((mp_obj_set_t*)self_in)->base.type;
    return self_out;
John R. Lenton's avatar
John R. Lenton committed
443
}
444
STATIC MP_DEFINE_CONST_FUN_OBJ_2(set_symmetric_difference_obj, set_symmetric_difference);
John R. Lenton's avatar
John R. Lenton committed
445

446
STATIC void set_update_int(mp_obj_set_t *self, mp_obj_t other_in) {
Damien George's avatar
Damien George committed
447
    mp_obj_t iter = mp_getiter(other_in);
John R. Lenton's avatar
John R. Lenton committed
448
    mp_obj_t next;
449
    while ((next = mp_iternext(iter)) != MP_OBJ_STOP_ITERATION) {
John R. Lenton's avatar
John R. Lenton committed
450
451
452
453
        mp_set_lookup(&self->set, next, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND);
    }
}

454
STATIC mp_obj_t set_update(uint n_args, const mp_obj_t *args) {
John R. Lenton's avatar
John R. Lenton committed
455
456
457
458
459
460
461
462
    assert(n_args > 0);

    for (int i = 1; i < n_args; i++) {
        set_update_int(args[0], args[i]);
    }

    return mp_const_none;
}
463
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR(set_update_obj, 1, set_update);
John R. Lenton's avatar
John R. Lenton committed
464

465
STATIC mp_obj_t set_union(mp_obj_t self_in, mp_obj_t other_in) {
466
    check_set_or_frozenset(self_in);
John R. Lenton's avatar
John R. Lenton committed
467
468
469
470
    mp_obj_set_t *self = set_copy(self_in);
    set_update_int(self, other_in);
    return self;
}
471
STATIC MP_DEFINE_CONST_FUN_OBJ_2(set_union_obj, set_union);
John R. Lenton's avatar
John R. Lenton committed
472

473
474
475
476
477
STATIC mp_obj_t set_unary_op(int op, mp_obj_t self_in) {
    mp_obj_set_t *self = self_in;
    switch (op) {
        case MP_UNARY_OP_BOOL: return MP_BOOL(self->set.used != 0);
        case MP_UNARY_OP_LEN: return MP_OBJ_NEW_SMALL_INT((machine_int_t)self->set.used);
478
        default: return MP_OBJ_NULL; // op not supported
479
480
    }
}
John R. Lenton's avatar
John R. Lenton committed
481

482
STATIC mp_obj_t set_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) {
John R. Lenton's avatar
John R. Lenton committed
483
484
    mp_obj_t args[] = {lhs, rhs};
    switch (op) {
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
        case MP_BINARY_OP_OR:
            return set_union(lhs, rhs);
        case MP_BINARY_OP_XOR:
            return set_symmetric_difference(lhs, rhs);
        case MP_BINARY_OP_AND:
            return set_intersect(lhs, rhs);
        case MP_BINARY_OP_SUBTRACT:
            return set_diff(2, args);
        case MP_BINARY_OP_INPLACE_OR:
            return set_union(lhs, rhs);
        case MP_BINARY_OP_INPLACE_XOR:
            return set_symmetric_difference(lhs, rhs);
        case MP_BINARY_OP_INPLACE_AND:
            return set_intersect(lhs, rhs);
        case MP_BINARY_OP_INPLACE_SUBTRACT:
            return set_diff(2, args);
        case MP_BINARY_OP_LESS:
            return set_issubset_proper(lhs, rhs);
        case MP_BINARY_OP_MORE:
            return set_issuperset_proper(lhs, rhs);
        case MP_BINARY_OP_EQUAL:
            return set_equal(lhs, rhs);
        case MP_BINARY_OP_LESS_EQUAL:
            return set_issubset(lhs, rhs);
        case MP_BINARY_OP_MORE_EQUAL:
            return set_issuperset(lhs, rhs);
        case MP_BINARY_OP_IN: {
            mp_obj_set_t *o = lhs;
            mp_obj_t elem = mp_set_lookup(&o->set, rhs, MP_MAP_LOOKUP);
            return MP_BOOL(elem != NULL);
        }
        default:
517
            return MP_OBJ_NULL; // op not supported
John R. Lenton's avatar
John R. Lenton committed
518
519
    }
}
John R. Lenton's avatar
John R. Lenton committed
520

John R. Lenton's avatar
John R. Lenton committed
521
522
523
524
/******************************************************************************/
/* set constructors & public C API                                            */


525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
STATIC const mp_map_elem_t set_locals_dict_table[] = {
    { MP_OBJ_NEW_QSTR(MP_QSTR_add), (mp_obj_t)&set_add_obj },
    { MP_OBJ_NEW_QSTR(MP_QSTR_clear), (mp_obj_t)&set_clear_obj },
    { MP_OBJ_NEW_QSTR(MP_QSTR_copy), (mp_obj_t)&set_copy_obj },
    { MP_OBJ_NEW_QSTR(MP_QSTR_discard), (mp_obj_t)&set_discard_obj },
    { MP_OBJ_NEW_QSTR(MP_QSTR_difference), (mp_obj_t)&set_diff_obj },
    { MP_OBJ_NEW_QSTR(MP_QSTR_difference_update), (mp_obj_t)&set_diff_update_obj },
    { MP_OBJ_NEW_QSTR(MP_QSTR_intersection), (mp_obj_t)&set_intersect_obj },
    { MP_OBJ_NEW_QSTR(MP_QSTR_intersection_update), (mp_obj_t)&set_intersect_update_obj },
    { MP_OBJ_NEW_QSTR(MP_QSTR_isdisjoint), (mp_obj_t)&set_isdisjoint_obj },
    { MP_OBJ_NEW_QSTR(MP_QSTR_issubset), (mp_obj_t)&set_issubset_obj },
    { MP_OBJ_NEW_QSTR(MP_QSTR_issuperset), (mp_obj_t)&set_issuperset_obj },
    { MP_OBJ_NEW_QSTR(MP_QSTR_pop), (mp_obj_t)&set_pop_obj },
    { MP_OBJ_NEW_QSTR(MP_QSTR_remove), (mp_obj_t)&set_remove_obj },
    { MP_OBJ_NEW_QSTR(MP_QSTR_symmetric_difference), (mp_obj_t)&set_symmetric_difference_obj },
    { MP_OBJ_NEW_QSTR(MP_QSTR_symmetric_difference_update), (mp_obj_t)&set_symmetric_difference_update_obj },
    { MP_OBJ_NEW_QSTR(MP_QSTR_union), (mp_obj_t)&set_union_obj },
    { MP_OBJ_NEW_QSTR(MP_QSTR_update), (mp_obj_t)&set_update_obj },
543
    { MP_OBJ_NEW_QSTR(MP_QSTR___contains__), (mp_obj_t)&mp_op_contains_obj },
John R. Lenton's avatar
John R. Lenton committed
544
545
};

546
547
STATIC MP_DEFINE_CONST_DICT(set_locals_dict, set_locals_dict_table);

548
const mp_obj_type_t mp_type_set = {
549
    { &mp_type_type },
550
    .name = MP_QSTR_set,
551
552
    .print = set_print,
    .make_new = set_make_new,
553
    .unary_op = set_unary_op,
John R. Lenton's avatar
John R. Lenton committed
554
    .binary_op = set_binary_op,
John R. Lenton's avatar
John R. Lenton committed
555
    .getiter = set_getiter,
556
    .locals_dict = (mp_obj_t)&set_locals_dict,
557
558
};

559
560
561
562
563
564
565
566
567
568
569
570
571
#if MICROPY_ENABLE_FROZENSET
const mp_obj_type_t mp_type_frozenset = {
    { &mp_type_type },
    .name = MP_QSTR_frozenset,
    .print = set_print,
    .make_new = set_make_new,
    .unary_op = set_unary_op,
    .binary_op = set_binary_op,
    .getiter = set_getiter,
    .locals_dict = (mp_obj_t)&set_locals_dict,
};
#endif

572
573
mp_obj_t mp_obj_new_set(int n_args, mp_obj_t *items) {
    mp_obj_set_t *o = m_new_obj(mp_obj_set_t);
574
    o->base.type = &mp_type_set;
575
576
    mp_set_init(&o->set, n_args);
    for (int i = 0; i < n_args; i++) {
John R. Lenton's avatar
John R. Lenton committed
577
        mp_set_lookup(&o->set, items[i], MP_MAP_LOOKUP_ADD_IF_NOT_FOUND);
578
579
580
581
582
    }
    return o;
}

void mp_obj_set_store(mp_obj_t self_in, mp_obj_t item) {
583
    assert(MP_OBJ_IS_TYPE(self_in, &mp_type_set));
584
    mp_obj_set_t *self = self_in;
John R. Lenton's avatar
John R. Lenton committed
585
    mp_set_lookup(&self->set, item, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND);
586
}