objdeque.c 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. /*
  2. * This file is part of the MicroPython project, http://micropython.org/
  3. *
  4. * The MIT License (MIT)
  5. *
  6. * Copyright (c) 2018 Paul Sokolovsky
  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. #include <unistd.h> // for ssize_t
  27. #include "py/runtime.h"
  28. #if MICROPY_PY_COLLECTIONS_DEQUE
  29. typedef struct _mp_obj_deque_t {
  30. mp_obj_base_t base;
  31. size_t alloc;
  32. size_t i_get;
  33. size_t i_put;
  34. mp_obj_t *items;
  35. uint32_t flags;
  36. #define FLAG_CHECK_OVERFLOW 1
  37. } mp_obj_deque_t;
  38. static mp_obj_t mp_obj_deque_append(mp_obj_t self_in, mp_obj_t arg);
  39. static mp_obj_t mp_obj_deque_extend(mp_obj_t self_in, mp_obj_t arg_in);
  40. #if MICROPY_PY_COLLECTIONS_DEQUE_ITER
  41. static mp_obj_t mp_obj_new_deque_it(mp_obj_t deque, mp_obj_iter_buf_t *iter_buf);
  42. #endif
  43. static mp_obj_t deque_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
  44. mp_arg_check_num(n_args, n_kw, 2, 3, false);
  45. // Protect against -1 leading to zero-length allocation and bad array access
  46. mp_int_t maxlen = mp_obj_get_int(args[1]);
  47. if (maxlen < 0) {
  48. mp_raise_ValueError(NULL);
  49. }
  50. mp_obj_deque_t *o = mp_obj_malloc(mp_obj_deque_t, type);
  51. o->alloc = maxlen + 1;
  52. o->i_get = o->i_put = 0;
  53. o->items = m_new0(mp_obj_t, o->alloc);
  54. if (n_args > 2) {
  55. o->flags = mp_obj_get_int(args[2]);
  56. }
  57. mp_obj_deque_extend(MP_OBJ_FROM_PTR(o), args[0]);
  58. return MP_OBJ_FROM_PTR(o);
  59. }
  60. static size_t deque_len(mp_obj_deque_t *self) {
  61. ssize_t len = self->i_put - self->i_get;
  62. if (len < 0) {
  63. len += self->alloc;
  64. }
  65. return len;
  66. }
  67. static mp_obj_t deque_unary_op(mp_unary_op_t op, mp_obj_t self_in) {
  68. mp_obj_deque_t *self = MP_OBJ_TO_PTR(self_in);
  69. switch (op) {
  70. case MP_UNARY_OP_BOOL:
  71. return mp_obj_new_bool(self->i_get != self->i_put);
  72. case MP_UNARY_OP_LEN:
  73. return MP_OBJ_NEW_SMALL_INT(deque_len(self));
  74. #if MICROPY_PY_SYS_GETSIZEOF
  75. case MP_UNARY_OP_SIZEOF: {
  76. size_t sz = sizeof(*self) + sizeof(mp_obj_t) * self->alloc;
  77. return MP_OBJ_NEW_SMALL_INT(sz);
  78. }
  79. #endif
  80. default:
  81. return MP_OBJ_NULL; // op not supported
  82. }
  83. }
  84. static mp_obj_t mp_obj_deque_append(mp_obj_t self_in, mp_obj_t arg) {
  85. mp_obj_deque_t *self = MP_OBJ_TO_PTR(self_in);
  86. size_t new_i_put = self->i_put + 1;
  87. if (new_i_put == self->alloc) {
  88. new_i_put = 0;
  89. }
  90. if (self->flags & FLAG_CHECK_OVERFLOW && new_i_put == self->i_get) {
  91. mp_raise_msg(&mp_type_IndexError, MP_ERROR_TEXT("full"));
  92. }
  93. self->items[self->i_put] = arg;
  94. self->i_put = new_i_put;
  95. if (self->i_get == new_i_put) {
  96. if (++self->i_get == self->alloc) {
  97. self->i_get = 0;
  98. }
  99. }
  100. return mp_const_none;
  101. }
  102. static MP_DEFINE_CONST_FUN_OBJ_2(deque_append_obj, mp_obj_deque_append);
  103. static mp_obj_t mp_obj_deque_appendleft(mp_obj_t self_in, mp_obj_t arg) {
  104. mp_obj_deque_t *self = MP_OBJ_TO_PTR(self_in);
  105. size_t new_i_get = self->i_get - 1;
  106. if (self->i_get == 0) {
  107. new_i_get = self->alloc - 1;
  108. }
  109. if (self->flags & FLAG_CHECK_OVERFLOW && new_i_get == self->i_put) {
  110. mp_raise_msg(&mp_type_IndexError, MP_ERROR_TEXT("full"));
  111. }
  112. self->i_get = new_i_get;
  113. self->items[self->i_get] = arg;
  114. // overwriting first element in deque
  115. if (self->i_put == new_i_get) {
  116. if (self->i_put == 0) {
  117. self->i_put = self->alloc - 1;
  118. } else {
  119. self->i_put--;
  120. }
  121. }
  122. return mp_const_none;
  123. }
  124. static MP_DEFINE_CONST_FUN_OBJ_2(deque_appendleft_obj, mp_obj_deque_appendleft);
  125. static mp_obj_t mp_obj_deque_extend(mp_obj_t self_in, mp_obj_t arg_in) {
  126. mp_obj_iter_buf_t iter_buf;
  127. mp_obj_t iter = mp_getiter(arg_in, &iter_buf);
  128. mp_obj_t item;
  129. while ((item = mp_iternext(iter)) != MP_OBJ_STOP_ITERATION) {
  130. mp_obj_deque_append(self_in, item);
  131. }
  132. return mp_const_none;
  133. }
  134. static MP_DEFINE_CONST_FUN_OBJ_2(deque_extend_obj, mp_obj_deque_extend);
  135. static mp_obj_t deque_popleft(mp_obj_t self_in) {
  136. mp_obj_deque_t *self = MP_OBJ_TO_PTR(self_in);
  137. if (self->i_get == self->i_put) {
  138. mp_raise_msg(&mp_type_IndexError, MP_ERROR_TEXT("empty"));
  139. }
  140. mp_obj_t ret = self->items[self->i_get];
  141. self->items[self->i_get] = MP_OBJ_NULL;
  142. if (++self->i_get == self->alloc) {
  143. self->i_get = 0;
  144. }
  145. return ret;
  146. }
  147. static MP_DEFINE_CONST_FUN_OBJ_1(deque_popleft_obj, deque_popleft);
  148. static mp_obj_t deque_pop(mp_obj_t self_in) {
  149. mp_obj_deque_t *self = MP_OBJ_TO_PTR(self_in);
  150. if (self->i_get == self->i_put) {
  151. mp_raise_msg(&mp_type_IndexError, MP_ERROR_TEXT("empty"));
  152. }
  153. if (self->i_put == 0) {
  154. self->i_put = self->alloc - 1;
  155. } else {
  156. self->i_put--;
  157. }
  158. mp_obj_t ret = self->items[self->i_put];
  159. self->items[self->i_put] = MP_OBJ_NULL;
  160. return ret;
  161. }
  162. static MP_DEFINE_CONST_FUN_OBJ_1(deque_pop_obj, deque_pop);
  163. #if MICROPY_PY_COLLECTIONS_DEQUE_SUBSCR
  164. static mp_obj_t deque_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
  165. if (value == MP_OBJ_NULL) {
  166. // delete not supported, fall back to mp_obj_subscr() error message
  167. return MP_OBJ_NULL;
  168. }
  169. mp_obj_deque_t *self = MP_OBJ_TO_PTR(self_in);
  170. size_t offset = mp_get_index(self->base.type, deque_len(self), index, false);
  171. size_t index_val = self->i_get + offset;
  172. if (index_val > self->alloc) {
  173. index_val -= self->alloc;
  174. }
  175. if (value == MP_OBJ_SENTINEL) {
  176. // load
  177. return self->items[index_val];
  178. } else {
  179. // store into deque
  180. self->items[index_val] = value;
  181. return mp_const_none;
  182. }
  183. }
  184. #endif
  185. #if 0
  186. static mp_obj_t deque_clear(mp_obj_t self_in) {
  187. mp_obj_deque_t *self = MP_OBJ_TO_PTR(self_in);
  188. self->i_get = self->i_put = 0;
  189. mp_seq_clear(self->items, 0, self->alloc, sizeof(*self->items));
  190. return mp_const_none;
  191. }
  192. static MP_DEFINE_CONST_FUN_OBJ_1(deque_clear_obj, deque_clear);
  193. #endif
  194. static const mp_rom_map_elem_t deque_locals_dict_table[] = {
  195. { MP_ROM_QSTR(MP_QSTR_append), MP_ROM_PTR(&deque_append_obj) },
  196. { MP_ROM_QSTR(MP_QSTR_appendleft), MP_ROM_PTR(&deque_appendleft_obj) },
  197. { MP_ROM_QSTR(MP_QSTR_extend), MP_ROM_PTR(&deque_extend_obj) },
  198. #if 0
  199. { MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&deque_clear_obj) },
  200. #endif
  201. { MP_ROM_QSTR(MP_QSTR_pop), MP_ROM_PTR(&deque_pop_obj) },
  202. { MP_ROM_QSTR(MP_QSTR_popleft), MP_ROM_PTR(&deque_popleft_obj) },
  203. };
  204. static MP_DEFINE_CONST_DICT(deque_locals_dict, deque_locals_dict_table);
  205. #if MICROPY_PY_COLLECTIONS_DEQUE_ITER
  206. #define DEQUE_TYPE_FLAGS MP_TYPE_FLAG_ITER_IS_GETITER
  207. #define DEQUE_TYPE_ITER iter, mp_obj_new_deque_it,
  208. #else
  209. #define DEQUE_TYPE_FLAGS MP_TYPE_FLAG_NONE
  210. #define DEQUE_TYPE_ITER
  211. #endif
  212. #if MICROPY_PY_COLLECTIONS_DEQUE_SUBSCR
  213. #define DEQUE_TYPE_SUBSCR subscr, deque_subscr,
  214. #else
  215. #define DEQUE_TYPE_SUBSCR
  216. #endif
  217. MP_DEFINE_CONST_OBJ_TYPE(
  218. mp_type_deque,
  219. MP_QSTR_deque,
  220. MP_TYPE_FLAG_ITER_IS_GETITER,
  221. make_new, deque_make_new,
  222. unary_op, deque_unary_op,
  223. DEQUE_TYPE_SUBSCR
  224. DEQUE_TYPE_ITER
  225. locals_dict, &deque_locals_dict
  226. );
  227. /******************************************************************************/
  228. /* deque iterator */
  229. #if MICROPY_PY_COLLECTIONS_DEQUE_ITER
  230. typedef struct _mp_obj_deque_it_t {
  231. mp_obj_base_t base;
  232. mp_fun_1_t iternext;
  233. mp_obj_t deque;
  234. size_t cur;
  235. } mp_obj_deque_it_t;
  236. static mp_obj_t deque_it_iternext(mp_obj_t self_in) {
  237. mp_obj_deque_it_t *self = MP_OBJ_TO_PTR(self_in);
  238. mp_obj_deque_t *deque = MP_OBJ_TO_PTR(self->deque);
  239. if (self->cur != deque->i_put) {
  240. mp_obj_t o_out = deque->items[self->cur];
  241. if (++self->cur == deque->alloc) {
  242. self->cur = 0;
  243. }
  244. return o_out;
  245. } else {
  246. return MP_OBJ_STOP_ITERATION;
  247. }
  248. }
  249. static mp_obj_t mp_obj_new_deque_it(mp_obj_t deque, mp_obj_iter_buf_t *iter_buf) {
  250. mp_obj_deque_t *deque_ = MP_OBJ_TO_PTR(deque);
  251. size_t i_get = deque_->i_get;
  252. assert(sizeof(mp_obj_deque_it_t) <= sizeof(mp_obj_iter_buf_t));
  253. mp_obj_deque_it_t *o = (mp_obj_deque_it_t *)iter_buf;
  254. o->base.type = &mp_type_polymorph_iter;
  255. o->iternext = deque_it_iternext;
  256. o->deque = deque;
  257. o->cur = i_get;
  258. return MP_OBJ_FROM_PTR(o);
  259. }
  260. #endif
  261. #endif // MICROPY_PY_COLLECTIONS_DEQUE