blob: 3d2bbba4df6852b2cc1e88391445aeca5ed0d4d8 [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
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 Sokolovsky83eba5d2014-04-18 21:42:54 +030027#include <assert.h>
xbeefe34222014-03-16 00:14:26 -070028#include <stdbool.h>
Paul Sokolovsky439542f2014-01-21 00:19:19 +020029#include <string.h>
Paul Sokolovsky439542f2014-01-21 00:19:19 +020030
Paul Sokolovskyf54bcbf2014-05-02 17:47:01 +030031#include "mpconfig.h"
Paul Sokolovsky439542f2014-01-21 00:19:19 +020032#include "nlr.h"
33#include "misc.h"
Damien George12eacca2014-01-21 21:54:15 +000034#include "qstr.h"
Paul Sokolovsky439542f2014-01-21 00:19:19 +020035#include "obj.h"
Paul Sokolovsky439542f2014-01-21 00:19:19 +020036#include "runtime0.h"
37#include "runtime.h"
38
39// Helpers for sequence types
40
Paul Sokolovsky87e85b72014-02-02 08:24:07 +020041#define SWAP(type, var1, var2) { type t = var2; var2 = var1; var1 = t; }
42
Paul Sokolovsky439542f2014-01-21 00:19:19 +020043// Implements backend of sequence * integer operation. Assumes elements are
44// memory-adjacent in sequence.
45void mp_seq_multiply(const void *items, uint item_sz, uint len, uint times, void *dest) {
46 for (int i = 0; i < times; i++) {
47 uint copy_sz = item_sz * len;
48 memcpy(dest, items, copy_sz);
49 dest = (char*)dest + copy_sz;
50 }
51}
Paul Sokolovsky7364af22014-02-02 02:38:22 +020052
53bool m_seq_get_fast_slice_indexes(machine_uint_t len, mp_obj_t slice, machine_uint_t *begin, machine_uint_t *end) {
54 machine_int_t start, stop, step;
55 mp_obj_slice_get(slice, &start, &stop, &step);
56 if (step != 1) {
57 return false;
58 }
59
60 // Unlike subscription, out-of-bounds slice indexes are never error
61 if (start < 0) {
62 start = len + start;
63 if (start < 0) {
64 start = 0;
65 }
66 } else if (start > len) {
67 start = len;
68 }
69 if (stop <= 0) {
70 stop = len + stop;
71 // CPython returns empty sequence in such case
72 if (stop < 0) {
73 stop = start;
74 }
75 } else if (stop > len) {
76 stop = len;
77 }
78 *begin = start;
79 *end = stop;
80 return true;
81}
Paul Sokolovsky87e85b72014-02-02 08:24:07 +020082
83// Special-case comparison function for sequences of bytes
Damien Georged17926d2014-03-30 13:35:08 +010084// Don't pass MP_BINARY_OP_NOT_EQUAL here
Paul Sokolovsky87e85b72014-02-02 08:24:07 +020085bool mp_seq_cmp_bytes(int op, const byte *data1, uint len1, const byte *data2, uint len2) {
Paul Sokolovsky7b0f9a72014-05-10 04:26:10 +030086 if (op == MP_BINARY_OP_EQUAL && len1 != len2) {
87 return false;
88 }
89
Paul Sokolovsky87e85b72014-02-02 08:24:07 +020090 // Let's deal only with > & >=
Damien Georged17926d2014-03-30 13:35:08 +010091 if (op == MP_BINARY_OP_LESS || op == MP_BINARY_OP_LESS_EQUAL) {
Paul Sokolovsky87e85b72014-02-02 08:24:07 +020092 SWAP(const byte*, data1, data2);
93 SWAP(uint, len1, len2);
Damien Georged17926d2014-03-30 13:35:08 +010094 if (op == MP_BINARY_OP_LESS) {
95 op = MP_BINARY_OP_MORE;
Paul Sokolovsky87e85b72014-02-02 08:24:07 +020096 } else {
Damien Georged17926d2014-03-30 13:35:08 +010097 op = MP_BINARY_OP_MORE_EQUAL;
Paul Sokolovsky87e85b72014-02-02 08:24:07 +020098 }
99 }
100 uint min_len = len1 < len2 ? len1 : len2;
101 int res = memcmp(data1, data2, min_len);
102 if (res < 0) {
103 return false;
104 }
105 if (res > 0) {
106 return true;
107 }
108
109 // If we had tie in the last element...
110 // ... and we have lists of different lengths...
111 if (len1 != len2) {
112 if (len1 < len2) {
113 // ... then longer list length wins (we deal only with >)
114 return false;
115 }
Damien Georged17926d2014-03-30 13:35:08 +0100116 } else if (op == MP_BINARY_OP_MORE) {
Paul Sokolovsky87e85b72014-02-02 08:24:07 +0200117 // Otherwise, if we have strict relation, equality means failure
118 return false;
119 }
120 return true;
121}
Paul Sokolovsky1a996c42014-02-08 22:49:46 +0200122
123// Special-case comparison function for sequences of mp_obj_t
Damien Georged17926d2014-03-30 13:35:08 +0100124// Don't pass MP_BINARY_OP_NOT_EQUAL here
Paul Sokolovsky1a996c42014-02-08 22:49:46 +0200125bool 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 +0100126 if (op == MP_BINARY_OP_EQUAL && len1 != len2) {
Paul Sokolovsky1a996c42014-02-08 22:49:46 +0200127 return false;
128 }
129
130 // Let's deal only with > & >=
Damien Georged17926d2014-03-30 13:35:08 +0100131 if (op == MP_BINARY_OP_LESS || op == MP_BINARY_OP_LESS_EQUAL) {
Paul Sokolovsky1a996c42014-02-08 22:49:46 +0200132 SWAP(const mp_obj_t *, items1, items2);
133 SWAP(uint, len1, len2);
Damien Georged17926d2014-03-30 13:35:08 +0100134 if (op == MP_BINARY_OP_LESS) {
135 op = MP_BINARY_OP_MORE;
Paul Sokolovsky1a996c42014-02-08 22:49:46 +0200136 } else {
Damien Georged17926d2014-03-30 13:35:08 +0100137 op = MP_BINARY_OP_MORE_EQUAL;
Paul Sokolovsky1a996c42014-02-08 22:49:46 +0200138 }
139 }
140
141 int len = len1 < len2 ? len1 : len2;
Paul Sokolovsky1a996c42014-02-08 22:49:46 +0200142 for (int i = 0; i < len; i++) {
Paul Sokolovsky83eba5d2014-04-18 21:42:54 +0300143 // If current elements equal, can't decide anything - go on
Paul Sokolovsky0fc47752014-04-18 21:47:58 +0300144 if (mp_obj_equal(items1[i], items2[i])) {
Paul Sokolovsky83eba5d2014-04-18 21:42:54 +0300145 continue;
146 }
147
148 // Othewise, if they are not equal, we can have final decision based on them
149 if (op == MP_BINARY_OP_EQUAL) {
150 // In particular, if we are checking for equality, here're the answer
Paul Sokolovsky1a996c42014-02-08 22:49:46 +0200151 return false;
152 }
Paul Sokolovsky83eba5d2014-04-18 21:42:54 +0300153
154 // Otherwise, application of relation op gives the answer
155 return (mp_binary_op(op, items1[i], items2[i]) == mp_const_true);
Paul Sokolovsky1a996c42014-02-08 22:49:46 +0200156 }
157
158 // If we had tie in the last element...
Paul Sokolovsky0fc47752014-04-18 21:47:58 +0300159 // ... and we have lists of different lengths...
160 if (len1 != len2) {
161 if (len1 < len2) {
162 // ... then longer list length wins (we deal only with >)
Paul Sokolovsky1a996c42014-02-08 22:49:46 +0200163 return false;
164 }
Paul Sokolovsky0fc47752014-04-18 21:47:58 +0300165 } else if (op == MP_BINARY_OP_MORE) {
166 // Otherwise, if we have strict relation, sequence equality means failure
167 return false;
Paul Sokolovsky1a996c42014-02-08 22:49:46 +0200168 }
169
170 return true;
171}
Paul Sokolovsky0cd1dc02014-02-10 06:37:11 +0200172
173// Special-case of index() which searches for mp_obj_t
174mp_obj_t mp_seq_index_obj(const mp_obj_t *items, uint len, uint n_args, const mp_obj_t *args) {
175 mp_obj_type_t *type = mp_obj_get_type(args[0]);
176 mp_obj_t *value = args[1];
177 uint start = 0;
178 uint stop = len;
179
180 if (n_args >= 3) {
xbe9e1e8cd2014-03-12 22:57:16 -0700181 start = mp_get_index(type, len, args[2], true);
Paul Sokolovsky0cd1dc02014-02-10 06:37:11 +0200182 if (n_args >= 4) {
xbe9e1e8cd2014-03-12 22:57:16 -0700183 stop = mp_get_index(type, len, args[3], true);
Paul Sokolovsky0cd1dc02014-02-10 06:37:11 +0200184 }
185 }
186
Damien Georged46ca252014-02-10 21:46:47 +0000187 for (machine_uint_t i = start; i < stop; i++) {
Paul Sokolovsky624eff62014-02-10 06:42:20 +0200188 if (mp_obj_equal(items[i], value)) {
189 // Common sense says this cannot overflow small int
190 return MP_OBJ_NEW_SMALL_INT(i);
191 }
Paul Sokolovsky0cd1dc02014-02-10 06:37:11 +0200192 }
193
Damien Georgeea13f402014-04-05 18:32:08 +0100194 nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "object not in sequence"));
Paul Sokolovsky0cd1dc02014-02-10 06:37:11 +0200195}
Paul Sokolovskyac0134d2014-02-10 07:10:55 +0200196
197mp_obj_t mp_seq_count_obj(const mp_obj_t *items, uint len, mp_obj_t value) {
Damien Georged46ca252014-02-10 21:46:47 +0000198 machine_uint_t count = 0;
Paul Sokolovskyac0134d2014-02-10 07:10:55 +0200199 for (uint i = 0; i < len; i++) {
200 if (mp_obj_equal(items[i], value)) {
201 count++;
202 }
203 }
204
205 // Common sense says this cannot overflow small int
206 return MP_OBJ_NEW_SMALL_INT(count);
207}