array2d.cpp 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. #include "pocketpy/array2d.h"
  2. namespace pkpy{
  3. struct Array2d{
  4. PK_ALWAYS_PASS_BY_POINTER(Array2d)
  5. PY_CLASS(Array2d, array2d, array2d)
  6. PyObject** data;
  7. int n_cols;
  8. int n_rows;
  9. int numel;
  10. Array2d(){
  11. data = nullptr;
  12. n_cols = 0;
  13. n_rows = 0;
  14. numel = 0;
  15. }
  16. Array2d* _() { return this; }
  17. void init(int n_cols, int n_rows){
  18. this->n_cols = n_cols;
  19. this->n_rows = n_rows;
  20. this->numel = n_cols * n_rows;
  21. this->data = new PyObject*[numel];
  22. }
  23. bool is_valid(int col, int row) const{
  24. return 0 <= col && col < n_cols && 0 <= row && row < n_rows;
  25. }
  26. static void _register(VM* vm, PyObject* mod, PyObject* type){
  27. vm->bind(type, "__new__(cls, *args, **kwargs)", [](VM* vm, ArgsView args){
  28. Type cls = PK_OBJ_GET(Type, args[0]);
  29. return vm->heap.gcnew<Array2d>(cls);
  30. });
  31. vm->bind(type, "__init__(self, n_cols: int, n_rows: int, default=None)", [](VM* vm, ArgsView args){
  32. Array2d& self = PK_OBJ_GET(Array2d, args[0]);
  33. int n_cols = CAST(int, args[1]);
  34. int n_rows = CAST(int, args[2]);
  35. if(n_cols <= 0 || n_rows <= 0){
  36. vm->ValueError("n_cols and n_rows must be positive integers");
  37. }
  38. self.init(n_cols, n_rows);
  39. if(vm->py_callable(args[3])){
  40. for(int i = 0; i < self.numel; i++) self.data[i] = vm->call(args[3]);
  41. }else{
  42. for(int i = 0; i < self.numel; i++) self.data[i] = args[3];
  43. }
  44. return vm->None;
  45. });
  46. PY_READONLY_FIELD(Array2d, "n_cols", _, n_cols);
  47. PY_READONLY_FIELD(Array2d, "n_rows", _, n_rows);
  48. PY_READONLY_FIELD(Array2d, "width", _, n_cols);
  49. PY_READONLY_FIELD(Array2d, "height", _, n_rows);
  50. PY_READONLY_FIELD(Array2d, "numel", _, numel);
  51. vm->bind(type, "is_valid(self, col: int, row: int)", [](VM* vm, ArgsView args){
  52. Array2d& self = PK_OBJ_GET(Array2d, args[0]);
  53. int col = CAST(int, args[1]);
  54. int row = CAST(int, args[2]);
  55. return VAR(self.is_valid(col, row));
  56. });
  57. vm->bind(type, "get(self, col: int, row: int, default=None)", [](VM* vm, ArgsView args){
  58. Array2d& self = PK_OBJ_GET(Array2d, args[0]);
  59. int col = CAST(int, args[1]);
  60. int row = CAST(int, args[2]);
  61. if(!self.is_valid(col, row)) return args[3];
  62. return self.data[row * self.n_cols + col];
  63. });
  64. vm->bind__getitem__(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* _0, PyObject* _1){
  65. Array2d& self = PK_OBJ_GET(Array2d, _0);
  66. const Tuple& xy = CAST(Tuple&, _1);
  67. int col = CAST(int, xy[0]);
  68. int row = CAST(int, xy[1]);
  69. if(!self.is_valid(col, row)){
  70. vm->IndexError(_S('(', col, ", ", row, ')', " is not a valid index for array2d(", self.n_cols, ", ", self.n_rows, ')'));
  71. }
  72. return self.data[row * self.n_cols + col];
  73. });
  74. vm->bind__setitem__(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* _0, PyObject* _1, PyObject* _2){
  75. Array2d& self = PK_OBJ_GET(Array2d, _0);
  76. const Tuple& xy = CAST(Tuple&, _1);
  77. int col = CAST(int, xy[0]);
  78. int row = CAST(int, xy[1]);
  79. if(!self.is_valid(col, row)){
  80. vm->IndexError(_S('(', col, ", ", row, ')', " is not a valid index for array2d(", self.n_cols, ", ", self.n_rows, ')'));
  81. }
  82. self.data[row * self.n_cols + col] = _2;
  83. });
  84. vm->bind__iter__(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* _0){
  85. Array2d& self = PK_OBJ_GET(Array2d, _0);
  86. List t(self.n_rows);
  87. List row(self.n_cols);
  88. for(int i = 0; i < self.n_rows; i++){
  89. for(int j = 0; j < self.n_cols; j++){
  90. row[j] = self.data[i * self.n_cols + j];
  91. }
  92. t[i] = VAR(row); // copy
  93. }
  94. return vm->py_iter(VAR(std::move(t)));
  95. });
  96. vm->bind__len__(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* _0){
  97. Array2d& self = PK_OBJ_GET(Array2d, _0);
  98. return (i64)self.n_rows;
  99. });
  100. vm->bind__repr__(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* _0){
  101. Array2d& self = PK_OBJ_GET(Array2d, _0);
  102. return VAR(_S("array2d(", self.n_cols, ", ", self.n_rows, ')'));
  103. });
  104. vm->bind(type, "map(self, f)", [](VM* vm, ArgsView args){
  105. Array2d& self = PK_OBJ_GET(Array2d, args[0]);
  106. PyObject* f = args[1];
  107. PyObject* new_array_obj = vm->heap.gcnew<Array2d>(Array2d::_type(vm));
  108. Array2d& new_array = PK_OBJ_GET(Array2d, new_array_obj);
  109. new_array.init(self.n_cols, self.n_rows);
  110. for(int i = 0; i < new_array.numel; i++){
  111. new_array.data[i] = vm->call(f, self.data[i]);
  112. }
  113. return new_array_obj;
  114. });
  115. vm->bind(type, "copy(self)", [](VM* vm, ArgsView args){
  116. Array2d& self = PK_OBJ_GET(Array2d, args[0]);
  117. PyObject* new_array_obj = vm->heap.gcnew<Array2d>(Array2d::_type(vm));
  118. Array2d& new_array = PK_OBJ_GET(Array2d, new_array_obj);
  119. new_array.init(self.n_cols, self.n_rows);
  120. for(int i = 0; i < new_array.numel; i++){
  121. new_array.data[i] = self.data[i];
  122. }
  123. return new_array_obj;
  124. });
  125. vm->bind(type, "fill_(self, value)", [](VM* vm, ArgsView args){
  126. Array2d& self = PK_OBJ_GET(Array2d, args[0]);
  127. for(int i = 0; i < self.numel; i++){
  128. self.data[i] = args[1];
  129. }
  130. return vm->None;
  131. });
  132. vm->bind(type, "apply_(self, f)", [](VM* vm, ArgsView args){
  133. Array2d& self = PK_OBJ_GET(Array2d, args[0]);
  134. PyObject* f = args[1];
  135. for(int i = 0; i < self.numel; i++){
  136. self.data[i] = vm->call(f, self.data[i]);
  137. }
  138. return vm->None;
  139. });
  140. vm->bind(type, "copy_(self, other)", [](VM* vm, ArgsView args){
  141. Array2d& self = PK_OBJ_GET(Array2d, args[0]);
  142. Array2d& other = CAST(Array2d&, args[1]);
  143. delete self.data;
  144. self.init(other.n_cols, other.n_rows);
  145. for(int i = 0; i < self.numel; i++){
  146. self.data[i] = other.data[i];
  147. }
  148. return vm->None;
  149. });
  150. vm->bind__eq__(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* _0, PyObject* _1){
  151. Array2d& self = PK_OBJ_GET(Array2d, _0);
  152. if(!is_non_tagged_type(_1, Array2d::_type(vm))) return vm->NotImplemented;
  153. Array2d& other = PK_OBJ_GET(Array2d, _1);
  154. if(self.n_cols != other.n_cols || self.n_rows != other.n_rows) return vm->False;
  155. for(int i = 0; i < self.numel; i++){
  156. if(vm->py_ne(self.data[i], other.data[i])) return vm->False;
  157. }
  158. return vm->True;
  159. });
  160. }
  161. void _gc_mark() const{
  162. for(int i = 0; i < numel; i++) PK_OBJ_MARK(data[i]);
  163. }
  164. ~Array2d(){
  165. delete[] data;
  166. }
  167. };
  168. void add_module_array2d(VM* vm){
  169. PyObject* mod = vm->new_module("array2d");
  170. Array2d::register_class(vm, mod);
  171. }
  172. } // namespace pkpy