From 76a96a0baa9da95d6af31ae079a11132ac29f00e Mon Sep 17 00:00:00 2001 From: blueloveTH Date: Wed, 12 Feb 2025 20:03:38 +0800 Subject: [PATCH] backup --- include/pocketpy/interpreter/array2d.h | 10 +- include/typings/array2d.pyi | 94 ++++--- src/modules/array2d.c | 375 +++++++++++++------------ 3 files changed, 250 insertions(+), 229 deletions(-) diff --git a/include/pocketpy/interpreter/array2d.h b/include/pocketpy/interpreter/array2d.h index b875adb0..498ff007 100644 --- a/include/pocketpy/interpreter/array2d.h +++ b/include/pocketpy/interpreter/array2d.h @@ -6,11 +6,17 @@ #include "pocketpy/common/sstream.h" #include "pocketpy/interpreter/vm.h" -typedef struct c11_array2d { - py_TValue* data; // slots +typedef struct c11_array2d_like { int n_cols; int n_rows; int numel; + py_Ref (*f_get)(struct c11_array2d_like* self, int col, int row); + bool (*f_set)(struct c11_array2d_like* self, int col, int row, py_Ref value); +} c11_array2d_like; + +typedef struct c11_array2d { + c11_array2d_like header; + py_TValue* data; // slots } c11_array2d; typedef struct c11_array2d_iterator { diff --git a/include/typings/array2d.pyi b/include/typings/array2d.pyi index 5c4ca01a..eb7ff2f4 100644 --- a/include/typings/array2d.pyi +++ b/include/typings/array2d.pyi @@ -1,4 +1,4 @@ -from typing import Callable, Any, Generic, TypeVar, Literal, overload, Iterator +from typing import Callable, Literal, overload, Iterator from linalg import vec2i Neighborhood = Literal['Moore', 'von Neumann'] @@ -13,6 +13,8 @@ class array2d_like[T]: @property def height(self) -> int: ... @property + def shape(self) -> vec2i: ... + @property def numel(self) -> int: ... @overload @@ -20,53 +22,37 @@ class array2d_like[T]: @overload def is_valid(self, pos: vec2i) -> bool: ... - @overload - def __getitem__(self, index: vec2i) -> T: ... - @overload - def __getitem__(self, index: tuple[int, int]) -> T: ... - @overload - def __setitem__(self, index: vec2i, value: T): ... - @overload - def __setitem__(self, index: tuple[int, int], value: T): ... - - -class array2d_view[T](array2d_like[T]): - origin: vec2i - - -class array2d[T](array2d_like[T]): - def __new__(cls, n_cols: int, n_rows: int, default: T | Callable[[vec2i], T] | None = None): ... - def __eq__(self, other: object) -> array2d[bool]: ... # type: ignore - def __ne__(self, other: object) -> array2d[bool]: ... # type: ignore - def __iter__(self) -> Iterator[tuple[vec2i, T]]: ... - def get[R](self, col: int, row: int, default: R = None) -> T | R: - """Gets the value at the given position. If the position is out of bounds, return the default value.""" - - @overload - def __getitem__(self, index: tuple[slice, slice]) -> array2d[T]: ... - @overload - def __getitem__(self, mask: array2d[bool]) -> list[T]: ... - @overload - def __setitem__(self, index: tuple[slice, slice], value: int | float | str | bool | None | 'array2d[T]'): ... - @overload - def __setitem__(self, mask: array2d[bool], value: T): ... - - def map[R](self, f: Callable[[T], R]) -> array2d[R]: ... - def copy(self) -> 'array2d[T]': ... - - def fill_(self, value: T) -> None: ... - def apply_(self, f: Callable[[T], T]) -> None: ... - def copy_(self, other: array2d[T] | list[T]) -> None: ... + """Get the value at the given position. + + If the position is out of bounds, return the default value. + """ def render(self) -> str: ... - def all(self: array2d[bool]) -> bool: ... - def any(self: array2d[bool]) -> bool: ... - - @staticmethod - def fromlist(data: list[list[T]]) -> array2d[T]: ... - def tolist(self) -> list[list[T]]: ... + def all(self: array2d_like[bool]) -> bool: ... + def any(self: array2d_like[bool]) -> bool: ... + + def map[R](self, f: Callable[[T], R]) -> array2d[R]: ... + def apply(self, f: Callable[[T], T]) -> None: ... + def copy(self) -> 'array2d[T]': ... + + @overload + def __getitem__(self, index: vec2i | tuple[int, int]) -> T: ... + @overload + def __getitem__(self, index: tuple[slice, slice]) -> array2d_view[T]: ... + @overload + def __getitem__(self, index: array2d_like[bool]) -> list[T]: ... + @overload + def __setitem__(self, index: vec2i | tuple[int, int], value: T): ... + @overload + def __setitem__(self, index: tuple[slice, slice], value: T | 'array2d_like[T]'): ... + @overload + def __setitem__(self, index: array2d_like[bool], value: T): ... + + def __eq__(self, other: object) -> array2d[bool]: ... # type: ignore + def __ne__(self, other: object) -> array2d[bool]: ... # type: ignore + def __iter__(self) -> Iterator[tuple[vec2i, T]]: ... # algorithms def count(self, value: T) -> int: @@ -81,7 +67,7 @@ class array2d[T](array2d_like[T]): Returns a tuple `(x, y, width, height)` or raise `ValueError` if the value is not found. """ - def convolve(self: array2d[int], kernel: array2d[int], padding: int) -> array2d[int]: + def convolve(self: array2d_like[int], kernel: array2d_like[int], padding: int) -> array2d[int]: """Convolves the array with the given kernel.""" def get_connected_components(self, value: T, neighborhood: Neighborhood) -> tuple[array2d[int], int]: @@ -92,6 +78,24 @@ class array2d[T](array2d_like[T]): """ +class array2d_view[T](array2d_like[T]): + @property + def origin(self) -> vec2i: ... + + +class array2d[T](array2d_like[T]): + def __new__( + cls, + n_cols: int, + n_rows: int, + default: T | Callable[[vec2i], T] | None = None + ): ... + + @staticmethod + def fromlist(data: list[list[T]]) -> array2d[T]: ... + def tolist(self) -> list[list[T]]: ... + + class chunked_array2d[T, TContext]: def __init__( self, diff --git a/src/modules/array2d.c b/src/modules/array2d.c index 6966e5a5..b577d7f2 100644 --- a/src/modules/array2d.c +++ b/src/modules/array2d.c @@ -1,86 +1,63 @@ #include "pocketpy/interpreter/array2d.h" -static bool py_array2d_is_valid(c11_array2d* self, int col, int row) { - return col >= 0 && col < self->n_cols && row >= 0 && row < self->n_rows; +static bool c11_array2d_like_is_valid(c11_array2d_like* self, unsigned int col, unsigned int row) { + return col < self->n_cols && row < self->n_rows; } -static py_ObjectRef py_array2d__get(c11_array2d* self, int col, int row) { - return self->data + row * self->n_cols + col; +static py_Ref py_array2d__get(c11_array2d* self, int col, int row) { + return self->data + row * self->header.n_cols + col; } - -static void py_array2d__set(c11_array2d* self, int col, int row, py_Ref value) { - self->data[row * self->n_cols + col] = *value; +static bool py_array2d__set(c11_array2d* self, int col, int row, py_Ref value) { + self->data[row * self->header.n_cols + col] = *value; + return true; } c11_array2d* py_newarray2d(py_OutRef out, int n_cols, int n_rows) { int numel = n_cols * n_rows; c11_array2d* ud = py_newobject(out, tp_array2d, numel, sizeof(c11_array2d)); + ud->header.n_cols = n_cols; + ud->header.n_rows = n_rows; + ud->header.numel = numel; + ud->header.f_get = (py_Ref (*)(c11_array2d_like*, int, int))py_array2d__get; + ud->header.f_set = (bool (*)(c11_array2d_like*, int, int, py_Ref))py_array2d__set; ud->data = py_getslot(out, 0); - ud->n_cols = n_cols; - ud->n_rows = n_rows; - ud->numel = numel; return ud; } -/* bindings */ -static bool array2d__new__(int argc, py_Ref argv) { - // __new__(cls, n_cols: int, n_rows: int, default: Callable[[vec2i], T] = None) - py_Ref default_ = py_arg(3); - PY_CHECK_ARG_TYPE(0, tp_type); - PY_CHECK_ARG_TYPE(1, tp_int); - PY_CHECK_ARG_TYPE(2, tp_int); - int n_cols = argv[1]._i64; - int n_rows = argv[2]._i64; - int numel = n_cols * n_rows; - if(n_cols <= 0 || n_rows <= 0) return ValueError("array2d() expected positive dimensions"); - c11_array2d* ud = py_newarray2d(py_pushtmp(), n_cols, n_rows); - // setup initial values - if(py_callable(default_)) { - for(int j = 0; j < n_rows; j++) { - for(int i = 0; i < n_cols; i++) { - py_TValue tmp; - py_newvec2i(&tmp, - (c11_vec2i){ - {i, j} - }); - bool ok = py_call(default_, 1, &tmp); - if(!ok) return false; - ud->data[j * n_cols + i] = *py_retval(); - } - } - } else { - for(int i = 0; i < numel; i++) { - ud->data[i] = *default_; - } - } - py_assign(py_retval(), py_peek(-1)); - py_pop(); - return true; -} - -static bool array2d_n_cols(int argc, py_Ref argv) { +/* array2d_like bindings */ +static bool array2d_like_n_cols(int argc, py_Ref argv) { PY_CHECK_ARGC(1); - c11_array2d* self = py_touserdata(argv); + c11_array2d_like* self = py_touserdata(argv); py_newint(py_retval(), self->n_cols); return true; } -static bool array2d_n_rows(int argc, py_Ref argv) { +static bool array2d_like_n_rows(int argc, py_Ref argv) { PY_CHECK_ARGC(1); - c11_array2d* self = py_touserdata(argv); + c11_array2d_like* self = py_touserdata(argv); py_newint(py_retval(), self->n_rows); return true; } -static bool array2d_numel(int argc, py_Ref argv) { +static bool array2d_like_shape(int argc, py_Ref argv) { PY_CHECK_ARGC(1); - c11_array2d* self = py_touserdata(argv); + c11_array2d_like* self = py_touserdata(argv); + c11_vec2i shape; + shape.x = self->n_cols; + shape.y = self->n_rows; + py_newvec2i(py_retval(), shape); + return true; +} + +static bool array2d_like_numel(int argc, py_Ref argv) { + PY_CHECK_ARGC(1); + c11_array2d_like* self = py_touserdata(argv); py_newint(py_retval(), self->numel); return true; } -static bool array2d_is_valid(int argc, py_Ref argv) { - c11_array2d* self = py_touserdata(argv); +static bool array2d_like_is_valid(int argc, py_Ref argv) { + c11_array2d_like* self = py_touserdata(argv); int col, row; if(argc == 2) { PY_CHECK_ARG_TYPE(1, tp_vec2i); @@ -95,15 +72,15 @@ static bool array2d_is_valid(int argc, py_Ref argv) { } else { return TypeError("is_valid() expected 2 or 3 arguments"); } - py_newbool(py_retval(), py_array2d_is_valid(self, col, row)); + py_newbool(py_retval(), c11_array2d_like_is_valid(self, col, row)); return true; } -static bool array2d_get(int argc, py_Ref argv) { - py_Ref default_; - c11_array2d* self = py_touserdata(argv); +static bool array2d_like_get(int argc, py_Ref argv) { PY_CHECK_ARG_TYPE(1, tp_int); PY_CHECK_ARG_TYPE(2, tp_int); + py_Ref default_; + c11_array2d_like* self = py_touserdata(argv); if(argc == 3) { default_ = py_None(); } else if(argc == 4) { @@ -113,14 +90,169 @@ static bool array2d_get(int argc, py_Ref argv) { } int col = py_toint(py_arg(1)); int row = py_toint(py_arg(2)); - if(py_array2d_is_valid(self, col, row)) { - py_assign(py_retval(), py_array2d__get(self, col, row)); + if(c11_array2d_like_is_valid(self, col, row)) { + py_assign(py_retval(), self->f_get(self, col, row)); } else { py_assign(py_retval(), default_); } return true; } +static bool array2d_like_render(int argc, py_Ref argv) { + PY_CHECK_ARGC(1); + c11_sbuf buf; + c11_sbuf__ctor(&buf); + c11_array2d_like* self = py_touserdata(argv); + for(int j = 0; j < self->n_rows; j++) { + for(int i = 0; i < self->n_cols; i++) { + py_Ref item = self->f_get(self, i, j); + if(!py_str(item)) return false; + c11_sbuf__write_sv(&buf, py_tosv(py_retval())); + } + if(j < self->n_rows - 1) c11_sbuf__write_char(&buf, '\n'); + } + c11_sbuf__py_submit(&buf, py_retval()); + return true; +} + +static bool array2d_like_all(int argc, py_Ref argv) { + PY_CHECK_ARGC(1); + c11_array2d_like* self = py_touserdata(argv); + for(int j = 0; j < self->n_rows; j++) { + for(int i = 0; i < self->n_cols; i++) { + py_Ref item = self->f_get(self, i, j); + if(!py_checkbool(item)) return false; + if(!py_tobool(item)) { + py_newbool(py_retval(), false); + return true; + } + } + } + py_newbool(py_retval(), true); + return true; +} + +static bool array2d_like_any(int argc, py_Ref argv) { + PY_CHECK_ARGC(1); + c11_array2d_like* self = py_touserdata(argv); + for(int j = 0; j < self->n_rows; j++) { + for(int i = 0; i < self->n_cols; i++) { + py_Ref item = self->f_get(self, i, j); + if(!py_checkbool(item)) return false; + if(py_tobool(item)) { + py_newbool(py_retval(), true); + return true; + } + } + } + py_newbool(py_retval(), false); + return true; +} + +static bool array2d_like_map(int argc, py_Ref argv) { + // def map(self, f: Callable[[T], Any]) -> 'array2d': ... + PY_CHECK_ARGC(2); + c11_array2d_like* self = py_touserdata(argv); + py_Ref f = py_arg(1); + c11_array2d* res = py_newarray2d(py_pushtmp(), self->n_cols, self->n_rows); + for(int j = 0; j < self->n_rows; j++) { + for(int i = 0; i < self->n_cols; i++) { + py_Ref item = self->f_get(self, i, j); + if(!py_call(f, 1, item)) return false; + res->data[j * self->n_cols + i] = *py_retval(); + } + } + py_assign(py_retval(), py_peek(-1)); + py_pop(); + return true; +} + +static bool array2d_like_copy(int argc, py_Ref argv) { + // def copy(self) -> 'array2d': ... + PY_CHECK_ARGC(1); + c11_array2d_like* self = py_touserdata(argv); + c11_array2d* res = py_newarray2d(py_retval(), self->n_cols, self->n_rows); + for(int j = 0; j < self->n_rows; j++) { + for(int i = 0; i < self->n_cols; i++) { + py_Ref item = self->f_get(self, i, j); + res->data[j * self->n_cols + i] = *item; + } + } + return true; +} + +static bool array2d_like_apply(int argc, py_Ref argv) { + // def apply_(self, f: Callable[[T], T]) -> None: ... + PY_CHECK_ARGC(2); + c11_array2d_like* self = py_touserdata(argv); + py_Ref f = py_arg(1); + for(int j = 0; j < self->n_rows; j++) { + for(int i = 0; i < self->n_cols; i++) { + py_Ref item = self->f_get(self, i, j); + if(!py_call(f, 1, item)) return false; + bool ok = self->f_set(self, i, j, py_retval()); + if(!ok) return false; + } + } + py_newnone(py_retval()); + return true; +} + +static void pk__register_array2d_like(py_Ref mod) { + py_Type type = py_newtype("array2d_like", tp_object, mod, NULL); + + py_bindproperty(type, "n_cols", array2d_like_n_cols, NULL); + py_bindproperty(type, "n_rows", array2d_like_n_rows, NULL); + py_bindproperty(type, "width", array2d_like_n_cols, NULL); + py_bindproperty(type, "height", array2d_like_n_rows, NULL); + py_bindproperty(type, "shape", array2d_like_shape, NULL); + py_bindproperty(type, "numel", array2d_like_numel, NULL); + + py_bindmethod(type, "is_valid", array2d_like_is_valid); + py_bindmethod(type, "get", array2d_like_get); + + py_bindmethod(type, "render", array2d_like_render); + + py_bindmethod(type, "all", array2d_like_all); + py_bindmethod(type, "any", array2d_like_any); + + py_bindmethod(type, "map", array2d_like_map); + py_bindmethod(type, "apply", array2d_like_apply); + py_bindmethod(type, "copy", array2d_like_copy); +} + +static bool array2d__new__(int argc, py_Ref argv) { + // __new__(cls, n_cols: int, n_rows: int, default: Callable[[vec2i], T] = None) + py_Ref default_ = py_arg(3); + PY_CHECK_ARG_TYPE(0, tp_type); + PY_CHECK_ARG_TYPE(1, tp_int); + PY_CHECK_ARG_TYPE(2, tp_int); + int n_cols = argv[1]._i64; + int n_rows = argv[2]._i64; + if(n_cols <= 0 || n_rows <= 0) return ValueError("array2d() expected positive dimensions"); + c11_array2d* ud = py_newarray2d(py_pushtmp(), n_cols, n_rows); + // setup initial values + if(py_callable(default_)) { + for(int j = 0; j < n_rows; j++) { + for(int i = 0; i < n_cols; i++) { + py_TValue tmp; + py_newvec2i(&tmp, (c11_vec2i){{i, j}}); + if(!py_call(default_, 1, &tmp)) return false; + ud->data[j * n_cols + i] = *py_retval(); + } + } + } else { + for(int i = 0; i < ud->header.numel; i++) { + ud->data[i] = *default_; + } + } + py_assign(py_retval(), py_peek(-1)); + py_pop(); + return true; +} + + + static bool _array2d_check_all_type(c11_array2d* self, py_Type type) { for(int i = 0; i < self->numel; i++) { py_Type item_type = self->data[i].type; @@ -144,33 +276,7 @@ static bool _array2d_check_same_shape(c11_array2d* self, c11_array2d* other) { return _check_same_shape(self->n_cols, self->n_rows, other->n_cols, other->n_rows); } -static bool array2d_all(int argc, py_Ref argv) { - PY_CHECK_ARGC(1); - c11_array2d* self = py_touserdata(argv); - if(!_array2d_check_all_type(self, tp_bool)) return false; - for(int i = 0; i < self->numel; i++) { - if(!py_tobool(self->data + i)) { - py_newbool(py_retval(), false); - return true; - } - } - py_newbool(py_retval(), true); - return true; -} -static bool array2d_any(int argc, py_Ref argv) { - PY_CHECK_ARGC(1); - c11_array2d* self = py_touserdata(argv); - if(!_array2d_check_all_type(self, tp_bool)) return false; - for(int i = 0; i < self->numel; i++) { - if(py_tobool(self->data + i)) { - py_newbool(py_retval(), true); - return true; - } - } - py_newbool(py_retval(), false); - return true; -} static bool array2d__eq__(int argc, py_Ref argv) { PY_CHECK_ARGC(2); @@ -247,80 +353,6 @@ static bool array2d_iterator__next__(int argc, py_Ref argv) { return StopIteration(); } -static bool array2d_map(int argc, py_Ref argv) { - // def map(self, f: Callable[[T], Any]) -> 'array2d': ... - PY_CHECK_ARGC(2); - c11_array2d* self = py_touserdata(argv); - py_Ref f = py_arg(1); - c11_array2d* res = py_newarray2d(py_pushtmp(), self->n_cols, self->n_rows); - for(int i = 0; i < self->numel; i++) { - bool ok = py_call(f, 1, self->data + i); - if(!ok) return false; - res->data[i] = *py_retval(); - } - py_assign(py_retval(), py_peek(-1)); - py_pop(); - return true; -} - -static bool array2d_copy(int argc, py_Ref argv) { - // def copy(self) -> 'array2d': ... - PY_CHECK_ARGC(1); - c11_array2d* self = py_touserdata(argv); - c11_array2d* res = py_newarray2d(py_retval(), self->n_cols, self->n_rows); - memcpy(res->data, self->data, self->numel * sizeof(py_TValue)); - return true; -} - -static bool array2d_fill_(int argc, py_Ref argv) { - // def fill_(self, value: T) -> None: ... - PY_CHECK_ARGC(2); - c11_array2d* self = py_touserdata(argv); - for(int i = 0; i < self->numel; i++) - self->data[i] = argv[1]; - py_newnone(py_retval()); - return true; -} - -static bool array2d_apply_(int argc, py_Ref argv) { - // def apply_(self, f: Callable[[T], T]) -> None: ... - PY_CHECK_ARGC(2); - c11_array2d* self = py_touserdata(argv); - py_Ref f = py_arg(1); - for(int i = 0; i < self->numel; i++) { - bool ok = py_call(f, 1, self->data + i); - if(!ok) return false; - self->data[i] = *py_retval(); - } - py_newnone(py_retval()); - return true; -} - -static bool array2d_copy_(int argc, py_Ref argv) { - // def copy_(self, src: 'array2d') -> None: ... - PY_CHECK_ARGC(2); - c11_array2d* self = py_touserdata(argv); - - py_Type src_type = py_typeof(py_arg(1)); - if(src_type == tp_array2d) { - c11_array2d* src = py_touserdata(py_arg(1)); - if(!_array2d_check_same_shape(self, src)) return false; - memcpy(self->data, src->data, self->numel * sizeof(py_TValue)); - } else { - py_TValue* data; - int length = pk_arrayview(py_arg(1), &data); - if(length != -1) { - if(self->numel != length) { - return ValueError("copy_() expected the same numel: %d != %d", self->numel, length); - } - memcpy(self->data, data, self->numel * sizeof(py_TValue)); - } else { - return TypeError("copy_() expected `array2d`, `list` or `tuple`, got '%t", src_type); - } - } - py_newnone(py_retval()); - return true; -} // fromlist(data: list[list[T]]) -> array2d[T] static bool array2d_fromlist_STATIC(int argc, py_Ref argv) { @@ -365,22 +397,7 @@ static bool array2d_tolist(int argc, py_Ref argv) { return true; } -static bool array2d_render(int argc, py_Ref argv) { - PY_CHECK_ARGC(1); - c11_sbuf buf; - c11_sbuf__ctor(&buf); - c11_array2d* self = py_touserdata(argv); - for(int j = 0; j < self->n_rows; j++) { - for(int i = 0; i < self->n_cols; i++) { - py_Ref item = py_array2d__get(self, i, j); - if(!py_str(item)) return false; - c11_sbuf__write_sv(&buf, py_tosv(py_retval())); - } - if(j < self->n_rows - 1) c11_sbuf__write_char(&buf, '\n'); - } - c11_sbuf__py_submit(&buf, py_retval()); - return true; -} + // count(self, value: T) -> int static bool array2d_count(int argc, py_Ref argv) { @@ -696,12 +713,6 @@ void pk__add_module_array2d() { py_bindmagic(array2d, __getitem__, array2d__getitem__); py_bindmagic(array2d, __setitem__, array2d__setitem__); - py_bindproperty(array2d, "n_cols", array2d_n_cols, NULL); - py_bindproperty(array2d, "n_rows", array2d_n_rows, NULL); - py_bindproperty(array2d, "width", array2d_n_cols, NULL); - py_bindproperty(array2d, "height", array2d_n_rows, NULL); - py_bindproperty(array2d, "numel", array2d_numel, NULL); - py_bindmethod(array2d, "is_valid", array2d_is_valid); py_bindmethod(array2d, "get", array2d_get);