blob: 3a4d65d53b0029320cddae0ed0ad635f22409c74 [file] [log] [blame]
xbeefe34222014-03-16 00:14:26 -07001#include <stdbool.h>
Paul Sokolovsky439542f2014-01-21 00:19:19 +02002#include <string.h>
Paul Sokolovsky439542f2014-01-21 00:19:19 +02003
4#include "nlr.h"
5#include "misc.h"
6#include "mpconfig.h"
Damien George12eacca2014-01-21 21:54:15 +00007#include "qstr.h"
Paul Sokolovsky439542f2014-01-21 00:19:19 +02008#include "obj.h"
Paul Sokolovsky439542f2014-01-21 00:19:19 +02009#include "runtime0.h"
10#include "runtime.h"
11
12// Helpers for sequence types
13
Paul Sokolovsky87e85b72014-02-02 08:24:07 +020014#define SWAP(type, var1, var2) { type t = var2; var2 = var1; var1 = t; }
15
Paul Sokolovsky439542f2014-01-21 00:19:19 +020016// Implements backend of sequence * integer operation. Assumes elements are
17// memory-adjacent in sequence.
18void mp_seq_multiply(const void *items, uint item_sz, uint len, uint times, void *dest) {
19 for (int i = 0; i < times; i++) {
20 uint copy_sz = item_sz * len;
21 memcpy(dest, items, copy_sz);
22 dest = (char*)dest + copy_sz;
23 }
24}
Paul Sokolovsky7364af22014-02-02 02:38:22 +020025
26bool m_seq_get_fast_slice_indexes(machine_uint_t len, mp_obj_t slice, machine_uint_t *begin, machine_uint_t *end) {
27 machine_int_t start, stop, step;
28 mp_obj_slice_get(slice, &start, &stop, &step);
29 if (step != 1) {
30 return false;
31 }
32
33 // Unlike subscription, out-of-bounds slice indexes are never error
34 if (start < 0) {
35 start = len + start;
36 if (start < 0) {
37 start = 0;
38 }
39 } else if (start > len) {
40 start = len;
41 }
42 if (stop <= 0) {
43 stop = len + stop;
44 // CPython returns empty sequence in such case
45 if (stop < 0) {
46 stop = start;
47 }
48 } else if (stop > len) {
49 stop = len;
50 }
51 *begin = start;
52 *end = stop;
53 return true;
54}
Paul Sokolovsky87e85b72014-02-02 08:24:07 +020055
56// Special-case comparison function for sequences of bytes
Damien Georged17926d2014-03-30 13:35:08 +010057// Don't pass MP_BINARY_OP_NOT_EQUAL here
Paul Sokolovsky87e85b72014-02-02 08:24:07 +020058bool mp_seq_cmp_bytes(int op, const byte *data1, uint len1, const byte *data2, uint len2) {
59 // Let's deal only with > & >=
Damien Georged17926d2014-03-30 13:35:08 +010060 if (op == MP_BINARY_OP_LESS || op == MP_BINARY_OP_LESS_EQUAL) {
Paul Sokolovsky87e85b72014-02-02 08:24:07 +020061 SWAP(const byte*, data1, data2);
62 SWAP(uint, len1, len2);
Damien Georged17926d2014-03-30 13:35:08 +010063 if (op == MP_BINARY_OP_LESS) {
64 op = MP_BINARY_OP_MORE;
Paul Sokolovsky87e85b72014-02-02 08:24:07 +020065 } else {
Damien Georged17926d2014-03-30 13:35:08 +010066 op = MP_BINARY_OP_MORE_EQUAL;
Paul Sokolovsky87e85b72014-02-02 08:24:07 +020067 }
68 }
69 uint min_len = len1 < len2 ? len1 : len2;
70 int res = memcmp(data1, data2, min_len);
71 if (res < 0) {
72 return false;
73 }
74 if (res > 0) {
75 return true;
76 }
77
78 // If we had tie in the last element...
79 // ... and we have lists of different lengths...
80 if (len1 != len2) {
81 if (len1 < len2) {
82 // ... then longer list length wins (we deal only with >)
83 return false;
84 }
Damien Georged17926d2014-03-30 13:35:08 +010085 } else if (op == MP_BINARY_OP_MORE) {
Paul Sokolovsky87e85b72014-02-02 08:24:07 +020086 // Otherwise, if we have strict relation, equality means failure
87 return false;
88 }
89 return true;
90}
Paul Sokolovsky1a996c42014-02-08 22:49:46 +020091
92// Special-case comparison function for sequences of mp_obj_t
Damien Georged17926d2014-03-30 13:35:08 +010093// Don't pass MP_BINARY_OP_NOT_EQUAL here
Paul Sokolovsky1a996c42014-02-08 22:49:46 +020094bool 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 +010095 if (op == MP_BINARY_OP_EQUAL && len1 != len2) {
Paul Sokolovsky1a996c42014-02-08 22:49:46 +020096 return false;
97 }
98
99 // Let's deal only with > & >=
Damien Georged17926d2014-03-30 13:35:08 +0100100 if (op == MP_BINARY_OP_LESS || op == MP_BINARY_OP_LESS_EQUAL) {
Paul Sokolovsky1a996c42014-02-08 22:49:46 +0200101 SWAP(const mp_obj_t *, items1, items2);
102 SWAP(uint, len1, len2);
Damien Georged17926d2014-03-30 13:35:08 +0100103 if (op == MP_BINARY_OP_LESS) {
104 op = MP_BINARY_OP_MORE;
Paul Sokolovsky1a996c42014-02-08 22:49:46 +0200105 } else {
Damien Georged17926d2014-03-30 13:35:08 +0100106 op = MP_BINARY_OP_MORE_EQUAL;
Paul Sokolovsky1a996c42014-02-08 22:49:46 +0200107 }
108 }
109
110 int len = len1 < len2 ? len1 : len2;
111 bool eq_status = true; // empty lists are equal
112 bool rel_status;
113 for (int i = 0; i < len; i++) {
114 eq_status = mp_obj_equal(items1[i], items2[i]);
Damien Georged17926d2014-03-30 13:35:08 +0100115 if (op == MP_BINARY_OP_EQUAL && !eq_status) {
Paul Sokolovsky1a996c42014-02-08 22:49:46 +0200116 return false;
117 }
Damien Georged17926d2014-03-30 13:35:08 +0100118 rel_status = (mp_binary_op(op, items1[i], items2[i]) == mp_const_true);
Paul Sokolovsky1a996c42014-02-08 22:49:46 +0200119 if (!eq_status && !rel_status) {
120 return false;
121 }
122 }
123
124 // If we had tie in the last element...
125 if (eq_status) {
126 // ... and we have lists of different lengths...
127 if (len1 != len2) {
128 if (len1 < len2) {
129 // ... then longer list length wins (we deal only with >)
130 return false;
131 }
Damien Georged17926d2014-03-30 13:35:08 +0100132 } else if (op == MP_BINARY_OP_MORE) {
Paul Sokolovsky1a996c42014-02-08 22:49:46 +0200133 // Otherwise, if we have strict relation, equality means failure
134 return false;
135 }
136 }
137
138 return true;
139}
Paul Sokolovsky0cd1dc02014-02-10 06:37:11 +0200140
141// Special-case of index() which searches for mp_obj_t
142mp_obj_t mp_seq_index_obj(const mp_obj_t *items, uint len, uint n_args, const mp_obj_t *args) {
143 mp_obj_type_t *type = mp_obj_get_type(args[0]);
144 mp_obj_t *value = args[1];
145 uint start = 0;
146 uint stop = len;
147
148 if (n_args >= 3) {
xbe9e1e8cd2014-03-12 22:57:16 -0700149 start = mp_get_index(type, len, args[2], true);
Paul Sokolovsky0cd1dc02014-02-10 06:37:11 +0200150 if (n_args >= 4) {
xbe9e1e8cd2014-03-12 22:57:16 -0700151 stop = mp_get_index(type, len, args[3], true);
Paul Sokolovsky0cd1dc02014-02-10 06:37:11 +0200152 }
153 }
154
Damien Georged46ca252014-02-10 21:46:47 +0000155 for (machine_uint_t i = start; i < stop; i++) {
Paul Sokolovsky624eff62014-02-10 06:42:20 +0200156 if (mp_obj_equal(items[i], value)) {
157 // Common sense says this cannot overflow small int
158 return MP_OBJ_NEW_SMALL_INT(i);
159 }
Paul Sokolovsky0cd1dc02014-02-10 06:37:11 +0200160 }
161
Damien Georgeea13f402014-04-05 18:32:08 +0100162 nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "object not in sequence"));
Paul Sokolovsky0cd1dc02014-02-10 06:37:11 +0200163}
Paul Sokolovskyac0134d2014-02-10 07:10:55 +0200164
165mp_obj_t mp_seq_count_obj(const mp_obj_t *items, uint len, mp_obj_t value) {
Damien Georged46ca252014-02-10 21:46:47 +0000166 machine_uint_t count = 0;
Paul Sokolovskyac0134d2014-02-10 07:10:55 +0200167 for (uint i = 0; i < len; i++) {
168 if (mp_obj_equal(items[i], value)) {
169 count++;
170 }
171 }
172
173 // Common sense says this cannot overflow small int
174 return MP_OBJ_NEW_SMALL_INT(count);
175}