blob: 0a4bb26b31486c50f7e4fad79a6320a3b7d077f8 [file] [log] [blame]
Damien George04b91472014-05-03 23:27:38 +01001/*
2 * This file is part of the Micro Python project, http://micropython.org/
3 *
4 * The MIT License (MIT)
5 *
6 * Copyright (c) 2013, 2014 Damien P. George
Paul Sokolovskyda9f0922014-05-13 08:44:45 +03007 * Copyright (c) 2014 Paul Sokolovsky
Damien George04b91472014-05-03 23:27:38 +01008 *
9 * Permission is hereby granted, free of charge, to any person obtaining a copy
10 * of this software and associated documentation files (the "Software"), to deal
11 * in the Software without restriction, including without limitation the rights
12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 * copies of the Software, and to permit persons to whom the Software is
14 * furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 * THE SOFTWARE.
26 */
27
Paul Sokolovsky83eba5d2014-04-18 21:42:54 +030028#include <assert.h>
xbeefe34222014-03-16 00:14:26 -070029#include <stdbool.h>
Paul Sokolovsky439542f2014-01-21 00:19:19 +020030#include <string.h>
Paul Sokolovsky439542f2014-01-21 00:19:19 +020031
Paul Sokolovskyf54bcbf2014-05-02 17:47:01 +030032#include "mpconfig.h"
Paul Sokolovsky439542f2014-01-21 00:19:19 +020033#include "nlr.h"
34#include "misc.h"
Damien George12eacca2014-01-21 21:54:15 +000035#include "qstr.h"
Paul Sokolovsky439542f2014-01-21 00:19:19 +020036#include "obj.h"
Paul Sokolovsky439542f2014-01-21 00:19:19 +020037#include "runtime0.h"
38#include "runtime.h"
39
40// Helpers for sequence types
41
Paul Sokolovsky87e85b72014-02-02 08:24:07 +020042#define SWAP(type, var1, var2) { type t = var2; var2 = var1; var1 = t; }
43
Paul Sokolovsky439542f2014-01-21 00:19:19 +020044// Implements backend of sequence * integer operation. Assumes elements are
45// memory-adjacent in sequence.
46void mp_seq_multiply(const void *items, uint item_sz, uint len, uint times, void *dest) {
47 for (int i = 0; i < times; i++) {
48 uint copy_sz = item_sz * len;
49 memcpy(dest, items, copy_sz);
50 dest = (char*)dest + copy_sz;
51 }
52}
Paul Sokolovsky7364af22014-02-02 02:38:22 +020053
Paul Sokolovskyd915a522014-05-10 21:36:33 +030054bool mp_seq_get_fast_slice_indexes(machine_uint_t len, mp_obj_t slice, machine_uint_t *begin, machine_uint_t *end) {
Paul Sokolovskyafaaf532014-05-25 01:39:27 +030055 mp_obj_t ostart, ostop, ostep;
56 machine_int_t start, stop;
57 mp_obj_slice_get(slice, &ostart, &ostop, &ostep);
58 if (ostep != mp_const_none && ostep != MP_OBJ_NEW_SMALL_INT(1)) {
Paul Sokolovsky7364af22014-02-02 02:38:22 +020059 return false;
60 }
61
Paul Sokolovskyafaaf532014-05-25 01:39:27 +030062 if (ostart == mp_const_none) {
63 start = 0;
64 } else {
65 start = MP_OBJ_SMALL_INT_VALUE(ostart);
66 }
67 if (ostop == mp_const_none) {
68 stop = len;
69 } else {
70 stop = MP_OBJ_SMALL_INT_VALUE(ostop);
71 }
72
Paul Sokolovsky7364af22014-02-02 02:38:22 +020073 // Unlike subscription, out-of-bounds slice indexes are never error
74 if (start < 0) {
75 start = len + start;
76 if (start < 0) {
77 start = 0;
78 }
79 } else if (start > len) {
80 start = len;
81 }
Paul Sokolovskyafaaf532014-05-25 01:39:27 +030082 if (stop < 0) {
Paul Sokolovsky7364af22014-02-02 02:38:22 +020083 stop = len + stop;
84 // CPython returns empty sequence in such case
85 if (stop < 0) {
86 stop = start;
87 }
88 } else if (stop > len) {
89 stop = len;
90 }
Paul Sokolovsky69d081a2014-05-25 02:29:40 +030091
92 // CPython returns empty sequence in such case, or point for assignment is at start
93 if (start > stop) {
94 stop = start;
95 }
96
Paul Sokolovsky7364af22014-02-02 02:38:22 +020097 *begin = start;
98 *end = stop;
99 return true;
100}
Paul Sokolovsky87e85b72014-02-02 08:24:07 +0200101
102// Special-case comparison function for sequences of bytes
Damien Georged17926d2014-03-30 13:35:08 +0100103// Don't pass MP_BINARY_OP_NOT_EQUAL here
Paul Sokolovsky87e85b72014-02-02 08:24:07 +0200104bool mp_seq_cmp_bytes(int op, const byte *data1, uint len1, const byte *data2, uint len2) {
Paul Sokolovsky7b0f9a72014-05-10 04:26:10 +0300105 if (op == MP_BINARY_OP_EQUAL && len1 != len2) {
106 return false;
107 }
108
Paul Sokolovsky87e85b72014-02-02 08:24:07 +0200109 // Let's deal only with > & >=
Damien Georged17926d2014-03-30 13:35:08 +0100110 if (op == MP_BINARY_OP_LESS || op == MP_BINARY_OP_LESS_EQUAL) {
Paul Sokolovsky87e85b72014-02-02 08:24:07 +0200111 SWAP(const byte*, data1, data2);
112 SWAP(uint, len1, len2);
Damien Georged17926d2014-03-30 13:35:08 +0100113 if (op == MP_BINARY_OP_LESS) {
114 op = MP_BINARY_OP_MORE;
Paul Sokolovsky87e85b72014-02-02 08:24:07 +0200115 } else {
Damien Georged17926d2014-03-30 13:35:08 +0100116 op = MP_BINARY_OP_MORE_EQUAL;
Paul Sokolovsky87e85b72014-02-02 08:24:07 +0200117 }
118 }
119 uint min_len = len1 < len2 ? len1 : len2;
120 int res = memcmp(data1, data2, min_len);
Paul Sokolovskyad3baec2014-05-15 19:09:06 +0300121 if (op == MP_BINARY_OP_EQUAL) {
122 // If we are checking for equality, here're the answer
123 return res == 0;
124 }
Paul Sokolovsky87e85b72014-02-02 08:24:07 +0200125 if (res < 0) {
126 return false;
127 }
128 if (res > 0) {
129 return true;
130 }
131
132 // If we had tie in the last element...
133 // ... and we have lists of different lengths...
134 if (len1 != len2) {
135 if (len1 < len2) {
136 // ... then longer list length wins (we deal only with >)
137 return false;
138 }
Damien Georged17926d2014-03-30 13:35:08 +0100139 } else if (op == MP_BINARY_OP_MORE) {
Paul Sokolovsky87e85b72014-02-02 08:24:07 +0200140 // Otherwise, if we have strict relation, equality means failure
141 return false;
142 }
143 return true;
144}
Paul Sokolovsky1a996c42014-02-08 22:49:46 +0200145
146// Special-case comparison function for sequences of mp_obj_t
Damien Georged17926d2014-03-30 13:35:08 +0100147// Don't pass MP_BINARY_OP_NOT_EQUAL here
Paul Sokolovsky1a996c42014-02-08 22:49:46 +0200148bool mp_seq_cmp_objs(int op, const mp_obj_t *items1, uint len1, const mp_obj_t *items2, uint len2) {
Damien Georged17926d2014-03-30 13:35:08 +0100149 if (op == MP_BINARY_OP_EQUAL && len1 != len2) {
Paul Sokolovsky1a996c42014-02-08 22:49:46 +0200150 return false;
151 }
152
153 // Let's deal only with > & >=
Damien Georged17926d2014-03-30 13:35:08 +0100154 if (op == MP_BINARY_OP_LESS || op == MP_BINARY_OP_LESS_EQUAL) {
Paul Sokolovsky1a996c42014-02-08 22:49:46 +0200155 SWAP(const mp_obj_t *, items1, items2);
156 SWAP(uint, len1, len2);
Damien Georged17926d2014-03-30 13:35:08 +0100157 if (op == MP_BINARY_OP_LESS) {
158 op = MP_BINARY_OP_MORE;
Paul Sokolovsky1a996c42014-02-08 22:49:46 +0200159 } else {
Damien Georged17926d2014-03-30 13:35:08 +0100160 op = MP_BINARY_OP_MORE_EQUAL;
Paul Sokolovsky1a996c42014-02-08 22:49:46 +0200161 }
162 }
163
164 int len = len1 < len2 ? len1 : len2;
Paul Sokolovsky1a996c42014-02-08 22:49:46 +0200165 for (int i = 0; i < len; i++) {
Paul Sokolovsky83eba5d2014-04-18 21:42:54 +0300166 // If current elements equal, can't decide anything - go on
Paul Sokolovsky0fc47752014-04-18 21:47:58 +0300167 if (mp_obj_equal(items1[i], items2[i])) {
Paul Sokolovsky83eba5d2014-04-18 21:42:54 +0300168 continue;
169 }
170
171 // Othewise, if they are not equal, we can have final decision based on them
172 if (op == MP_BINARY_OP_EQUAL) {
173 // In particular, if we are checking for equality, here're the answer
Paul Sokolovsky1a996c42014-02-08 22:49:46 +0200174 return false;
175 }
Paul Sokolovsky83eba5d2014-04-18 21:42:54 +0300176
177 // Otherwise, application of relation op gives the answer
178 return (mp_binary_op(op, items1[i], items2[i]) == mp_const_true);
Paul Sokolovsky1a996c42014-02-08 22:49:46 +0200179 }
180
181 // If we had tie in the last element...
Paul Sokolovsky0fc47752014-04-18 21:47:58 +0300182 // ... and we have lists of different lengths...
183 if (len1 != len2) {
184 if (len1 < len2) {
185 // ... then longer list length wins (we deal only with >)
Paul Sokolovsky1a996c42014-02-08 22:49:46 +0200186 return false;
187 }
Paul Sokolovsky0fc47752014-04-18 21:47:58 +0300188 } else if (op == MP_BINARY_OP_MORE) {
189 // Otherwise, if we have strict relation, sequence equality means failure
190 return false;
Paul Sokolovsky1a996c42014-02-08 22:49:46 +0200191 }
192
193 return true;
194}
Paul Sokolovsky0cd1dc02014-02-10 06:37:11 +0200195
196// Special-case of index() which searches for mp_obj_t
197mp_obj_t mp_seq_index_obj(const mp_obj_t *items, uint len, uint n_args, const mp_obj_t *args) {
198 mp_obj_type_t *type = mp_obj_get_type(args[0]);
199 mp_obj_t *value = args[1];
200 uint start = 0;
201 uint stop = len;
202
203 if (n_args >= 3) {
xbe9e1e8cd2014-03-12 22:57:16 -0700204 start = mp_get_index(type, len, args[2], true);
Paul Sokolovsky0cd1dc02014-02-10 06:37:11 +0200205 if (n_args >= 4) {
xbe9e1e8cd2014-03-12 22:57:16 -0700206 stop = mp_get_index(type, len, args[3], true);
Paul Sokolovsky0cd1dc02014-02-10 06:37:11 +0200207 }
208 }
209
Damien Georged46ca252014-02-10 21:46:47 +0000210 for (machine_uint_t i = start; i < stop; i++) {
Paul Sokolovsky624eff62014-02-10 06:42:20 +0200211 if (mp_obj_equal(items[i], value)) {
212 // Common sense says this cannot overflow small int
213 return MP_OBJ_NEW_SMALL_INT(i);
214 }
Paul Sokolovsky0cd1dc02014-02-10 06:37:11 +0200215 }
216
Damien Georgeea13f402014-04-05 18:32:08 +0100217 nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "object not in sequence"));
Paul Sokolovsky0cd1dc02014-02-10 06:37:11 +0200218}
Paul Sokolovskyac0134d2014-02-10 07:10:55 +0200219
220mp_obj_t mp_seq_count_obj(const mp_obj_t *items, uint len, mp_obj_t value) {
Damien Georged46ca252014-02-10 21:46:47 +0000221 machine_uint_t count = 0;
Paul Sokolovskyac0134d2014-02-10 07:10:55 +0200222 for (uint i = 0; i < len; i++) {
223 if (mp_obj_equal(items[i], value)) {
224 count++;
225 }
226 }
227
228 // Common sense says this cannot overflow small int
229 return MP_OBJ_NEW_SMALL_INT(count);
230}