blob: 7ea3f708f109da0caa0bca49a2880c7f0a49131b [file] [log] [blame]
Paul Sokolovsky83eba5d2014-04-18 21:42:54 +03001#include <assert.h>
xbeefe34222014-03-16 00:14:26 -07002#include <stdbool.h>
Paul Sokolovsky439542f2014-01-21 00:19:19 +02003#include <string.h>
Paul Sokolovsky439542f2014-01-21 00:19:19 +02004
5#include "nlr.h"
6#include "misc.h"
7#include "mpconfig.h"
Damien George12eacca2014-01-21 21:54:15 +00008#include "qstr.h"
Paul Sokolovsky439542f2014-01-21 00:19:19 +02009#include "obj.h"
Paul Sokolovsky439542f2014-01-21 00:19:19 +020010#include "runtime0.h"
11#include "runtime.h"
12
13// Helpers for sequence types
14
Paul Sokolovsky87e85b72014-02-02 08:24:07 +020015#define SWAP(type, var1, var2) { type t = var2; var2 = var1; var1 = t; }
16
Paul Sokolovsky439542f2014-01-21 00:19:19 +020017// Implements backend of sequence * integer operation. Assumes elements are
18// memory-adjacent in sequence.
19void mp_seq_multiply(const void *items, uint item_sz, uint len, uint times, void *dest) {
20 for (int i = 0; i < times; i++) {
21 uint copy_sz = item_sz * len;
22 memcpy(dest, items, copy_sz);
23 dest = (char*)dest + copy_sz;
24 }
25}
Paul Sokolovsky7364af22014-02-02 02:38:22 +020026
27bool m_seq_get_fast_slice_indexes(machine_uint_t len, mp_obj_t slice, machine_uint_t *begin, machine_uint_t *end) {
28 machine_int_t start, stop, step;
29 mp_obj_slice_get(slice, &start, &stop, &step);
30 if (step != 1) {
31 return false;
32 }
33
34 // Unlike subscription, out-of-bounds slice indexes are never error
35 if (start < 0) {
36 start = len + start;
37 if (start < 0) {
38 start = 0;
39 }
40 } else if (start > len) {
41 start = len;
42 }
43 if (stop <= 0) {
44 stop = len + stop;
45 // CPython returns empty sequence in such case
46 if (stop < 0) {
47 stop = start;
48 }
49 } else if (stop > len) {
50 stop = len;
51 }
52 *begin = start;
53 *end = stop;
54 return true;
55}
Paul Sokolovsky87e85b72014-02-02 08:24:07 +020056
57// Special-case comparison function for sequences of bytes
Damien Georged17926d2014-03-30 13:35:08 +010058// Don't pass MP_BINARY_OP_NOT_EQUAL here
Paul Sokolovsky87e85b72014-02-02 08:24:07 +020059bool mp_seq_cmp_bytes(int op, const byte *data1, uint len1, const byte *data2, uint len2) {
60 // Let's deal only with > & >=
Damien Georged17926d2014-03-30 13:35:08 +010061 if (op == MP_BINARY_OP_LESS || op == MP_BINARY_OP_LESS_EQUAL) {
Paul Sokolovsky87e85b72014-02-02 08:24:07 +020062 SWAP(const byte*, data1, data2);
63 SWAP(uint, len1, len2);
Damien Georged17926d2014-03-30 13:35:08 +010064 if (op == MP_BINARY_OP_LESS) {
65 op = MP_BINARY_OP_MORE;
Paul Sokolovsky87e85b72014-02-02 08:24:07 +020066 } else {
Damien Georged17926d2014-03-30 13:35:08 +010067 op = MP_BINARY_OP_MORE_EQUAL;
Paul Sokolovsky87e85b72014-02-02 08:24:07 +020068 }
69 }
70 uint min_len = len1 < len2 ? len1 : len2;
71 int res = memcmp(data1, data2, min_len);
72 if (res < 0) {
73 return false;
74 }
75 if (res > 0) {
76 return true;
77 }
78
79 // If we had tie in the last element...
80 // ... and we have lists of different lengths...
81 if (len1 != len2) {
82 if (len1 < len2) {
83 // ... then longer list length wins (we deal only with >)
84 return false;
85 }
Damien Georged17926d2014-03-30 13:35:08 +010086 } else if (op == MP_BINARY_OP_MORE) {
Paul Sokolovsky87e85b72014-02-02 08:24:07 +020087 // Otherwise, if we have strict relation, equality means failure
88 return false;
89 }
90 return true;
91}
Paul Sokolovsky1a996c42014-02-08 22:49:46 +020092
93// Special-case comparison function for sequences of mp_obj_t
Damien Georged17926d2014-03-30 13:35:08 +010094// Don't pass MP_BINARY_OP_NOT_EQUAL here
Paul Sokolovsky1a996c42014-02-08 22:49:46 +020095bool 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 +010096 if (op == MP_BINARY_OP_EQUAL && len1 != len2) {
Paul Sokolovsky1a996c42014-02-08 22:49:46 +020097 return false;
98 }
99
100 // Let's deal only with > & >=
Damien Georged17926d2014-03-30 13:35:08 +0100101 if (op == MP_BINARY_OP_LESS || op == MP_BINARY_OP_LESS_EQUAL) {
Paul Sokolovsky1a996c42014-02-08 22:49:46 +0200102 SWAP(const mp_obj_t *, items1, items2);
103 SWAP(uint, len1, len2);
Damien Georged17926d2014-03-30 13:35:08 +0100104 if (op == MP_BINARY_OP_LESS) {
105 op = MP_BINARY_OP_MORE;
Paul Sokolovsky1a996c42014-02-08 22:49:46 +0200106 } else {
Damien Georged17926d2014-03-30 13:35:08 +0100107 op = MP_BINARY_OP_MORE_EQUAL;
Paul Sokolovsky1a996c42014-02-08 22:49:46 +0200108 }
109 }
110
111 int len = len1 < len2 ? len1 : len2;
112 bool eq_status = true; // empty lists are equal
Paul Sokolovsky1a996c42014-02-08 22:49:46 +0200113 for (int i = 0; i < len; i++) {
114 eq_status = mp_obj_equal(items1[i], items2[i]);
Paul Sokolovsky83eba5d2014-04-18 21:42:54 +0300115 // If current elements equal, can't decide anything - go on
116 if (eq_status) {
117 continue;
118 }
119
120 // Othewise, if they are not equal, we can have final decision based on them
121 if (op == MP_BINARY_OP_EQUAL) {
122 // In particular, if we are checking for equality, here're the answer
Paul Sokolovsky1a996c42014-02-08 22:49:46 +0200123 return false;
124 }
Paul Sokolovsky83eba5d2014-04-18 21:42:54 +0300125
126 // Otherwise, application of relation op gives the answer
127 return (mp_binary_op(op, items1[i], items2[i]) == mp_const_true);
Paul Sokolovsky1a996c42014-02-08 22:49:46 +0200128 }
129
Paul Sokolovsky83eba5d2014-04-18 21:42:54 +0300130 assert(eq_status);
Paul Sokolovsky1a996c42014-02-08 22:49:46 +0200131 // If we had tie in the last element...
132 if (eq_status) {
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 Sokolovsky1a996c42014-02-08 22:49:46 +0200140 // Otherwise, if we have strict relation, equality means failure
141 return false;
142 }
143 }
144
145 return true;
146}
Paul Sokolovsky0cd1dc02014-02-10 06:37:11 +0200147
148// Special-case of index() which searches for mp_obj_t
149mp_obj_t mp_seq_index_obj(const mp_obj_t *items, uint len, uint n_args, const mp_obj_t *args) {
150 mp_obj_type_t *type = mp_obj_get_type(args[0]);
151 mp_obj_t *value = args[1];
152 uint start = 0;
153 uint stop = len;
154
155 if (n_args >= 3) {
xbe9e1e8cd2014-03-12 22:57:16 -0700156 start = mp_get_index(type, len, args[2], true);
Paul Sokolovsky0cd1dc02014-02-10 06:37:11 +0200157 if (n_args >= 4) {
xbe9e1e8cd2014-03-12 22:57:16 -0700158 stop = mp_get_index(type, len, args[3], true);
Paul Sokolovsky0cd1dc02014-02-10 06:37:11 +0200159 }
160 }
161
Damien Georged46ca252014-02-10 21:46:47 +0000162 for (machine_uint_t i = start; i < stop; i++) {
Paul Sokolovsky624eff62014-02-10 06:42:20 +0200163 if (mp_obj_equal(items[i], value)) {
164 // Common sense says this cannot overflow small int
165 return MP_OBJ_NEW_SMALL_INT(i);
166 }
Paul Sokolovsky0cd1dc02014-02-10 06:37:11 +0200167 }
168
Damien Georgeea13f402014-04-05 18:32:08 +0100169 nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "object not in sequence"));
Paul Sokolovsky0cd1dc02014-02-10 06:37:11 +0200170}
Paul Sokolovskyac0134d2014-02-10 07:10:55 +0200171
172mp_obj_t mp_seq_count_obj(const mp_obj_t *items, uint len, mp_obj_t value) {
Damien Georged46ca252014-02-10 21:46:47 +0000173 machine_uint_t count = 0;
Paul Sokolovskyac0134d2014-02-10 07:10:55 +0200174 for (uint i = 0; i < len; i++) {
175 if (mp_obj_equal(items[i], value)) {
176 count++;
177 }
178 }
179
180 // Common sense says this cannot overflow small int
181 return MP_OBJ_NEW_SMALL_INT(count);
182}