blob: 63f6bd69447977c4b4b8260f3b816542df98f0b5 [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) {
86 // Let's deal only with > & >=
Damien Georged17926d2014-03-30 13:35:08 +010087 if (op == MP_BINARY_OP_LESS || op == MP_BINARY_OP_LESS_EQUAL) {
Paul Sokolovsky87e85b72014-02-02 08:24:07 +020088 SWAP(const byte*, data1, data2);
89 SWAP(uint, len1, len2);
Damien Georged17926d2014-03-30 13:35:08 +010090 if (op == MP_BINARY_OP_LESS) {
91 op = MP_BINARY_OP_MORE;
Paul Sokolovsky87e85b72014-02-02 08:24:07 +020092 } else {
Damien Georged17926d2014-03-30 13:35:08 +010093 op = MP_BINARY_OP_MORE_EQUAL;
Paul Sokolovsky87e85b72014-02-02 08:24:07 +020094 }
95 }
96 uint min_len = len1 < len2 ? len1 : len2;
97 int res = memcmp(data1, data2, min_len);
98 if (res < 0) {
99 return false;
100 }
101 if (res > 0) {
102 return true;
103 }
104
105 // If we had tie in the last element...
106 // ... and we have lists of different lengths...
107 if (len1 != len2) {
108 if (len1 < len2) {
109 // ... then longer list length wins (we deal only with >)
110 return false;
111 }
Damien Georged17926d2014-03-30 13:35:08 +0100112 } else if (op == MP_BINARY_OP_MORE) {
Paul Sokolovsky87e85b72014-02-02 08:24:07 +0200113 // Otherwise, if we have strict relation, equality means failure
114 return false;
115 }
116 return true;
117}
Paul Sokolovsky1a996c42014-02-08 22:49:46 +0200118
119// Special-case comparison function for sequences of mp_obj_t
Damien Georged17926d2014-03-30 13:35:08 +0100120// Don't pass MP_BINARY_OP_NOT_EQUAL here
Paul Sokolovsky1a996c42014-02-08 22:49:46 +0200121bool 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 +0100122 if (op == MP_BINARY_OP_EQUAL && len1 != len2) {
Paul Sokolovsky1a996c42014-02-08 22:49:46 +0200123 return false;
124 }
125
126 // Let's deal only with > & >=
Damien Georged17926d2014-03-30 13:35:08 +0100127 if (op == MP_BINARY_OP_LESS || op == MP_BINARY_OP_LESS_EQUAL) {
Paul Sokolovsky1a996c42014-02-08 22:49:46 +0200128 SWAP(const mp_obj_t *, items1, items2);
129 SWAP(uint, len1, len2);
Damien Georged17926d2014-03-30 13:35:08 +0100130 if (op == MP_BINARY_OP_LESS) {
131 op = MP_BINARY_OP_MORE;
Paul Sokolovsky1a996c42014-02-08 22:49:46 +0200132 } else {
Damien Georged17926d2014-03-30 13:35:08 +0100133 op = MP_BINARY_OP_MORE_EQUAL;
Paul Sokolovsky1a996c42014-02-08 22:49:46 +0200134 }
135 }
136
137 int len = len1 < len2 ? len1 : len2;
Paul Sokolovsky1a996c42014-02-08 22:49:46 +0200138 for (int i = 0; i < len; i++) {
Paul Sokolovsky83eba5d2014-04-18 21:42:54 +0300139 // If current elements equal, can't decide anything - go on
Paul Sokolovsky0fc47752014-04-18 21:47:58 +0300140 if (mp_obj_equal(items1[i], items2[i])) {
Paul Sokolovsky83eba5d2014-04-18 21:42:54 +0300141 continue;
142 }
143
144 // Othewise, if they are not equal, we can have final decision based on them
145 if (op == MP_BINARY_OP_EQUAL) {
146 // In particular, if we are checking for equality, here're the answer
Paul Sokolovsky1a996c42014-02-08 22:49:46 +0200147 return false;
148 }
Paul Sokolovsky83eba5d2014-04-18 21:42:54 +0300149
150 // Otherwise, application of relation op gives the answer
151 return (mp_binary_op(op, items1[i], items2[i]) == mp_const_true);
Paul Sokolovsky1a996c42014-02-08 22:49:46 +0200152 }
153
154 // If we had tie in the last element...
Paul Sokolovsky0fc47752014-04-18 21:47:58 +0300155 // ... and we have lists of different lengths...
156 if (len1 != len2) {
157 if (len1 < len2) {
158 // ... then longer list length wins (we deal only with >)
Paul Sokolovsky1a996c42014-02-08 22:49:46 +0200159 return false;
160 }
Paul Sokolovsky0fc47752014-04-18 21:47:58 +0300161 } else if (op == MP_BINARY_OP_MORE) {
162 // Otherwise, if we have strict relation, sequence equality means failure
163 return false;
Paul Sokolovsky1a996c42014-02-08 22:49:46 +0200164 }
165
166 return true;
167}
Paul Sokolovsky0cd1dc02014-02-10 06:37:11 +0200168
169// Special-case of index() which searches for mp_obj_t
170mp_obj_t mp_seq_index_obj(const mp_obj_t *items, uint len, uint n_args, const mp_obj_t *args) {
171 mp_obj_type_t *type = mp_obj_get_type(args[0]);
172 mp_obj_t *value = args[1];
173 uint start = 0;
174 uint stop = len;
175
176 if (n_args >= 3) {
xbe9e1e8cd2014-03-12 22:57:16 -0700177 start = mp_get_index(type, len, args[2], true);
Paul Sokolovsky0cd1dc02014-02-10 06:37:11 +0200178 if (n_args >= 4) {
xbe9e1e8cd2014-03-12 22:57:16 -0700179 stop = mp_get_index(type, len, args[3], true);
Paul Sokolovsky0cd1dc02014-02-10 06:37:11 +0200180 }
181 }
182
Damien Georged46ca252014-02-10 21:46:47 +0000183 for (machine_uint_t i = start; i < stop; i++) {
Paul Sokolovsky624eff62014-02-10 06:42:20 +0200184 if (mp_obj_equal(items[i], value)) {
185 // Common sense says this cannot overflow small int
186 return MP_OBJ_NEW_SMALL_INT(i);
187 }
Paul Sokolovsky0cd1dc02014-02-10 06:37:11 +0200188 }
189
Damien Georgeea13f402014-04-05 18:32:08 +0100190 nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "object not in sequence"));
Paul Sokolovsky0cd1dc02014-02-10 06:37:11 +0200191}
Paul Sokolovskyac0134d2014-02-10 07:10:55 +0200192
193mp_obj_t mp_seq_count_obj(const mp_obj_t *items, uint len, mp_obj_t value) {
Damien Georged46ca252014-02-10 21:46:47 +0000194 machine_uint_t count = 0;
Paul Sokolovskyac0134d2014-02-10 07:10:55 +0200195 for (uint i = 0; i < len; i++) {
196 if (mp_obj_equal(items[i], value)) {
197 count++;
198 }
199 }
200
201 // Common sense says this cannot overflow small int
202 return MP_OBJ_NEW_SMALL_INT(count);
203}