This commit is contained in:
blueloveTH 2025-02-13 15:41:03 +08:00
parent d744e654cc
commit a27e0e2210
2 changed files with 136 additions and 21 deletions

View File

@ -25,7 +25,9 @@ typedef struct c11_array2d {
typedef struct c11_array2d_view { typedef struct c11_array2d_view {
c11_array2d_like header; c11_array2d_like header;
c11_array2d_like* array; void* ctx;
py_Ref (*f_get)(void* ctx, int col, int row);
bool (*f_set)(void* ctx, int col, int row, py_Ref value);
c11_vec2i origin; c11_vec2i origin;
} c11_array2d_view; } c11_array2d_view;
@ -51,3 +53,6 @@ typedef struct c11_chunked_array2d {
py_TValue default_T; py_TValue default_T;
py_TValue context_builder; py_TValue context_builder;
} c11_chunked_array2d; } c11_chunked_array2d;
py_Ref c11_chunked_array2d__get(c11_chunked_array2d* self, int col, int row);
bool c11_chunked_array2d__set(c11_chunked_array2d* self, int col, int row, py_Ref value);

View File

@ -1,5 +1,7 @@
#include "pocketpy/interpreter/array2d.h" #include "pocketpy/interpreter/array2d.h"
#include "pocketpy/interpreter/vm.h" #include "pocketpy/interpreter/vm.h"
#include "pocketpy/pocketpy.h"
#include <limits.h>
static bool c11_array2d_like_is_valid(c11_array2d_like* self, unsigned int col, unsigned int row) { 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; return col < self->n_cols && row < self->n_rows;
@ -316,29 +318,62 @@ static bool _array2d_like_IndexError(c11_array2d_like* self, int col, int row) {
} }
static py_Ref c11_array2d_view__get(c11_array2d_view* self, int col, int row) { static py_Ref c11_array2d_view__get(c11_array2d_view* self, int col, int row) {
return self->array->f_get(self->array, col + self->origin.x, row + self->origin.y); return self->f_get(self->ctx, col + self->origin.x, row + self->origin.y);
} }
static bool c11_array2d_view__set(c11_array2d_view* self, int col, int row, py_Ref value) { static bool c11_array2d_view__set(c11_array2d_view* self, int col, int row, py_Ref value) {
return self->array->f_set(self->array, col + self->origin.x, row + self->origin.y, value); return self->f_set(self->ctx, col + self->origin.x, row + self->origin.y, value);
} }
static bool _array2d_view(py_OutRef out, static c11_array2d_view* _array2d_view__new(py_OutRef out,
c11_array2d_like* array, py_Ref keepalive,
int start_col, int start_col,
int start_row, int start_row,
int width, int width,
int height) { int height) {
c11_array2d_view* res = py_newobject(out, tp_array2d_view, 1, sizeof(c11_array2d_view)); c11_array2d_view* res = py_newobject(out, tp_array2d_view, 1, sizeof(c11_array2d_view));
if(width <= 0 || height <= 0) return ValueError("width and height must be positive"); if(width <= 0 || height <= 0) {
ValueError("width and height must be positive");
return NULL;
}
res->header.n_cols = width; res->header.n_cols = width;
res->header.n_rows = height; res->header.n_rows = height;
res->header.numel = width * height; res->header.numel = width * height;
res->header.f_get = (py_Ref(*)(c11_array2d_like*, int, int))c11_array2d_view__get; res->header.f_get = (py_Ref(*)(c11_array2d_like*, int, int))c11_array2d_view__get;
res->header.f_set = (bool (*)(c11_array2d_like*, int, int, py_Ref))c11_array2d_view__set; res->header.f_set = (bool (*)(c11_array2d_like*, int, int, py_Ref))c11_array2d_view__set;
res->array = array;
res->origin.x = start_col; res->origin.x = start_col;
res->origin.y = start_row; res->origin.y = start_row;
py_setslot(out, 0, keepalive);
return res;
}
static bool _array2d_view(py_OutRef out,
py_Ref keepalive,
c11_array2d_like* array,
int start_col,
int start_row,
int width,
int height) {
c11_array2d_view* res = _array2d_view__new(out, keepalive, start_col, start_row, width, height);
if(res == NULL) return false;
res->ctx = array;
res->f_get = (py_Ref(*)(void*, int, int))array->f_get;
res->f_set = (bool (*)(void*, int, int, py_Ref))array->f_set;
return true;
}
static bool _chunked_array2d_view(py_OutRef out,
py_Ref keepalive,
c11_chunked_array2d* array,
int start_col,
int start_row,
int width,
int height) {
c11_array2d_view* res = _array2d_view__new(out, keepalive, start_col, start_row, width, height);
if(res == NULL) return false;
res->ctx = array;
res->f_get = (py_Ref(*)(void*, int, int))c11_chunked_array2d__get;
res->f_set = (bool (*)(void*, int, int, py_Ref))c11_chunked_array2d__set;
return true; return true;
} }
@ -385,7 +420,13 @@ static bool array2d_like__getitem__(int argc, py_Ref argv) {
if(py_istype(x, tp_slice) && py_istype(y, tp_slice)) { if(py_istype(x, tp_slice) && py_istype(y, tp_slice)) {
HANDLE_SLICE(); HANDLE_SLICE();
return _array2d_view(py_retval(), self, start_col, start_row, slice_width, slice_height); return _array2d_view(py_retval(),
argv,
self,
start_col,
start_row,
slice_width,
slice_height);
} }
return TypeError("expected `tuple[int, int]` or `tuple[slice, slice]`"); return TypeError("expected `tuple[int, int]` or `tuple[slice, slice]`");
@ -754,7 +795,7 @@ static bool array2d_fromlist_STATIC(int argc, py_Ref argv) {
return true; return true;
} }
static void register_array2d(py_Ref mod){ static void register_array2d(py_Ref mod) {
py_Type type = py_newtype("array2d", tp_array2d_like, mod, NULL); py_Type type = py_newtype("array2d", tp_array2d_like, mod, NULL);
assert(type == tp_array2d); assert(type == tp_array2d);
py_bind(py_tpobject(type), py_bind(py_tpobject(type),
@ -848,7 +889,7 @@ static py_TValue* c11_chunked_array2d__parse_col_row(c11_chunked_array2d* self,
return data + 1; // skip context return data + 1; // skip context
} }
static py_Ref c11_chunked_array2d__get(c11_chunked_array2d* self, int col, int row) { py_Ref c11_chunked_array2d__get(c11_chunked_array2d* self, int col, int row) {
c11_vec2i chunk_pos, local_pos; c11_vec2i chunk_pos, local_pos;
py_TValue* data = c11_chunked_array2d__parse_col_row(self, col, row, &chunk_pos, &local_pos); py_TValue* data = c11_chunked_array2d__parse_col_row(self, col, row, &chunk_pos, &local_pos);
if(data == NULL) return NULL; if(data == NULL) return NULL;
@ -857,7 +898,7 @@ static py_Ref c11_chunked_array2d__get(c11_chunked_array2d* self, int col, int r
return retval; return retval;
} }
static bool c11_chunked_array2d__set(c11_chunked_array2d* self, int col, int row, py_Ref value) { bool c11_chunked_array2d__set(c11_chunked_array2d* self, int col, int row, py_Ref value) {
c11_vec2i chunk_pos, local_pos; c11_vec2i chunk_pos, local_pos;
py_TValue* data = c11_chunked_array2d__parse_col_row(self, col, row, &chunk_pos, &local_pos); py_TValue* data = c11_chunked_array2d__parse_col_row(self, col, row, &chunk_pos, &local_pos);
if(data == NULL) { if(data == NULL) {
@ -1037,8 +1078,73 @@ static void c11_chunked_array2d__mark(void* ud) {
} }
} }
static bool chunked_array2d_view(int argc, py_Ref argv) {
PY_CHECK_ARGC(1);
c11_chunked_array2d* self = py_touserdata(&argv[0]);
if(self->chunks.length == 0) { return ValueError("chunked_array2d is empty"); }
int min_chunk_x = INT_MAX;
int min_chunk_y = INT_MAX;
int max_chunk_x = INT_MIN;
int max_chunk_y = INT_MIN;
for(int i = 0; i < self->chunks.length; i++) {
c11_vec2i chunk_pos = c11__getitem(c11_chunked_array2d_chunks_KV, &self->chunks, i).key;
min_chunk_x = c11__min(min_chunk_x, chunk_pos.x);
min_chunk_y = c11__min(min_chunk_y, chunk_pos.y);
max_chunk_x = c11__max(max_chunk_x, chunk_pos.x);
max_chunk_y = c11__max(max_chunk_y, chunk_pos.y);
}
int start_col = min_chunk_x << self->chunk_size_log2;
int start_row = min_chunk_y << self->chunk_size_log2;
int width = (max_chunk_x - min_chunk_x + 1) * self->chunk_size;
int height = (max_chunk_y - min_chunk_y + 1) * self->chunk_size;
return _chunked_array2d_view(py_retval(), argv, self, start_col, start_row, width, height);
}
static bool chunked_array2d_view_rect(int argc, py_Ref argv) {
PY_CHECK_ARGC(4);
PY_CHECK_ARG_TYPE(1, tp_vec2i);
PY_CHECK_ARG_TYPE(2, tp_int);
PY_CHECK_ARG_TYPE(3, tp_int);
c11_chunked_array2d* self = py_touserdata(&argv[0]);
c11_vec2i pos = py_tovec2i(&argv[1]);
int width = py_toint(&argv[2]);
int height = py_toint(&argv[3]);
return _chunked_array2d_view(py_retval(), argv, self, pos.x, pos.y, width, height);
}
static bool chunked_array2d_view_chunk(int argc, py_Ref argv) {
PY_CHECK_ARGC(1);
PY_CHECK_ARG_TYPE(1, tp_vec2i);
c11_chunked_array2d* self = py_touserdata(&argv[0]);
c11_vec2i chunk_pos = py_tovec2i(&argv[1]);
int start_col = chunk_pos.x << self->chunk_size_log2;
int start_row = chunk_pos.y << self->chunk_size_log2;
return _chunked_array2d_view(py_retval(),
argv,
self,
start_col,
start_row,
self->chunk_size,
self->chunk_size);
}
static bool chunked_array2d_view_chunks(int argc, py_Ref argv) {
PY_CHECK_ARGC(4);
PY_CHECK_ARG_TYPE(1, tp_vec2i);
PY_CHECK_ARG_TYPE(2, tp_int);
PY_CHECK_ARG_TYPE(3, tp_int);
c11_chunked_array2d* self = py_touserdata(&argv[0]);
c11_vec2i chunk_pos = py_tovec2i(&argv[1]);
int width = py_toint(&argv[2]) * self->chunk_size;
int height = py_toint(&argv[3]) * self->chunk_size;
int start_col = chunk_pos.x << self->chunk_size_log2;
int start_row = chunk_pos.y << self->chunk_size_log2;
return _chunked_array2d_view(py_retval(), argv, self, start_col, start_row, width, height);
}
static void register_chunked_array2d(py_Ref mod) { static void register_chunked_array2d(py_Ref mod) {
py_Type type = py_newtype("chunked_array2d", tp_object, mod, (py_Dtor)c11_chunked_array2d__dtor); py_Type type =
py_newtype("chunked_array2d", tp_object, mod, (py_Dtor)c11_chunked_array2d__dtor);
pk__tp_set_marker(type, c11_chunked_array2d__mark); pk__tp_set_marker(type, c11_chunked_array2d__mark);
assert(type == tp_chunked_array2d); assert(type == tp_chunked_array2d);
@ -1059,8 +1165,12 @@ static void register_chunked_array2d(py_Ref mod) {
py_bindmethod(type, "add_chunk", chunked_array2d__add_chunk); py_bindmethod(type, "add_chunk", chunked_array2d__add_chunk);
py_bindmethod(type, "remove_chunk", chunked_array2d__remove_chunk); py_bindmethod(type, "remove_chunk", chunked_array2d__remove_chunk);
py_bindmethod(type, "get_context", chunked_array2d__get_context); py_bindmethod(type, "get_context", chunked_array2d__get_context);
}
py_bindmethod(type, "view", chunked_array2d_view);
py_bindmethod(type, "view_rect", chunked_array2d_view_rect);
py_bindmethod(type, "view_chunk", chunked_array2d_view_chunk);
py_bindmethod(type, "view_chunks", chunked_array2d_view_chunks);
}
void pk__add_module_array2d() { void pk__add_module_array2d() {
py_GlobalRef mod = py_newmodule("array2d"); py_GlobalRef mod = py_newmodule("array2d");