py_tuple.c 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. #include "pocketpy/pocketpy.h"
  2. #include "pocketpy/common/utils.h"
  3. #include "pocketpy/common/sstream.h"
  4. #include "pocketpy/objects/object.h"
  5. #include "pocketpy/objects/iterator.h"
  6. #include "pocketpy/interpreter/vm.h"
  7. py_ObjectRef py_newtuple(py_OutRef out, int n) {
  8. VM* vm = pk_current_vm;
  9. PyObject* obj = ManagedHeap__gcnew(&vm->heap, tp_tuple, n, 0);
  10. out->type = tp_tuple;
  11. out->is_ptr = true;
  12. out->_obj = obj;
  13. return PyObject__slots(obj);
  14. }
  15. py_Ref py_tuple_getitem(py_Ref self, int i) { return py_getslot(self, i); }
  16. py_Ref py_tuple_data(py_Ref self) { return PyObject__slots(self->_obj); }
  17. void py_tuple_setitem(py_Ref self, int i, py_Ref val) { py_setslot(self, i, val); }
  18. int py_tuple_len(py_Ref self) { return self->_obj->slots; }
  19. //////////////
  20. static bool tuple__len__(int argc, py_Ref argv) {
  21. py_newint(py_retval(), py_tuple_len(argv));
  22. return true;
  23. }
  24. static bool tuple__repr__(int argc, py_Ref argv) {
  25. c11_sbuf buf;
  26. c11_sbuf__ctor(&buf);
  27. c11_sbuf__write_char(&buf, '(');
  28. int length = py_tuple_len(argv);
  29. for(int i = 0; i < length; i++) {
  30. py_TValue* val = py_getslot(argv, i);
  31. bool ok = py_repr(val);
  32. if(!ok) {
  33. c11_sbuf__dtor(&buf);
  34. return false;
  35. }
  36. c11_sbuf__write_sv(&buf, py_tosv(py_retval()));
  37. if(i != length - 1) c11_sbuf__write_cstr(&buf, ", ");
  38. }
  39. if(length == 1) c11_sbuf__write_char(&buf, ',');
  40. c11_sbuf__write_char(&buf, ')');
  41. c11_sbuf__py_submit(&buf, py_retval());
  42. return true;
  43. }
  44. static bool tuple__new__(int argc, py_Ref argv) {
  45. if(argc == 1 + 0) {
  46. py_newtuple(py_retval(), 0);
  47. return true;
  48. }
  49. if(argc == 1 + 1) {
  50. bool ok = py_tpcall(tp_list, 1, py_arg(1));
  51. if(!ok) return false;
  52. py_Ref tmp = py_pushtmp();
  53. *tmp = *py_retval(); // backup the list
  54. int length = py_list_len(tmp);
  55. py_Ref p = py_newtuple(py_retval(), length);
  56. for(int i = 0; i < py_tuple_len(py_retval()); i++) {
  57. p[i] = *py_list_getitem(tmp, i);
  58. }
  59. py_pop();
  60. return true;
  61. }
  62. return TypeError("tuple() takes at most 1 argument");
  63. }
  64. static bool tuple__getitem__(int argc, py_Ref argv) {
  65. PY_CHECK_ARGC(2);
  66. int length = py_tuple_len(argv);
  67. py_Ref _1 = py_arg(1);
  68. if(_1->type == tp_int) {
  69. int index = py_toint(py_arg(1));
  70. if(!pk__normalize_index(&index, length)) return false;
  71. *py_retval() = *py_getslot(argv, index);
  72. return true;
  73. } else if(_1->type == tp_slice) {
  74. int start, stop, step;
  75. bool ok = pk__parse_int_slice(_1, length, &start, &stop, &step);
  76. if(!ok) return false;
  77. py_Ref tmp = py_pushtmp();
  78. py_newlist(tmp);
  79. PK_SLICE_LOOP(i, start, stop, step) py_list_append(tmp, py_getslot(argv, i));
  80. // convert list to tuple
  81. py_Ref p = py_newtuple(py_retval(), py_list_len(tmp));
  82. for(int i = 0; i < py_tuple_len(py_retval()); i++) {
  83. p[i] = *py_list_getitem(tmp, i);
  84. }
  85. py_pop();
  86. return true;
  87. } else {
  88. return TypeError("tuple indices must be integers");
  89. }
  90. }
  91. static bool tuple__eq__(int argc, py_Ref argv) {
  92. return pk_wrapper__arrayequal(tp_tuple, argc, argv);
  93. }
  94. static bool tuple__ne__(int argc, py_Ref argv) {
  95. if(!tuple__eq__(argc, argv)) return false;
  96. if(py_isbool(py_retval())) {
  97. bool res = py_tobool(py_retval());
  98. py_newbool(py_retval(), !res);
  99. }
  100. return true;
  101. }
  102. static bool tuple__lt__(int argc, py_Ref argv) {
  103. PY_CHECK_ARGC(2);
  104. if(!py_istype(py_arg(1), tp_tuple)) {
  105. py_newnotimplemented(py_retval());
  106. return true;
  107. }
  108. py_TValue *p0, *p1;
  109. int lhs_length = py_tuple_len(py_arg(0));
  110. int rhs_length = py_tuple_len(py_arg(1));
  111. p0 = py_tuple_data(py_arg(0));
  112. p1 = py_tuple_data(py_arg(1));
  113. int length = lhs_length < rhs_length ? lhs_length : rhs_length;
  114. for(int i = 0; i < length; i++) {
  115. int res_lt = py_less(p0 + i, p1 + i);
  116. if(res_lt == -1) return false;
  117. if(res_lt) {
  118. py_newbool(py_retval(), true);
  119. return true;
  120. } else {
  121. int res_eq = py_equal(p0 + i, p1 + i);
  122. if(res_eq == -1) return false;
  123. if(!res_eq) {
  124. py_newbool(py_retval(), false);
  125. return true;
  126. }
  127. }
  128. }
  129. py_newbool(py_retval(), lhs_length < rhs_length);
  130. return true;
  131. }
  132. static bool tuple__iter__(int argc, py_Ref argv) {
  133. PY_CHECK_ARGC(1);
  134. tuple_iterator* ud = py_newobject(py_retval(), tp_tuple_iterator, 1, sizeof(tuple_iterator));
  135. ud->p = py_tuple_data(argv);
  136. ud->length = py_tuple_len(argv);
  137. ud->index = 0;
  138. py_setslot(py_retval(), 0, argv); // keep a reference to the object
  139. return true;
  140. }
  141. static bool tuple__contains__(int argc, py_Ref argv) {
  142. PY_CHECK_ARGC(2);
  143. return pk_arraycontains(py_arg(0), py_arg(1));
  144. }
  145. static bool tuple__hash__(int argc, py_Ref argv) {
  146. PY_CHECK_ARGC(1);
  147. int length = py_tuple_len(argv);
  148. py_TValue* data = py_tuple_data(argv);
  149. uint64_t x = 1000003;
  150. for(int i = 0; i < length; i++) {
  151. py_i64 y;
  152. if(!py_hash(&data[i], &y)) return false;
  153. // recommended by Github Copilot
  154. x = x ^ (y + 0x9e3779b9 + (x << 6) + (x >> 2));
  155. }
  156. py_newint(py_retval(), x);
  157. return true;
  158. }
  159. py_Type pk_tuple__register() {
  160. py_Type type = pk_newtype("tuple", tp_object, NULL, NULL, false, true);
  161. py_bindmagic(type, __len__, tuple__len__);
  162. py_bindmagic(type, __repr__, tuple__repr__);
  163. py_bindmagic(type, __new__, tuple__new__);
  164. py_bindmagic(type, __getitem__, tuple__getitem__);
  165. py_bindmagic(type, __eq__, tuple__eq__);
  166. py_bindmagic(type, __ne__, tuple__ne__);
  167. py_bindmagic(type, __lt__, tuple__lt__);
  168. py_bindmagic(type, __iter__, tuple__iter__);
  169. py_bindmagic(type, __contains__, tuple__contains__);
  170. py_bindmagic(type, __hash__, tuple__hash__);
  171. return type;
  172. }