blob: 3e7575522b28d26b394a9d492003d6fb1df91fa8 [file] [log] [blame]
Damien George04b91472014-05-03 23:27:38 +01001/*
Alexander Steffen55f33242017-06-30 09:22:17 +02002 * This file is part of the MicroPython project, http://micropython.org/
Damien George04b91472014-05-03 23:27:38 +01003 *
4 * The MIT License (MIT)
5 *
6 * Copyright (c) 2013, 2014 Damien P. George
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a copy
9 * of this software and associated documentation files (the "Software"), to deal
10 * in the Software without restriction, including without limitation the rights
11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 * copies of the Software, and to permit persons to whom the Software is
13 * furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 * THE SOFTWARE.
25 */
26
Paul Sokolovsky1c6de112014-01-03 02:41:17 +020027#include <stdlib.h>
Paul Sokolovsky1c6de112014-01-03 02:41:17 +020028#include <assert.h>
29
Nicko van Someren4c939552019-11-16 17:07:11 -070030#include "py/runtime.h"
Paul Sokolovsky1c6de112014-01-03 02:41:17 +020031
Damien Georgee9906ac2014-01-04 18:44:46 +000032/******************************************************************************/
Damien Georgee9906ac2014-01-04 18:44:46 +000033/* slice object */
34
Damien Georgefb510b32014-06-01 13:32:54 +010035#if MICROPY_PY_BUILTINS_SLICE
Paul Sokolovsky1c6de112014-01-03 02:41:17 +020036
Angus Grattondecf8e62024-02-27 15:32:29 +110037static void slice_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) {
Damien Georgeff8dd3f2015-01-20 12:47:20 +000038 (void)kind;
Damien George999cedb2015-11-27 17:01:44 +000039 mp_obj_slice_t *o = MP_OBJ_TO_PTR(o_in);
Damien George7f9d1d62015-04-09 23:56:15 +010040 mp_print_str(print, "slice(");
41 mp_obj_print_helper(print, o->start, PRINT_REPR);
42 mp_print_str(print, ", ");
43 mp_obj_print_helper(print, o->stop, PRINT_REPR);
44 mp_print_str(print, ", ");
45 mp_obj_print_helper(print, o->step, PRINT_REPR);
46 mp_print_str(print, ")");
Paul Sokolovsky1c6de112014-01-03 02:41:17 +020047}
48
Angus Grattondecf8e62024-02-27 15:32:29 +110049static mp_obj_t slice_unary_op(mp_unary_op_t op, mp_obj_t o_in) {
David Lechner8491eb12023-01-12 19:51:45 -060050 // Needed to explicitly opt out of default __hash__.
51 // REVISIT: CPython implements comparison operators for slice.
52 return MP_OBJ_NULL;
53}
54
Nicko van Someren4c939552019-11-16 17:07:11 -070055#if MICROPY_PY_BUILTINS_SLICE_INDICES
Angus Grattondecf8e62024-02-27 15:32:29 +110056static mp_obj_t slice_indices(mp_obj_t self_in, mp_obj_t length_obj) {
Damien Georgef397a3e2023-11-21 22:28:57 +110057 mp_int_t length = mp_obj_get_int(length_obj);
Nicko van Someren4c939552019-11-16 17:07:11 -070058 mp_bound_slice_t bound_indices;
59 mp_obj_slice_indices(self_in, length, &bound_indices);
60
61 mp_obj_t results[3] = {
62 MP_OBJ_NEW_SMALL_INT(bound_indices.start),
63 MP_OBJ_NEW_SMALL_INT(bound_indices.stop),
64 MP_OBJ_NEW_SMALL_INT(bound_indices.step),
65 };
66 return mp_obj_new_tuple(3, results);
67}
Angus Grattondecf8e62024-02-27 15:32:29 +110068static MP_DEFINE_CONST_FUN_OBJ_2(slice_indices_obj, slice_indices);
Nicko van Someren4c939552019-11-16 17:07:11 -070069#endif
70
Tom Soulanilleaeb62f92015-09-11 14:31:32 -070071#if MICROPY_PY_BUILTINS_SLICE_ATTRS
Angus Grattondecf8e62024-02-27 15:32:29 +110072static void slice_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
Tom Soulanilleaeb62f92015-09-11 14:31:32 -070073 if (dest[0] != MP_OBJ_NULL) {
74 // not load attribute
75 return;
76 }
Damien George999cedb2015-11-27 17:01:44 +000077 mp_obj_slice_t *self = MP_OBJ_TO_PTR(self_in);
Nicko van Someren4c939552019-11-16 17:07:11 -070078
Tom Soulanilleaeb62f92015-09-11 14:31:32 -070079 if (attr == MP_QSTR_start) {
80 dest[0] = self->start;
81 } else if (attr == MP_QSTR_stop) {
82 dest[0] = self->stop;
83 } else if (attr == MP_QSTR_step) {
84 dest[0] = self->step;
Nicko van Someren4c939552019-11-16 17:07:11 -070085 #if MICROPY_PY_BUILTINS_SLICE_INDICES
86 } else if (attr == MP_QSTR_indices) {
87 dest[0] = MP_OBJ_FROM_PTR(&slice_indices_obj);
88 dest[1] = self_in;
89 #endif
Tom Soulanilleaeb62f92015-09-11 14:31:32 -070090 }
91}
92#endif
93
Nicko van Someren4c939552019-11-16 17:07:11 -070094#if MICROPY_PY_BUILTINS_SLICE_INDICES && !MICROPY_PY_BUILTINS_SLICE_ATTRS
Angus Grattondecf8e62024-02-27 15:32:29 +110095static const mp_rom_map_elem_t slice_locals_dict_table[] = {
Nicko van Someren4c939552019-11-16 17:07:11 -070096 { MP_ROM_QSTR(MP_QSTR_indices), MP_ROM_PTR(&slice_indices_obj) },
97};
Angus Grattondecf8e62024-02-27 15:32:29 +110098static MP_DEFINE_CONST_DICT(slice_locals_dict, slice_locals_dict_table);
Nicko van Someren4c939552019-11-16 17:07:11 -070099#endif
100
Jim Mussaredb7d6ee92022-06-24 16:22:38 +1000101#if MICROPY_PY_BUILTINS_SLICE_ATTRS
102#define SLICE_TYPE_ATTR_OR_LOCALS_DICT attr, slice_attr,
103#elif MICROPY_PY_BUILTINS_SLICE_INDICES
Jim Mussared9dce8272022-06-24 16:27:46 +1000104#define SLICE_TYPE_ATTR_OR_LOCALS_DICT locals_dict, &slice_locals_dict,
Jim Mussaredb7d6ee92022-06-24 16:22:38 +1000105#else
106#define SLICE_TYPE_ATTR_OR_LOCALS_DICT
107#endif
108
Jim Mussared662b9762021-07-14 14:38:38 +1000109MP_DEFINE_CONST_OBJ_TYPE(
110 mp_type_slice,
111 MP_QSTR_slice,
112 MP_TYPE_FLAG_NONE,
David Lechner8491eb12023-01-12 19:51:45 -0600113 unary_op, slice_unary_op,
Jim Mussaredb7d6ee92022-06-24 16:22:38 +1000114 SLICE_TYPE_ATTR_OR_LOCALS_DICT
Jim Mussared662b9762021-07-14 14:38:38 +1000115 print, slice_print
Jim Mussared662b9762021-07-14 14:38:38 +1000116 );
Paul Sokolovsky1c6de112014-01-03 02:41:17 +0200117
Paul Sokolovsky1c6de112014-01-03 02:41:17 +0200118mp_obj_t mp_obj_new_slice(mp_obj_t ostart, mp_obj_t ostop, mp_obj_t ostep) {
Jim Mussared0e7bfc82022-04-22 17:09:15 +1000119 mp_obj_slice_t *o = mp_obj_malloc(mp_obj_slice_t, &mp_type_slice);
Paul Sokolovskyafaaf532014-05-25 01:39:27 +0300120 o->start = ostart;
121 o->stop = ostop;
122 o->step = ostep;
Damien George999cedb2015-11-27 17:01:44 +0000123 return MP_OBJ_FROM_PTR(o);
Paul Sokolovsky1c6de112014-01-03 02:41:17 +0200124}
125
Nicko van Someren4c939552019-11-16 17:07:11 -0700126// Return the real index and step values for a slice when applied to a sequence of
127// the given length, resolving missing components, negative values and values off
128// the end of the sequence.
129void mp_obj_slice_indices(mp_obj_t self_in, mp_int_t length, mp_bound_slice_t *result) {
130 mp_obj_slice_t *self = MP_OBJ_TO_PTR(self_in);
131 mp_int_t start, stop, step;
132
133 if (self->step == mp_const_none) {
134 step = 1;
135 } else {
136 step = mp_obj_get_int(self->step);
137 if (step == 0) {
Damien George8e048d22020-04-09 17:22:25 +1000138 mp_raise_ValueError(MP_ERROR_TEXT("slice step can't be zero"));
Nicko van Someren4c939552019-11-16 17:07:11 -0700139 }
140 }
141
142 if (step > 0) {
143 // Positive step
144 if (self->start == mp_const_none) {
145 start = 0;
146 } else {
147 start = mp_obj_get_int(self->start);
148 if (start < 0) {
149 start += length;
150 }
151 start = MIN(length, MAX(start, 0));
152 }
153
154 if (self->stop == mp_const_none) {
155 stop = length;
156 } else {
157 stop = mp_obj_get_int(self->stop);
158 if (stop < 0) {
159 stop += length;
160 }
161 stop = MIN(length, MAX(stop, 0));
162 }
163 } else {
164 // Negative step
165 if (self->start == mp_const_none) {
166 start = length - 1;
167 } else {
168 start = mp_obj_get_int(self->start);
169 if (start < 0) {
170 start += length;
171 }
172 start = MIN(length - 1, MAX(start, -1));
173 }
174
175 if (self->stop == mp_const_none) {
176 stop = -1;
177 } else {
178 stop = mp_obj_get_int(self->stop);
179 if (stop < 0) {
180 stop += length;
181 }
182 stop = MIN(length - 1, MAX(stop, -1));
183 }
184 }
185
186 result->start = start;
187 result->stop = stop;
188 result->step = step;
189}
190
Paul Sokolovsky1c6de112014-01-03 02:41:17 +0200191#endif