py_tuple.c 5.6 KB

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