py_tuple.c 5.0 KB

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