feat: indie status page MVP -- FastAPI + SQLite
- 8 DB models (services, incidents, monitors, subscribers, etc.) - Full CRUD API for services, incidents, monitors - Public status page with live data - Incident detail page with timeline - API key authentication - Uptime monitoring scheduler - 13 tests passing - TECHNICAL_DESIGN.md with full spec
This commit is contained in:
commit
902133edd3
4655 changed files with 1342691 additions and 0 deletions
1026
venv/lib/python3.11/site-packages/mypyc/lib-rt/vecs/librt_vecs.c
Normal file
1026
venv/lib/python3.11/site-packages/mypyc/lib-rt/vecs/librt_vecs.c
Normal file
File diff suppressed because it is too large
Load diff
873
venv/lib/python3.11/site-packages/mypyc/lib-rt/vecs/librt_vecs.h
Normal file
873
venv/lib/python3.11/site-packages/mypyc/lib-rt/vecs/librt_vecs.h
Normal file
|
|
@ -0,0 +1,873 @@
|
|||
#ifndef VEC_H_INCL
|
||||
#define VEC_H_INCL
|
||||
|
||||
// Header for the implementation of librt.vecs, which defines the 'vec' type.
|
||||
// Refer to librt_vecs.c for more detailed information.
|
||||
|
||||
#define PY_SSIZE_T_CLEAN
|
||||
#include <Python.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifndef MYPYC_EXPERIMENTAL
|
||||
|
||||
static int
|
||||
import_librt_vecs(void)
|
||||
{
|
||||
// All librt.vecs features are experimental for now, so don't set up the API here
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else // MYPYC_EXPERIMENTAL
|
||||
|
||||
// Magic (native) integer return value on exception. Caller must also
|
||||
// use PyErr_Occurred() since this overlaps with valid integer values.
|
||||
#define MYPYC_INT_ERROR -113
|
||||
|
||||
// Item type constants for supported packed/specialized item types; must be
|
||||
// even but not a multiple of 4 (2 + 4 * n). Each of these has a corresponding
|
||||
// distinct implementation C extension class. For example, vec[i64] has a
|
||||
// different runtime type than vec[i32]. All other item types use generic
|
||||
// implementations.
|
||||
#define VEC_ITEM_TYPE_I64 2
|
||||
#define VEC_ITEM_TYPE_I32 6
|
||||
#define VEC_ITEM_TYPE_I16 10
|
||||
#define VEC_ITEM_TYPE_U8 14
|
||||
#define VEC_ITEM_TYPE_FLOAT 18
|
||||
#define VEC_ITEM_TYPE_BOOL 22
|
||||
|
||||
static inline size_t Vec_IsMagicItemType(size_t item_type) {
|
||||
return item_type & 2;
|
||||
}
|
||||
|
||||
|
||||
// Buffer objects
|
||||
|
||||
|
||||
// vecbuf[i64]
|
||||
typedef struct _VecI64BufObject {
|
||||
PyObject_VAR_HEAD
|
||||
int64_t items[1];
|
||||
} VecI64BufObject;
|
||||
|
||||
// vecbuf[i32]
|
||||
typedef struct _VecI32BufObject {
|
||||
PyObject_VAR_HEAD
|
||||
int32_t items[1];
|
||||
} VecI32BufObject;
|
||||
|
||||
// vecbuf[i16]
|
||||
typedef struct _VecI16BufObject {
|
||||
PyObject_VAR_HEAD
|
||||
int16_t items[1];
|
||||
} VecI16BufObject;
|
||||
|
||||
// vecbuf[u8]
|
||||
typedef struct _VecU8BufObject {
|
||||
PyObject_VAR_HEAD
|
||||
uint8_t items[1];
|
||||
} VecU8BufObject;
|
||||
|
||||
// vecbuf[float]
|
||||
typedef struct _VecFloatBufObject {
|
||||
PyObject_VAR_HEAD
|
||||
double items[1];
|
||||
} VecFloatBufObject;
|
||||
|
||||
// vecbuf[bool]
|
||||
typedef struct _VecBoolBufObject {
|
||||
PyObject_VAR_HEAD
|
||||
char items[1];
|
||||
} VecBoolBufObject;
|
||||
|
||||
// Simple generic vecbuf: vecbuf[t] when t is a type object
|
||||
typedef struct _VecTBufObject {
|
||||
PyObject_VAR_HEAD
|
||||
// Tagged pointer to PyTypeObject *. The lowest bit is 1 for optional item type.
|
||||
size_t item_type;
|
||||
PyObject *items[1];
|
||||
} VecTBufObject;
|
||||
|
||||
typedef struct _VecNestedBufItem {
|
||||
Py_ssize_t len;
|
||||
PyObject *buf;
|
||||
} VecNestedBufItem;
|
||||
|
||||
// Nested vec type: vec[vec[...]], vec[vec[...] | None], etc.
|
||||
typedef struct _VecNestedBufObject {
|
||||
PyObject_VAR_HEAD
|
||||
// Tagged pointer to PyTypeObject *. Lowest bit is set for optional item type.
|
||||
// The second lowest bit is set for a packed item type (VEC_ITEM_TYPE_*).
|
||||
size_t item_type;
|
||||
// Number of nested vec types (of any kind, at least 1)
|
||||
size_t depth;
|
||||
VecNestedBufItem items[1];
|
||||
} VecNestedBufObject;
|
||||
|
||||
|
||||
// Unboxed vec objects
|
||||
|
||||
|
||||
typedef struct _VecI64 {
|
||||
Py_ssize_t len;
|
||||
VecI64BufObject *buf;
|
||||
} VecI64;
|
||||
|
||||
typedef struct _VecI32 {
|
||||
Py_ssize_t len;
|
||||
VecI32BufObject *buf;
|
||||
} VecI32;
|
||||
|
||||
typedef struct _VecI16 {
|
||||
Py_ssize_t len;
|
||||
VecI16BufObject *buf;
|
||||
} VecI16;
|
||||
|
||||
typedef struct _VecU8 {
|
||||
Py_ssize_t len;
|
||||
VecU8BufObject *buf;
|
||||
} VecU8;
|
||||
|
||||
typedef struct _VecFloat {
|
||||
Py_ssize_t len;
|
||||
VecFloatBufObject *buf;
|
||||
} VecFloat;
|
||||
|
||||
typedef struct _VecBool {
|
||||
Py_ssize_t len;
|
||||
VecBoolBufObject *buf;
|
||||
} VecBool;
|
||||
|
||||
typedef struct _VecT {
|
||||
Py_ssize_t len;
|
||||
VecTBufObject *buf;
|
||||
} VecT;
|
||||
|
||||
typedef struct _VecNested {
|
||||
Py_ssize_t len;
|
||||
VecNestedBufObject *buf;
|
||||
} VecNested;
|
||||
|
||||
|
||||
// Boxed vec objects
|
||||
|
||||
|
||||
// Arbitrary boxed vec object (only shared bits)
|
||||
typedef struct _VecObject {
|
||||
PyObject_HEAD
|
||||
Py_ssize_t len;
|
||||
} VecObject;
|
||||
|
||||
// Base vec type object (for isinstance checks)
|
||||
// This is an abstract base type that all specialized vec types inherit from.
|
||||
// It cannot be instantiated directly - only used for isinstance(x, vec).
|
||||
typedef struct _VecBaseObject {
|
||||
PyObject_HEAD
|
||||
} VecBaseObject;
|
||||
|
||||
// Boxed vec[i64]
|
||||
typedef struct _VecI64Object {
|
||||
PyObject_HEAD
|
||||
VecI64 vec;
|
||||
} VecI64Object;
|
||||
|
||||
// Boxed vec[i32]
|
||||
typedef struct _VecI32Object {
|
||||
PyObject_HEAD
|
||||
VecI32 vec;
|
||||
} VecI32Object;
|
||||
|
||||
// Boxed vec[i16]
|
||||
typedef struct _VecI16Object {
|
||||
PyObject_HEAD
|
||||
VecI16 vec;
|
||||
} VecI16Object;
|
||||
|
||||
// Boxed vec[u8]
|
||||
typedef struct _VecU8Object {
|
||||
PyObject_HEAD
|
||||
VecU8 vec;
|
||||
} VecU8Object;
|
||||
|
||||
// Boxed vec[float]
|
||||
typedef struct _VecFloatObject {
|
||||
PyObject_HEAD
|
||||
VecFloat vec;
|
||||
} VecFloatObject;
|
||||
|
||||
// Boxed vec[bool]
|
||||
typedef struct _VecBoolObject {
|
||||
PyObject_HEAD
|
||||
VecBool vec;
|
||||
} VecBoolObject;
|
||||
|
||||
// Simple boxed generic vecbuf: vecbuf[t] when t is a type object
|
||||
typedef struct _VecTObject {
|
||||
PyObject_HEAD
|
||||
VecT vec;
|
||||
} VecTObject;
|
||||
|
||||
// Extended generic vec type: vec[t | None], vec[vec[...]], etc.
|
||||
typedef struct _VecNestedObject {
|
||||
PyObject_HEAD
|
||||
VecNested vec;
|
||||
} VecNestedObject;
|
||||
|
||||
|
||||
#ifndef MYPYC_DECLARED_tuple_T2V88
|
||||
#define MYPYC_DECLARED_tuple_T2V88
|
||||
typedef struct tuple_T2V88 {
|
||||
VecI64 f0;
|
||||
int64_t f1;
|
||||
} tuple_T2V88;
|
||||
static tuple_T2V88 tuple_undefined_T2V88 = { { -1, NULL } , 0 };
|
||||
#endif
|
||||
|
||||
#ifndef MYPYC_DECLARED_tuple_T2V44
|
||||
#define MYPYC_DECLARED_tuple_T2V44
|
||||
typedef struct tuple_T2V44 {
|
||||
VecI32 f0;
|
||||
int32_t f1;
|
||||
} tuple_T2V44;
|
||||
static tuple_T2V44 tuple_undefined_T2V44 = { { -1, NULL } , 0 };
|
||||
#endif
|
||||
|
||||
#ifndef MYPYC_DECLARED_tuple_T2V22
|
||||
#define MYPYC_DECLARED_tuple_T2V22
|
||||
typedef struct tuple_T2V22 {
|
||||
VecI16 f0;
|
||||
int16_t f1;
|
||||
} tuple_T2V22;
|
||||
static tuple_T2V22 tuple_undefined_T2V22 = { { -1, NULL } , 0 };
|
||||
#endif
|
||||
|
||||
#ifndef MYPYC_DECLARED_tuple_T2VU1U1
|
||||
#define MYPYC_DECLARED_tuple_T2VU1U1
|
||||
typedef struct tuple_T2VU1U1 {
|
||||
VecU8 f0;
|
||||
uint8_t f1;
|
||||
} tuple_T2VU1U1;
|
||||
static tuple_T2VU1U1 tuple_undefined_T2VU1U1 = { { -1, NULL } , 0 };
|
||||
#endif
|
||||
|
||||
#ifndef MYPYC_DECLARED_tuple_T2VFF
|
||||
#define MYPYC_DECLARED_tuple_T2VFF
|
||||
typedef struct tuple_T2VFF {
|
||||
VecFloat f0;
|
||||
double f1;
|
||||
} tuple_T2VFF;
|
||||
static tuple_T2VFF tuple_undefined_T2VFF = { { -1, NULL } , 0.0 };
|
||||
#endif
|
||||
|
||||
#ifndef MYPYC_DECLARED_tuple_T2VCC
|
||||
#define MYPYC_DECLARED_tuple_T2VCC
|
||||
typedef struct tuple_T2VCC {
|
||||
VecBool f0;
|
||||
char f1;
|
||||
} tuple_T2VCC;
|
||||
static tuple_T2VCC tuple_undefined_T2VCC = { { -1, NULL } , 0 };
|
||||
#endif
|
||||
|
||||
typedef tuple_T2V88 VecI64PopResult;
|
||||
typedef tuple_T2V44 VecI32PopResult;
|
||||
typedef tuple_T2V22 VecI16PopResult;
|
||||
typedef tuple_T2VU1U1 VecU8PopResult;
|
||||
typedef tuple_T2VFF VecFloatPopResult;
|
||||
typedef tuple_T2VCC VecBoolPopResult;
|
||||
|
||||
// vec[i64] operations + type objects (stored in a capsule)
|
||||
typedef struct _VecI64API {
|
||||
PyTypeObject *boxed_type;
|
||||
PyTypeObject *buf_type;
|
||||
VecI64 (*alloc)(Py_ssize_t, Py_ssize_t);
|
||||
PyObject *(*box)(VecI64);
|
||||
VecI64 (*unbox)(PyObject *);
|
||||
VecI64 (*convert_from_nested)(VecNestedBufItem);
|
||||
VecI64 (*append)(VecI64, int64_t);
|
||||
VecI64PopResult (*pop)(VecI64, Py_ssize_t);
|
||||
VecI64 (*remove)(VecI64, int64_t);
|
||||
// TODO: Py_ssize_t
|
||||
VecI64 (*slice)(VecI64, int64_t, int64_t);
|
||||
// PyObject *(*extend)(PyObject *, PyObject *);
|
||||
// PyObject *(*concat)(PyObject *, PyObject *);
|
||||
// bool (*contains)(PyObject *, int64_t);
|
||||
// iter?
|
||||
} VecI64API;
|
||||
|
||||
// vec[i32] operations + type objects (stored in a capsule)
|
||||
typedef struct _VecI32API {
|
||||
PyTypeObject *boxed_type;
|
||||
PyTypeObject *buf_type;
|
||||
VecI32 (*alloc)(Py_ssize_t, Py_ssize_t);
|
||||
PyObject *(*box)(VecI32);
|
||||
VecI32 (*unbox)(PyObject *);
|
||||
VecI32 (*convert_from_nested)(VecNestedBufItem);
|
||||
VecI32 (*append)(VecI32, int32_t);
|
||||
VecI32PopResult (*pop)(VecI32, Py_ssize_t);
|
||||
VecI32 (*remove)(VecI32, int32_t);
|
||||
// TODO: Py_ssize_t
|
||||
VecI32 (*slice)(VecI32, int64_t, int64_t);
|
||||
// PyObject *(*extend)(PyObject *, PyObject *);
|
||||
// PyObject *(*concat)(PyObject *, PyObject *);
|
||||
// bool (*contains)(PyObject *, int32_t);
|
||||
// iter?
|
||||
} VecI32API;
|
||||
|
||||
// vec[i16] operations + type objects (stored in a capsule)
|
||||
typedef struct _VecI16API {
|
||||
PyTypeObject *boxed_type;
|
||||
PyTypeObject *buf_type;
|
||||
VecI16 (*alloc)(Py_ssize_t, Py_ssize_t);
|
||||
PyObject *(*box)(VecI16);
|
||||
VecI16 (*unbox)(PyObject *);
|
||||
VecI16 (*convert_from_nested)(VecNestedBufItem);
|
||||
VecI16 (*append)(VecI16, int16_t);
|
||||
VecI16PopResult (*pop)(VecI16, Py_ssize_t);
|
||||
VecI16 (*remove)(VecI16, int16_t);
|
||||
// TODO: Py_ssize_t
|
||||
VecI16 (*slice)(VecI16, int64_t, int64_t);
|
||||
// PyObject *(*extend)(PyObject *, PyObject *);
|
||||
// PyObject *(*concat)(PyObject *, PyObject *);
|
||||
// bool (*contains)(PyObject *, int16_t);
|
||||
// iter?
|
||||
} VecI16API;
|
||||
|
||||
// vec[u8] operations + type objects (stored in a capsule)
|
||||
typedef struct _VecU8API {
|
||||
PyTypeObject *boxed_type;
|
||||
PyTypeObject *buf_type;
|
||||
VecU8 (*alloc)(Py_ssize_t, Py_ssize_t);
|
||||
PyObject *(*box)(VecU8);
|
||||
VecU8 (*unbox)(PyObject *);
|
||||
VecU8 (*convert_from_nested)(VecNestedBufItem);
|
||||
VecU8 (*append)(VecU8, uint8_t);
|
||||
VecU8PopResult (*pop)(VecU8, Py_ssize_t);
|
||||
VecU8 (*remove)(VecU8, uint8_t);
|
||||
// TODO: Py_ssize_t
|
||||
VecU8 (*slice)(VecU8, int64_t, int64_t);
|
||||
// PyObject *(*extend)(PyObject *, PyObject *);
|
||||
// PyObject *(*concat)(PyObject *, PyObject *);
|
||||
// bool (*contains)(PyObject *, uint8_t);
|
||||
// iter?
|
||||
} VecU8API;
|
||||
|
||||
// vec[float] operations + type objects (stored in a capsule)
|
||||
typedef struct _VecFloatAPI {
|
||||
PyTypeObject *boxed_type;
|
||||
PyTypeObject *buf_type;
|
||||
VecFloat (*alloc)(Py_ssize_t, Py_ssize_t);
|
||||
PyObject *(*box)(VecFloat);
|
||||
VecFloat (*unbox)(PyObject *);
|
||||
VecFloat (*convert_from_nested)(VecNestedBufItem);
|
||||
VecFloat (*append)(VecFloat, double);
|
||||
VecFloatPopResult (*pop)(VecFloat, Py_ssize_t);
|
||||
VecFloat (*remove)(VecFloat, double);
|
||||
// TODO: Py_ssize_t
|
||||
VecFloat (*slice)(VecFloat, int64_t, int64_t);
|
||||
// PyObject *(*extend)(PyObject *, PyObject *);
|
||||
// PyObject *(*concat)(PyObject *, PyObject *);
|
||||
// bool (*contains)(PyObject *, double);
|
||||
// iter?
|
||||
} VecFloatAPI;
|
||||
|
||||
// vec[bool] operations + type objects (stored in a capsule)
|
||||
typedef struct _VecBoolAPI {
|
||||
PyTypeObject *boxed_type;
|
||||
PyTypeObject *buf_type;
|
||||
VecBool (*alloc)(Py_ssize_t, Py_ssize_t);
|
||||
PyObject *(*box)(VecBool);
|
||||
VecBool (*unbox)(PyObject *);
|
||||
VecBool (*convert_from_nested)(VecNestedBufItem);
|
||||
VecBool (*append)(VecBool, char);
|
||||
VecBoolPopResult (*pop)(VecBool, Py_ssize_t);
|
||||
VecBool (*remove)(VecBool, char);
|
||||
// TODO: Py_ssize_t
|
||||
VecBool (*slice)(VecBool, int64_t, int64_t);
|
||||
// PyObject *(*extend)(PyObject *, PyObject *);
|
||||
// PyObject *(*concat)(PyObject *, PyObject *);
|
||||
// bool (*contains)(PyObject *, char);
|
||||
// iter?
|
||||
} VecBoolAPI;
|
||||
|
||||
#ifndef MYPYC_DECLARED_tuple_T2VOO
|
||||
#define MYPYC_DECLARED_tuple_T2VOO
|
||||
typedef struct tuple_T2VOO {
|
||||
VecT f0;
|
||||
PyObject *f1;
|
||||
} tuple_T2VOO;
|
||||
static tuple_T2VOO tuple_undefined_T2VOO = { { -1, NULL } , NULL };
|
||||
#endif
|
||||
|
||||
typedef tuple_T2VOO VecTPopResult;
|
||||
|
||||
// vec[T] operations + type objects (stored in a capsule)
|
||||
//
|
||||
// T is a class type or class type | None
|
||||
typedef struct _VecTAPI {
|
||||
PyTypeObject *boxed_type;
|
||||
PyTypeObject *buf_type;
|
||||
VecT (*alloc)(Py_ssize_t, Py_ssize_t, size_t);
|
||||
PyObject *(*box)(VecT, size_t);
|
||||
VecT (*unbox)(PyObject *, size_t);
|
||||
VecT (*convert_from_nested)(VecNestedBufItem);
|
||||
VecT (*append)(VecT, PyObject *, size_t);
|
||||
VecTPopResult (*pop)(VecT, Py_ssize_t);
|
||||
VecT (*remove)(VecT, PyObject *);
|
||||
// TODO: Py_ssize_t
|
||||
VecT (*slice)(VecT, int64_t, int64_t);
|
||||
// PyObject *(*extend)(PyObject *, PyObject *);
|
||||
// PyObject *(*concat)(PyObject *, PyObject *);
|
||||
// bool (*contains)(PyObject *, PyObject *);
|
||||
// iter?
|
||||
} VecTAPI;
|
||||
|
||||
|
||||
#ifndef MYPYC_DECLARED_tuple_T2VvVi
|
||||
#define MYPYC_DECLARED_tuple_T2VvVi
|
||||
typedef struct tuple_T2VvVi {
|
||||
VecNested f0;
|
||||
VecNestedBufItem f1;
|
||||
} tuple_T2VvVi;
|
||||
static tuple_T2VvVi tuple_undefined_T2VvVi = { { -1, NULL } , { -1, NULL } };
|
||||
#endif
|
||||
|
||||
typedef tuple_T2VvVi VecNestedPopResult;
|
||||
|
||||
// Nested vec operations + type objects (stored in a capsule)
|
||||
typedef struct _VecNestedAPI {
|
||||
PyTypeObject *boxed_type;
|
||||
PyTypeObject *buf_type;
|
||||
VecNested (*alloc)(Py_ssize_t, Py_ssize_t, size_t, size_t depth);
|
||||
PyObject *(*box)(VecNested);
|
||||
VecNested (*unbox)(PyObject *, size_t, size_t depth);
|
||||
VecNested (*convert_from_nested)(VecNestedBufItem);
|
||||
VecNested (*append)(VecNested, VecNestedBufItem);
|
||||
VecNestedPopResult (*pop)(VecNested, Py_ssize_t);
|
||||
VecNested (*remove)(VecNested, VecNestedBufItem);
|
||||
// TODO: Py_ssize_t
|
||||
VecNested (*slice)(VecNested, int64_t, int64_t);
|
||||
// PyObject *(*extend)(PyObject *, PyObject *);
|
||||
// PyObject *(*concat)(PyObject *, PyObject *);
|
||||
// bool (*contains)(PyObject *, PyObject *);
|
||||
// iter?
|
||||
} VecNestedAPI;
|
||||
|
||||
typedef struct {
|
||||
VecTAPI *t;
|
||||
VecNestedAPI *nested;
|
||||
VecI64API *i64;
|
||||
VecI32API *i32;
|
||||
VecI16API *i16;
|
||||
VecU8API *u8;
|
||||
VecFloatAPI *float_;
|
||||
VecBoolAPI *bool_;
|
||||
PyTypeObject *(*get_vec_type)(void); // Function to get base VecType for isinstance checks
|
||||
} VecCapsule;
|
||||
|
||||
#define VEC_BUF_SIZE(b) ((b)->ob_base.ob_size)
|
||||
#define VEC_ITEM_TYPE(t) ((PyTypeObject *)((t) & ~1))
|
||||
#define VEC_BUF_ITEM_TYPE(b) VEC_ITEM_TYPE((b)->item_type)
|
||||
#define VEC_CAP(v) ((v).buf->ob_base.ob_size)
|
||||
#define VEC_IS_ERROR(v) ((v).len < 0)
|
||||
#define VEC_DECREF(v) Py_XDECREF((v).buf)
|
||||
#define VEC_INCREF(v) Py_XINCREF((v).buf)
|
||||
|
||||
// Type objects
|
||||
|
||||
// Buffer type objects that store vec items
|
||||
extern PyTypeObject VecI64BufType;
|
||||
extern PyTypeObject VecI32BufType;
|
||||
extern PyTypeObject VecI16BufType;
|
||||
extern PyTypeObject VecU8BufType;
|
||||
extern PyTypeObject VecFloatBufType;
|
||||
extern PyTypeObject VecBoolBufType;
|
||||
extern PyTypeObject VecTBufType;
|
||||
extern PyTypeObject VecNestedBufType;
|
||||
|
||||
// Wrapper type objects for boxed vec values
|
||||
extern PyTypeObject VecI64Type;
|
||||
extern PyTypeObject VecI32Type;
|
||||
extern PyTypeObject VecI16Type;
|
||||
extern PyTypeObject VecU8Type;
|
||||
extern PyTypeObject VecFloatType;
|
||||
extern PyTypeObject VecBoolType;
|
||||
extern PyTypeObject VecTType;
|
||||
extern PyTypeObject VecNestedType;
|
||||
|
||||
// Type objects corresponding to the 'i64', 'i32', 'i16, and 'u8' types
|
||||
extern PyTypeObject *LibRTVecs_I64TypeObj;
|
||||
extern PyTypeObject *LibRTVecs_I32TypeObj;
|
||||
extern PyTypeObject *LibRTVecs_I16TypeObj;
|
||||
extern PyTypeObject *LibRTVecs_U8TypeObj;
|
||||
|
||||
extern VecI64API Vec_I64API;
|
||||
extern VecI32API Vec_I32API;
|
||||
extern VecI16API Vec_I16API;
|
||||
extern VecU8API Vec_U8API;
|
||||
extern VecFloatAPI Vec_FloatAPI;
|
||||
extern VecBoolAPI Vec_BoolAPI;
|
||||
extern VecTAPI Vec_TAPI;
|
||||
extern VecNestedAPI Vec_NestedAPI;
|
||||
|
||||
static inline int Vec_CheckFloatError(PyObject *o) {
|
||||
if (PyFloat_Check(o)) {
|
||||
PyErr_SetString(PyExc_TypeError, "integer argument expected, got float");
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// vec[i64] operations
|
||||
|
||||
static inline int VecI64_Check(PyObject *o) {
|
||||
return o->ob_type == &VecI64Type;
|
||||
}
|
||||
|
||||
static inline PyObject *VecI64_BoxItem(int64_t x) {
|
||||
return PyLong_FromLongLong(x);
|
||||
}
|
||||
|
||||
static inline int64_t VecI64_UnboxItem(PyObject *o) {
|
||||
if (Vec_CheckFloatError(o))
|
||||
return -1;
|
||||
return PyLong_AsLongLong(o);
|
||||
}
|
||||
|
||||
static inline int VecI64_IsUnboxError(int64_t x) {
|
||||
return x == -1 && PyErr_Occurred();
|
||||
}
|
||||
|
||||
PyObject *VecI64_Box(VecI64);
|
||||
VecI64 VecI64_Append(VecI64, int64_t x);
|
||||
VecI64 VecI64_Remove(VecI64, int64_t x);
|
||||
VecI64PopResult VecI64_Pop(VecI64 v, Py_ssize_t index);
|
||||
|
||||
// vec[i32] operations
|
||||
|
||||
static inline int VecI32_Check(PyObject *o) {
|
||||
return o->ob_type == &VecI32Type;
|
||||
}
|
||||
|
||||
static inline PyObject *VecI32_BoxItem(int32_t x) {
|
||||
return PyLong_FromLongLong(x);
|
||||
}
|
||||
|
||||
static inline int32_t VecI32_UnboxItem(PyObject *o) {
|
||||
if (Vec_CheckFloatError(o))
|
||||
return -1;
|
||||
long x = PyLong_AsLong(o);
|
||||
if (x > INT32_MAX || x < INT32_MIN) {
|
||||
PyErr_SetString(PyExc_OverflowError, "Python int too large to convert to i32");
|
||||
return -1;
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
static inline int VecI32_IsUnboxError(int32_t x) {
|
||||
return x == -1 && PyErr_Occurred();
|
||||
}
|
||||
|
||||
PyObject *VecI32_Box(VecI32);
|
||||
VecI32 VecI32_Append(VecI32, int32_t x);
|
||||
VecI32 VecI32_Remove(VecI32, int32_t x);
|
||||
VecI32PopResult VecI32_Pop(VecI32 v, Py_ssize_t index);
|
||||
|
||||
// vec[i16] operations
|
||||
|
||||
static inline int VecI16_Check(PyObject *o) {
|
||||
return o->ob_type == &VecI16Type;
|
||||
}
|
||||
|
||||
static inline PyObject *VecI16_BoxItem(int16_t x) {
|
||||
return PyLong_FromLongLong(x);
|
||||
}
|
||||
|
||||
static inline int16_t VecI16_UnboxItem(PyObject *o) {
|
||||
if (Vec_CheckFloatError(o))
|
||||
return -1;
|
||||
long x = PyLong_AsLong(o);
|
||||
if (x >= 32768 || x < -32768) {
|
||||
PyErr_SetString(PyExc_OverflowError, "Python int too large to convert to i16");
|
||||
return -1;
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
static inline int VecI16_IsUnboxError(int16_t x) {
|
||||
return x == -1 && PyErr_Occurred();
|
||||
}
|
||||
|
||||
PyObject *VecI16_Box(VecI16);
|
||||
VecI16 VecI16_Append(VecI16, int16_t x);
|
||||
VecI16 VecI16_Remove(VecI16, int16_t x);
|
||||
VecI16PopResult VecI16_Pop(VecI16 v, Py_ssize_t index);
|
||||
|
||||
// vec[u8] operations
|
||||
|
||||
static inline int VecU8_Check(PyObject *o) {
|
||||
return o->ob_type == &VecU8Type;
|
||||
}
|
||||
|
||||
static inline PyObject *VecU8_BoxItem(uint8_t x) {
|
||||
return PyLong_FromUnsignedLong(x);
|
||||
}
|
||||
|
||||
static inline uint8_t VecU8_UnboxItem(PyObject *o) {
|
||||
if (Vec_CheckFloatError(o))
|
||||
return -1;
|
||||
unsigned long x = PyLong_AsUnsignedLong(o);
|
||||
if (x <= 255)
|
||||
return x;
|
||||
else if (x == (unsigned long)-1)
|
||||
return 239;
|
||||
else {
|
||||
PyErr_SetString(PyExc_OverflowError, "Python int too large to convert to u8");
|
||||
return 239;
|
||||
}
|
||||
}
|
||||
|
||||
static inline int VecU8_IsUnboxError(uint8_t x) {
|
||||
return x == 239 && PyErr_Occurred();
|
||||
}
|
||||
|
||||
PyObject *VecU8_Box(VecU8);
|
||||
VecU8 VecU8_Append(VecU8, uint8_t x);
|
||||
VecU8 VecU8_Remove(VecU8, uint8_t x);
|
||||
VecU8PopResult VecU8_Pop(VecU8 v, Py_ssize_t index);
|
||||
|
||||
// vec[float] operations
|
||||
|
||||
static inline int VecFloat_Check(PyObject *o) {
|
||||
return o->ob_type == &VecFloatType;
|
||||
}
|
||||
|
||||
static inline PyObject *VecFloat_BoxItem(double x) {
|
||||
return PyFloat_FromDouble(x);
|
||||
}
|
||||
|
||||
static inline double VecFloat_UnboxItem(PyObject *o) {
|
||||
return PyFloat_AsDouble(o);
|
||||
}
|
||||
|
||||
static inline int VecFloat_IsUnboxError(double x) {
|
||||
return x == -1.0 && PyErr_Occurred();
|
||||
}
|
||||
|
||||
PyObject *VecFloat_Box(VecFloat);
|
||||
VecFloat VecFloat_Append(VecFloat, double x);
|
||||
VecFloat VecFloat_Remove(VecFloat, double x);
|
||||
VecFloatPopResult VecFloat_Pop(VecFloat v, Py_ssize_t index);
|
||||
|
||||
// vec[bool] operations
|
||||
|
||||
static inline int VecBool_Check(PyObject *o) {
|
||||
return o->ob_type == &VecBoolType;
|
||||
}
|
||||
|
||||
static inline PyObject *VecBool_BoxItem(char x) {
|
||||
if (x == 1) {
|
||||
Py_INCREF(Py_True);
|
||||
return Py_True;
|
||||
} else {
|
||||
Py_INCREF(Py_False);
|
||||
return Py_False;
|
||||
}
|
||||
}
|
||||
|
||||
static inline char VecBool_UnboxItem(PyObject *o) {
|
||||
if (o == Py_False) {
|
||||
return 0;
|
||||
} else if (o == Py_True) {
|
||||
return 1;
|
||||
} else {
|
||||
PyErr_SetString(PyExc_TypeError, "bool value expected");
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
static inline int VecBool_IsUnboxError(char x) {
|
||||
return x == 2;
|
||||
}
|
||||
|
||||
PyObject *VecBool_Box(VecBool);
|
||||
VecBool VecBool_Append(VecBool, char x);
|
||||
VecBool VecBool_Remove(VecBool, char x);
|
||||
VecBoolPopResult VecBool_Pop(VecBool v, Py_ssize_t index);
|
||||
|
||||
// vec[t] operations
|
||||
|
||||
static inline int VecT_Check(PyObject *o) {
|
||||
return o->ob_type == &VecTType;
|
||||
}
|
||||
|
||||
static inline int VecT_ItemCheck(VecT v, PyObject *item, size_t item_type) {
|
||||
if (PyObject_TypeCheck(item, VEC_ITEM_TYPE(item_type))) {
|
||||
return 1;
|
||||
} else if ((item_type & 1) && item == Py_None) {
|
||||
return 1;
|
||||
} else {
|
||||
// TODO: better error message
|
||||
PyErr_SetString(PyExc_TypeError, "invalid item type");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
VecT VecT_New(Py_ssize_t size, Py_ssize_t cap, size_t item_type);
|
||||
PyObject *VecT_FromIterable(size_t item_type, PyObject *iterable);
|
||||
PyObject *VecT_Box(VecT vec, size_t item_type);
|
||||
VecT VecT_Append(VecT vec, PyObject *x, size_t item_type);
|
||||
VecT VecT_Remove(VecT vec, PyObject *x);
|
||||
VecTPopResult VecT_Pop(VecT v, Py_ssize_t index);
|
||||
|
||||
// Nested vec operations
|
||||
|
||||
static inline int VecNested_Check(PyObject *o) {
|
||||
return o->ob_type == &VecNestedType;
|
||||
}
|
||||
|
||||
VecNested VecNested_New(Py_ssize_t size, Py_ssize_t cap, size_t item_type, size_t depth);
|
||||
PyObject *VecNested_FromIterable(size_t item_type, size_t depth, PyObject *iterable);
|
||||
PyObject *VecNested_Box(VecNested);
|
||||
VecNested VecNested_Append(VecNested vec, VecNestedBufItem x);
|
||||
VecNested VecNested_Remove(VecNested vec, VecNestedBufItem x);
|
||||
VecNestedPopResult VecNested_Pop(VecNested v, Py_ssize_t index);
|
||||
|
||||
// Return 0 on success, -1 on error. Store unboxed item in *unboxed if successful.
|
||||
// Return a *borrowed* reference.
|
||||
static inline int VecNested_UnboxItem(VecNested v, PyObject *item, VecNestedBufItem *unboxed) {
|
||||
size_t depth = v.buf->depth;
|
||||
if (depth == 1) {
|
||||
if (item->ob_type == &VecTType) {
|
||||
VecNestedObject *o = (VecNestedObject *)item;
|
||||
if (o->vec.buf->item_type == v.buf->item_type) {
|
||||
unboxed->len = o->vec.len;
|
||||
unboxed->buf = (PyObject *)o->vec.buf;
|
||||
return 0;
|
||||
}
|
||||
} else if (item->ob_type == &VecI64Type && v.buf->item_type == VEC_ITEM_TYPE_I64) {
|
||||
VecI64Object *o = (VecI64Object *)item;
|
||||
unboxed->len = o->vec.len;
|
||||
unboxed->buf = (PyObject *)o->vec.buf;
|
||||
return 0;
|
||||
} else if (item->ob_type == &VecU8Type && v.buf->item_type == VEC_ITEM_TYPE_U8) {
|
||||
VecU8Object *o = (VecU8Object *)item;
|
||||
unboxed->len = o->vec.len;
|
||||
unboxed->buf = (PyObject *)o->vec.buf;
|
||||
return 0;
|
||||
} else if (item->ob_type == &VecFloatType && v.buf->item_type == VEC_ITEM_TYPE_FLOAT) {
|
||||
VecFloatObject *o = (VecFloatObject *)item;
|
||||
unboxed->len = o->vec.len;
|
||||
unboxed->buf = (PyObject *)o->vec.buf;
|
||||
return 0;
|
||||
} else if (item->ob_type == &VecI32Type && v.buf->item_type == VEC_ITEM_TYPE_I32) {
|
||||
VecI32Object *o = (VecI32Object *)item;
|
||||
unboxed->len = o->vec.len;
|
||||
unboxed->buf = (PyObject *)o->vec.buf;
|
||||
return 0;
|
||||
} else if (item->ob_type == &VecI16Type && v.buf->item_type == VEC_ITEM_TYPE_I16) {
|
||||
VecI16Object *o = (VecI16Object *)item;
|
||||
unboxed->len = o->vec.len;
|
||||
unboxed->buf = (PyObject *)o->vec.buf;
|
||||
return 0;
|
||||
} else if (item->ob_type == &VecBoolType && v.buf->item_type == VEC_ITEM_TYPE_BOOL) {
|
||||
VecBoolObject *o = (VecBoolObject *)item;
|
||||
unboxed->len = o->vec.len;
|
||||
unboxed->buf = (PyObject *)o->vec.buf;
|
||||
return 0;
|
||||
}
|
||||
} else if (item->ob_type == &VecNestedType) {
|
||||
VecNestedObject *o = (VecNestedObject *)item;
|
||||
if (o->vec.buf->depth == v.buf->depth - 1
|
||||
&& o->vec.buf->item_type == v.buf->item_type) {
|
||||
unboxed->len = o->vec.len;
|
||||
unboxed->buf = (PyObject *)o->vec.buf;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
// TODO: better error message
|
||||
PyErr_SetString(PyExc_TypeError, "invalid item type");
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline PyObject *VecNested_BoxItem(VecNested v, VecNestedBufItem item) {
|
||||
if (item.len < 0)
|
||||
Py_RETURN_NONE;
|
||||
Py_XINCREF(item.buf);
|
||||
if (v.buf->depth > 1) {
|
||||
// Item is a nested vec
|
||||
VecNested v = { .len = item.len, .buf = (VecNestedBufObject *)item.buf };
|
||||
return VecNested_Box(v);
|
||||
} else {
|
||||
// Item is a non-nested vec
|
||||
size_t item_type = v.buf->item_type;
|
||||
if (item_type == VEC_ITEM_TYPE_I64) {
|
||||
VecI64 v = { .len = item.len, .buf = (VecI64BufObject *)item.buf };
|
||||
return VecI64_Box(v);
|
||||
} else if (item_type == VEC_ITEM_TYPE_U8) {
|
||||
VecU8 v = { .len = item.len, .buf = (VecU8BufObject *)item.buf };
|
||||
return VecU8_Box(v);
|
||||
} else if (item_type == VEC_ITEM_TYPE_FLOAT) {
|
||||
VecFloat v = { .len = item.len, .buf = (VecFloatBufObject *)item.buf };
|
||||
return VecFloat_Box(v);
|
||||
} else if (item_type == VEC_ITEM_TYPE_I32) {
|
||||
VecI32 v = { .len = item.len, .buf = (VecI32BufObject *)item.buf };
|
||||
return VecI32_Box(v);
|
||||
} else if (item_type == VEC_ITEM_TYPE_I16) {
|
||||
VecI16 v = { .len = item.len, .buf = (VecI16BufObject *)item.buf };
|
||||
return VecI16_Box(v);
|
||||
} else if (item_type == VEC_ITEM_TYPE_BOOL) {
|
||||
VecBool v = { .len = item.len, .buf = (VecBoolBufObject *)item.buf };
|
||||
return VecBool_Box(v);
|
||||
} else {
|
||||
// Generic vec[t]
|
||||
VecT v = { .len = item.len, .buf = (VecTBufObject *)item.buf };
|
||||
return VecT_Box(v, item_type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Misc helpers
|
||||
|
||||
PyObject *Vec_TypeToStr(size_t item_type, size_t depth);
|
||||
PyObject *Vec_GenericRepr(PyObject *vec, size_t item_type, size_t depth, int verbose);
|
||||
PyObject *Vec_GenericRichcompare(Py_ssize_t *len, PyObject **items,
|
||||
Py_ssize_t *other_len, PyObject **other_items,
|
||||
int op);
|
||||
int Vec_GenericRemove(Py_ssize_t *len, PyObject **items, PyObject *item);
|
||||
PyObject *Vec_GenericPopWrapper(Py_ssize_t *len, PyObject **items, PyObject *args);
|
||||
PyObject *Vec_GenericPop(Py_ssize_t *len, PyObject **items, Py_ssize_t index);
|
||||
|
||||
// Global API pointers initialized by import_librt_vecs()
|
||||
static VecCapsule *VecApi;
|
||||
static VecI64API VecI64Api;
|
||||
static VecI32API VecI32Api;
|
||||
static VecI16API VecI16Api;
|
||||
static VecU8API VecU8Api;
|
||||
static VecFloatAPI VecFloatApi;
|
||||
static VecBoolAPI VecBoolApi;
|
||||
static VecTAPI VecTApi;
|
||||
static VecNestedAPI VecNestedApi;
|
||||
|
||||
static int
|
||||
import_librt_vecs(void)
|
||||
{
|
||||
PyObject *mod = PyImport_ImportModule("librt.vecs");
|
||||
if (mod == NULL)
|
||||
return -1;
|
||||
Py_DECREF(mod); // we import just for the side effect of making the below work.
|
||||
VecApi = PyCapsule_Import("librt.vecs._C_API", 0);
|
||||
if (!VecApi)
|
||||
return -1;
|
||||
VecI64Api = *VecApi->i64;
|
||||
VecI32Api = *VecApi->i32;
|
||||
VecI16Api = *VecApi->i16;
|
||||
VecU8Api = *VecApi->u8;
|
||||
VecFloatApi = *VecApi->float_;
|
||||
VecBoolApi = *VecApi->bool_;
|
||||
VecTApi = *VecApi->t;
|
||||
VecNestedApi = *VecApi->nested;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif // MYPYC_EXPERIMENTAL
|
||||
|
||||
#endif // VEC_H_INCL
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
#ifdef MYPYC_EXPERIMENTAL
|
||||
#define VEC VecBool
|
||||
#define VEC_TYPE VecBoolType
|
||||
#define VEC_OBJECT VecBoolObject
|
||||
#define BUF_OBJECT VecBoolBufObject
|
||||
#define BUF_TYPE VecBoolBufType
|
||||
#define NAME(suffix) VecBool##suffix
|
||||
#define FUNC(suffix) VecBool_##suffix
|
||||
#define ITEM_TYPE_STR "bool"
|
||||
#define ITEM_TYPE_MAGIC VEC_ITEM_TYPE_BOOL
|
||||
#define ITEM_C_TYPE char
|
||||
#define FEATURES Vec_BoolAPI
|
||||
|
||||
#define BOX_ITEM VecBool_BoxItem
|
||||
#define UNBOX_ITEM VecBool_UnboxItem
|
||||
#define IS_UNBOX_ERROR VecBool_IsUnboxError
|
||||
|
||||
#include "vec_template.c"
|
||||
|
||||
#endif // MYPYC_EXPERIMENTAL
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
#ifdef MYPYC_EXPERIMENTAL
|
||||
#define VEC VecFloat
|
||||
#define VEC_TYPE VecFloatType
|
||||
#define VEC_OBJECT VecFloatObject
|
||||
#define BUF_OBJECT VecFloatBufObject
|
||||
#define BUF_TYPE VecFloatBufType
|
||||
#define NAME(suffix) VecFloat##suffix
|
||||
#define FUNC(suffix) VecFloat_##suffix
|
||||
#define ITEM_TYPE_STR "float"
|
||||
#define ITEM_TYPE_MAGIC VEC_ITEM_TYPE_FLOAT
|
||||
#define ITEM_C_TYPE double
|
||||
#define FEATURES Vec_FloatAPI
|
||||
|
||||
#define BOX_ITEM VecFloat_BoxItem
|
||||
#define UNBOX_ITEM VecFloat_UnboxItem
|
||||
#define IS_UNBOX_ERROR VecFloat_IsUnboxError
|
||||
|
||||
#include "vec_template.c"
|
||||
|
||||
#endif // MYPYC_EXPERIMENTAL
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
#ifdef MYPYC_EXPERIMENTAL
|
||||
#define VEC VecI16
|
||||
#define VEC_TYPE VecI16Type
|
||||
#define VEC_OBJECT VecI16Object
|
||||
#define BUF_OBJECT VecI16BufObject
|
||||
#define BUF_TYPE VecI16BufType
|
||||
#define NAME(suffix) VecI16##suffix
|
||||
#define FUNC(suffix) VecI16_##suffix
|
||||
#define ITEM_TYPE_STR "i16"
|
||||
#define ITEM_TYPE_MAGIC VEC_ITEM_TYPE_I16
|
||||
#define ITEM_C_TYPE int16_t
|
||||
#define FEATURES Vec_I16API
|
||||
|
||||
#define BOX_ITEM VecI16_BoxItem
|
||||
#define UNBOX_ITEM VecI16_UnboxItem
|
||||
#define IS_UNBOX_ERROR VecI16_IsUnboxError
|
||||
|
||||
#include "vec_template.c"
|
||||
|
||||
#endif // MYPYC_EXPERIMENTAL
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
#ifdef MYPYC_EXPERIMENTAL
|
||||
#define VEC VecI32
|
||||
#define VEC_TYPE VecI32Type
|
||||
#define VEC_OBJECT VecI32Object
|
||||
#define BUF_OBJECT VecI32BufObject
|
||||
#define BUF_TYPE VecI32BufType
|
||||
#define NAME(suffix) VecI32##suffix
|
||||
#define FUNC(suffix) VecI32_##suffix
|
||||
#define ITEM_TYPE_STR "i32"
|
||||
#define ITEM_TYPE_MAGIC VEC_ITEM_TYPE_I32
|
||||
#define ITEM_C_TYPE int32_t
|
||||
#define FEATURES Vec_I32API
|
||||
|
||||
#define BOX_ITEM VecI32_BoxItem
|
||||
#define UNBOX_ITEM VecI32_UnboxItem
|
||||
#define IS_UNBOX_ERROR VecI32_IsUnboxError
|
||||
|
||||
#include "vec_template.c"
|
||||
|
||||
#endif // MYPYC_EXPERIMENTAL
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
#ifdef MYPYC_EXPERIMENTAL
|
||||
#define VEC VecI64
|
||||
#define VEC_TYPE VecI64Type
|
||||
#define VEC_OBJECT VecI64Object
|
||||
#define BUF_OBJECT VecI64BufObject
|
||||
#define BUF_TYPE VecI64BufType
|
||||
#define NAME(suffix) VecI64##suffix
|
||||
#define FUNC(suffix) VecI64_##suffix
|
||||
#define ITEM_TYPE_STR "i64"
|
||||
#define ITEM_TYPE_MAGIC VEC_ITEM_TYPE_I64
|
||||
#define ITEM_C_TYPE int64_t
|
||||
#define FEATURES Vec_I64API
|
||||
|
||||
#define BOX_ITEM VecI64_BoxItem
|
||||
#define UNBOX_ITEM VecI64_UnboxItem
|
||||
#define IS_UNBOX_ERROR VecI64_IsUnboxError
|
||||
|
||||
#include "vec_template.c"
|
||||
|
||||
#endif // MYPYC_EXPERIMENTAL
|
||||
506
venv/lib/python3.11/site-packages/mypyc/lib-rt/vecs/vec_nested.c
Normal file
506
venv/lib/python3.11/site-packages/mypyc/lib-rt/vecs/vec_nested.c
Normal file
|
|
@ -0,0 +1,506 @@
|
|||
#ifdef MYPYC_EXPERIMENTAL
|
||||
// Implementation of nested vec[t], when t is a vec type.
|
||||
//
|
||||
// Examples of types supported:
|
||||
// - vec[vec[i64]]
|
||||
// - vec[vec[vec[str]]]
|
||||
// - vec[vec[str | None]]
|
||||
|
||||
#define PY_SSIZE_T_CLEAN
|
||||
#include <Python.h>
|
||||
#include "librt_vecs.h"
|
||||
#include "vecs_internal.h"
|
||||
|
||||
static inline VecNested vec_error() {
|
||||
VecNested v = { .len = -1 };
|
||||
return v;
|
||||
}
|
||||
|
||||
static inline PyObject *box_vec_item_by_index(VecNested v, Py_ssize_t index) {
|
||||
return VecNested_BoxItem(v, v.buf->items[index]);
|
||||
}
|
||||
|
||||
// Alloc a partially initialized vec. Caller *must* initialize len and buf->items of the
|
||||
// return value.
|
||||
static VecNested vec_alloc(Py_ssize_t size, size_t item_type, size_t depth) {
|
||||
VecNestedBufObject *buf = PyObject_GC_NewVar(VecNestedBufObject, &VecNestedBufType, size);
|
||||
if (buf == NULL)
|
||||
return vec_error();
|
||||
buf->item_type = item_type;
|
||||
buf->depth = depth;
|
||||
if (!Vec_IsMagicItemType(item_type))
|
||||
Py_INCREF(VEC_BUF_ITEM_TYPE(buf));
|
||||
VecNested res = { .buf = buf };
|
||||
PyObject_GC_Track(buf);
|
||||
return res;
|
||||
}
|
||||
|
||||
// Box a nested vec value, stealing 'vec'. On error, decref 'vec'.
|
||||
PyObject *VecNested_Box(VecNested vec) {
|
||||
VecNestedObject *obj = PyObject_GC_New(VecNestedObject, &VecNestedType);
|
||||
if (obj == NULL) {
|
||||
VEC_DECREF(vec);
|
||||
return NULL;
|
||||
}
|
||||
obj->vec = vec;
|
||||
PyObject_GC_Track(obj);
|
||||
return (PyObject *)obj;
|
||||
}
|
||||
|
||||
VecNested VecNested_Unbox(PyObject *obj, size_t item_type, size_t depth) {
|
||||
if (obj->ob_type == &VecNestedType) {
|
||||
VecNested result = ((VecNestedObject *)obj)->vec;
|
||||
if (result.buf->item_type == item_type && result.buf->depth == depth) {
|
||||
VEC_INCREF(result); // TODO: Should we borrow instead?
|
||||
return result;
|
||||
}
|
||||
}
|
||||
// TODO: Better error message, with name of type
|
||||
PyErr_SetString(PyExc_TypeError, "vec[t] expected");
|
||||
return vec_error();
|
||||
}
|
||||
|
||||
VecNested VecNested_ConvertFromNested(VecNestedBufItem item) {
|
||||
return (VecNested) { item.len, (VecNestedBufObject *)item.buf };
|
||||
}
|
||||
|
||||
VecNested VecNested_New(Py_ssize_t size, Py_ssize_t cap, size_t item_type, size_t depth) {
|
||||
if (cap < size)
|
||||
cap = size;
|
||||
VecNested vec = vec_alloc(cap, item_type, depth);
|
||||
if (VEC_IS_ERROR(vec))
|
||||
return vec;
|
||||
for (Py_ssize_t i = 0; i < cap; i++) {
|
||||
vec.buf->items[i].len = -1;
|
||||
vec.buf->items[i].buf = NULL;
|
||||
}
|
||||
vec.len = size;
|
||||
return vec;
|
||||
}
|
||||
|
||||
static PyObject *vec_repr(PyObject *self) {
|
||||
VecNested v = ((VecNestedObject *)self)->vec;
|
||||
return Vec_GenericRepr(self, v.buf->item_type, v.buf->depth, 1);
|
||||
}
|
||||
|
||||
static PyObject *vec_get_item(PyObject *o, Py_ssize_t i) {
|
||||
VecNested v = ((VecNestedObject *)o)->vec;
|
||||
if ((size_t)i < (size_t)v.len) {
|
||||
return box_vec_item_by_index(v, i);
|
||||
} else if ((size_t)i + (size_t)v.len < (size_t)v.len) {
|
||||
return box_vec_item_by_index(v, i + v.len);
|
||||
} else {
|
||||
PyErr_SetString(PyExc_IndexError, "index out of range");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
VecNested VecNested_Slice(VecNested vec, int64_t start, int64_t end) {
|
||||
if (start < 0)
|
||||
start += vec.len;
|
||||
if (end < 0)
|
||||
end += vec.len;
|
||||
if (start < 0)
|
||||
start = 0;
|
||||
if (start >= vec.len)
|
||||
start = vec.len;
|
||||
if (end < start)
|
||||
end = start;
|
||||
if (end > vec.len)
|
||||
end = vec.len;
|
||||
int64_t slicelength = end - start;
|
||||
VecNested res = vec_alloc(slicelength, vec.buf->item_type, vec.buf->depth);
|
||||
if (VEC_IS_ERROR(res))
|
||||
return res;
|
||||
res.len = slicelength;
|
||||
for (Py_ssize_t i = 0; i < slicelength; i++) {
|
||||
VecNestedBufItem item = vec.buf->items[start + i];
|
||||
Py_XINCREF(item.buf);
|
||||
res.buf->items[i] = item;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static PyObject *vec_subscript(PyObject *self, PyObject *item) {
|
||||
VecNested vec = ((VecNestedObject *)self)->vec;
|
||||
if (PyIndex_Check(item)) {
|
||||
Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
|
||||
if (i == -1 && PyErr_Occurred())
|
||||
return NULL;
|
||||
if ((size_t)i < (size_t)vec.len) {
|
||||
return box_vec_item_by_index(vec, i);
|
||||
} else if ((size_t)i + (size_t)vec.len < (size_t)vec.len) {
|
||||
return box_vec_item_by_index(vec, i + vec.len);
|
||||
} else {
|
||||
PyErr_SetString(PyExc_IndexError, "index out of range");
|
||||
return NULL;
|
||||
}
|
||||
} else if (PySlice_Check(item)) {
|
||||
Py_ssize_t start, stop, step;
|
||||
if (PySlice_Unpack(item, &start, &stop, &step) < 0)
|
||||
return NULL;
|
||||
Py_ssize_t slicelength = PySlice_AdjustIndices(vec.len, &start, &stop, step);
|
||||
VecNested res = vec_alloc(slicelength, vec.buf->item_type, vec.buf->depth);
|
||||
if (VEC_IS_ERROR(res))
|
||||
return NULL;
|
||||
res.len = slicelength;
|
||||
Py_ssize_t j = start;
|
||||
for (Py_ssize_t i = 0; i < slicelength; i++) {
|
||||
VecNestedBufItem item = vec.buf->items[j];
|
||||
Py_INCREF(item.buf);
|
||||
res.buf->items[i] = item;
|
||||
j += step;
|
||||
}
|
||||
return VecNested_Box(res);
|
||||
} else {
|
||||
PyErr_Format(PyExc_TypeError, "vec indices must be integers or slices, not %.100s",
|
||||
item->ob_type->tp_name);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int vec_ass_item(PyObject *self, Py_ssize_t i, PyObject *o) {
|
||||
VecNested v = ((VecNestedObject *)self)->vec;
|
||||
if ((size_t)i + (size_t)v.len < (size_t)v.len) {
|
||||
i += v.len;
|
||||
}
|
||||
if ((size_t)i < (size_t)v.len) {
|
||||
VecNestedBufItem item;
|
||||
if (VecNested_UnboxItem(v, o, &item) < 0)
|
||||
return -1;
|
||||
VEC_INCREF(item);
|
||||
VEC_DECREF(v.buf->items[i]);
|
||||
v.buf->items[i] = item;
|
||||
return 0;
|
||||
} else {
|
||||
PyErr_SetString(PyExc_IndexError, "index out of range");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static PyObject *compare_vec_eq(VecNested x, VecNested y, int op) {
|
||||
int cmp = 1;
|
||||
PyObject *res;
|
||||
if (x.len != y.len
|
||||
|| x.buf->item_type != y.buf->item_type
|
||||
|| x.buf->depth != y.buf->depth) {
|
||||
cmp = 0;
|
||||
} else {
|
||||
for (Py_ssize_t i = 0; i < x.len; i++) {
|
||||
PyObject *x_item = box_vec_item_by_index(x, i);
|
||||
PyObject *y_item = box_vec_item_by_index(y, i);
|
||||
int itemcmp = PyObject_RichCompareBool(x_item, y_item, Py_EQ);
|
||||
Py_DECREF(x_item);
|
||||
Py_DECREF(y_item);
|
||||
if (itemcmp < 0)
|
||||
return NULL;
|
||||
if (!itemcmp) {
|
||||
cmp = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (op == Py_NE)
|
||||
cmp = cmp ^ 1;
|
||||
res = cmp ? Py_True : Py_False;
|
||||
Py_INCREF(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
PyObject *vec_richcompare(PyObject *self, PyObject *other, int op) {
|
||||
PyObject *res;
|
||||
if (op == Py_EQ || op == Py_NE) {
|
||||
if (other->ob_type != &VecNestedType) {
|
||||
res = op == Py_EQ ? Py_False : Py_True;
|
||||
} else {
|
||||
return compare_vec_eq(((VecNestedObject *)self)->vec,
|
||||
((VecNestedObject *)other)->vec, op);
|
||||
}
|
||||
} else
|
||||
res = Py_NotImplemented;
|
||||
Py_INCREF(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
// Append item to 'vec', stealing 'vec'. Return 'vec' with item appended.
|
||||
VecNested VecNested_Append(VecNested vec, VecNestedBufItem x) {
|
||||
Py_ssize_t cap = VEC_CAP(vec);
|
||||
VEC_INCREF(x);
|
||||
if (vec.len < cap) {
|
||||
// Slot may have duplicate ref from prior remove/pop
|
||||
Py_XDECREF(vec.buf->items[vec.len].buf);
|
||||
vec.buf->items[vec.len] = x;
|
||||
vec.len++;
|
||||
return vec;
|
||||
} else {
|
||||
Py_ssize_t new_size = 2 * cap + 1;
|
||||
// TODO: Avoid initializing to zero here
|
||||
VecNested new = vec_alloc(new_size, vec.buf->item_type, vec.buf->depth);
|
||||
if (VEC_IS_ERROR(new)) {
|
||||
VEC_DECREF(x);
|
||||
// The input vec is being consumed/stolen by this function, so on error
|
||||
// we must decref it to avoid leaking the buffer.
|
||||
VEC_DECREF(vec);
|
||||
return new;
|
||||
}
|
||||
// Copy items to new vec.
|
||||
memcpy(new.buf->items, vec.buf->items, sizeof(VecNestedBufItem) * vec.len);
|
||||
// TODO: How to safely represent deleted items?
|
||||
memset(new.buf->items + vec.len, 0, sizeof(VecNestedBufItem) * (new_size - vec.len));
|
||||
// Clear the items in the old vec. We avoid reference count manipulation.
|
||||
memset(vec.buf->items, 0, sizeof(VecNestedBufItem) * vec.len);
|
||||
new.buf->items[vec.len] = x;
|
||||
new.len = vec.len + 1;
|
||||
VEC_DECREF(vec);
|
||||
return new;
|
||||
}
|
||||
}
|
||||
|
||||
// Remove item from 'vec', stealing 'vec'. Return 'vec' with item removed.
|
||||
VecNested VecNested_Remove(VecNested self, VecNestedBufItem arg) {
|
||||
VecNestedBufItem *items = self.buf->items;
|
||||
|
||||
PyObject *boxed_arg = VecNested_BoxItem(self, arg);
|
||||
if (boxed_arg == NULL) {
|
||||
// The input self is being consumed/stolen by this function, so on error
|
||||
// we must decref it to avoid leaking the buffer.
|
||||
VEC_DECREF(self);
|
||||
return vec_error();
|
||||
}
|
||||
|
||||
for (Py_ssize_t i = 0; i < self.len; i++) {
|
||||
int match = 0;
|
||||
if (items[i].len == arg.len && items[i].buf == arg.buf)
|
||||
match = 1;
|
||||
else {
|
||||
PyObject *item = box_vec_item_by_index(self, i);
|
||||
if (item == NULL) {
|
||||
Py_DECREF(boxed_arg);
|
||||
// The input self is being consumed/stolen by this function, so on error
|
||||
// we must decref it to avoid leaking the buffer.
|
||||
VEC_DECREF(self);
|
||||
return vec_error();
|
||||
}
|
||||
int itemcmp = PyObject_RichCompareBool(item, boxed_arg, Py_EQ);
|
||||
Py_DECREF(item);
|
||||
if (itemcmp < 0) {
|
||||
Py_DECREF(boxed_arg);
|
||||
// The input self is being consumed/stolen by this function, so on error
|
||||
// we must decref it to avoid leaking the buffer.
|
||||
VEC_DECREF(self);
|
||||
return vec_error();
|
||||
}
|
||||
match = itemcmp;
|
||||
}
|
||||
if (match) {
|
||||
if (i < self.len - 1) {
|
||||
Py_CLEAR(items[i].buf);
|
||||
for (; i < self.len - 1; i++) {
|
||||
items[i] = items[i + 1];
|
||||
}
|
||||
Py_XINCREF(items[self.len - 1].buf);
|
||||
}
|
||||
self.len--;
|
||||
Py_DECREF(boxed_arg);
|
||||
// Return the stolen reference without INCREF
|
||||
return self;
|
||||
}
|
||||
}
|
||||
Py_DECREF(boxed_arg);
|
||||
PyErr_SetString(PyExc_ValueError, "vec.remove(x): x not in vec");
|
||||
// The input self is being consumed/stolen by this function, so on error
|
||||
// we must decref it to avoid leaking the buffer.
|
||||
VEC_DECREF(self);
|
||||
return vec_error();
|
||||
}
|
||||
|
||||
// Pop item from 'vec', stealing 'vec'. Return struct with modified 'vec' and the popped item.
|
||||
VecNestedPopResult VecNested_Pop(VecNested v, Py_ssize_t index) {
|
||||
VecNestedPopResult result;
|
||||
|
||||
if (index < 0)
|
||||
index += v.len;
|
||||
|
||||
if (index < 0 || index >= v.len) {
|
||||
PyErr_SetString(PyExc_IndexError, "index out of range");
|
||||
// The input v is being consumed/stolen by this function, so on error
|
||||
// we must decref it to avoid leaking the buffer.
|
||||
VEC_DECREF(v);
|
||||
result.f0 = vec_error();
|
||||
result.f1.len = 0;
|
||||
result.f1.buf = NULL;
|
||||
return result;
|
||||
}
|
||||
|
||||
VecNestedBufItem *items = v.buf->items;
|
||||
result.f1 = items[index];
|
||||
for (Py_ssize_t i = index; i < v.len - 1; i++)
|
||||
items[i] = items[i + 1];
|
||||
if (v.len > 0)
|
||||
Py_XINCREF(items[v.len - 1].buf);
|
||||
v.len--;
|
||||
// Return the stolen reference without INCREF
|
||||
result.f0 = v;
|
||||
return result;
|
||||
}
|
||||
|
||||
static int
|
||||
VecNested_traverse(VecNestedObject *self, visitproc visit, void *arg)
|
||||
{
|
||||
Py_VISIT(self->vec.buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
VecNested_clear(VecNestedObject *self)
|
||||
{
|
||||
Py_CLEAR(self->vec.buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
VecNested_dealloc(VecNestedObject *self)
|
||||
{
|
||||
PyObject_GC_UnTrack(self);
|
||||
Py_TRASHCAN_BEGIN(self, VecNested_dealloc)
|
||||
Py_CLEAR(self->vec.buf);
|
||||
Py_TYPE(self)->tp_free((PyObject *)self);
|
||||
Py_TRASHCAN_END
|
||||
}
|
||||
|
||||
static int
|
||||
VecNestedBuf_traverse(VecNestedBufObject *self, visitproc visit, void *arg)
|
||||
{
|
||||
if (!Vec_IsMagicItemType(self->item_type))
|
||||
Py_VISIT(VEC_BUF_ITEM_TYPE(self));
|
||||
for (Py_ssize_t i = 0; i < VEC_BUF_SIZE(self); i++) {
|
||||
Py_VISIT(self->items[i].buf);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
VecNestedBuf_clear(VecNestedBufObject *self)
|
||||
{
|
||||
if (self->item_type && !Vec_IsMagicItemType(self->item_type)) {
|
||||
Py_DECREF(VEC_BUF_ITEM_TYPE(self));
|
||||
self->item_type = 0;
|
||||
}
|
||||
for (Py_ssize_t i = 0; i < VEC_BUF_SIZE(self); i++) {
|
||||
Py_CLEAR(self->items[i].buf);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
VecNestedBuf_dealloc(VecNestedBufObject *self)
|
||||
{
|
||||
PyObject_GC_UnTrack(self);
|
||||
Py_TRASHCAN_BEGIN(self, VecNestedBuf_dealloc)
|
||||
VecNestedBuf_clear(self);
|
||||
Py_TYPE(self)->tp_free((PyObject *)self);
|
||||
Py_TRASHCAN_END
|
||||
}
|
||||
|
||||
static Py_ssize_t vec_ext_length(PyObject *o) {
|
||||
return ((VecNestedObject *)o)->vec.len;
|
||||
}
|
||||
|
||||
static PyMappingMethods VecNestedMapping = {
|
||||
.mp_length = vec_ext_length,
|
||||
.mp_subscript = vec_subscript,
|
||||
};
|
||||
|
||||
static PySequenceMethods VecNestedSequence = {
|
||||
.sq_item = vec_get_item,
|
||||
.sq_ass_item = vec_ass_item,
|
||||
};
|
||||
|
||||
static PyMethodDef vec_methods[] = {
|
||||
{NULL, NULL, 0, NULL}, /* Sentinel */
|
||||
};
|
||||
|
||||
PyTypeObject VecNestedBufType = {
|
||||
PyVarObject_HEAD_INIT(NULL, 0)
|
||||
.tp_name = "vecbuf",
|
||||
.tp_doc = "Internal data buffer used by vec objects",
|
||||
.tp_basicsize = sizeof(VecNestedBufObject) - sizeof(VecNestedBufItem),
|
||||
.tp_itemsize = sizeof(VecNestedBufItem),
|
||||
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
|
||||
.tp_traverse = (traverseproc)VecNestedBuf_traverse,
|
||||
//.tp_new = vecbuf_i64_new, //??
|
||||
.tp_free = PyObject_GC_Del,
|
||||
.tp_clear = (inquiry)VecNestedBuf_clear,
|
||||
.tp_dealloc = (destructor)VecNestedBuf_dealloc,
|
||||
};
|
||||
|
||||
PyTypeObject VecNestedType = {
|
||||
PyVarObject_HEAD_INIT(NULL, 0)
|
||||
.tp_name = "vec",
|
||||
.tp_doc = "Mutable sequence-like container optimized for compilation with mypyc",
|
||||
.tp_basicsize = sizeof(VecNestedObject),
|
||||
.tp_itemsize = 0,
|
||||
.tp_base = &VecType, // Inherit from base vec type for isinstance() support
|
||||
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
|
||||
.tp_traverse = (traverseproc)VecNested_traverse,
|
||||
.tp_clear = (inquiry)VecNested_clear,
|
||||
.tp_dealloc = (destructor)VecNested_dealloc,
|
||||
//.tp_free = PyObject_GC_Del,
|
||||
.tp_repr = (reprfunc)vec_repr,
|
||||
.tp_as_sequence = &VecNestedSequence,
|
||||
.tp_as_mapping = &VecNestedMapping,
|
||||
.tp_richcompare = vec_richcompare,
|
||||
.tp_methods = vec_methods,
|
||||
// TODO: free
|
||||
};
|
||||
|
||||
PyObject *VecNested_FromIterable(size_t item_type, size_t depth, PyObject *iterable) {
|
||||
VecNested v = vec_alloc(0, item_type, depth);
|
||||
if (VEC_IS_ERROR(v))
|
||||
return NULL;
|
||||
v.len = 0;
|
||||
|
||||
PyObject *iter = PyObject_GetIter(iterable);
|
||||
if (iter == NULL) {
|
||||
VEC_DECREF(v);
|
||||
return NULL;
|
||||
}
|
||||
PyObject *item;
|
||||
while ((item = PyIter_Next(iter)) != NULL) {
|
||||
VecNestedBufItem vecitem;
|
||||
if (VecNested_UnboxItem(v, item, &vecitem) < 0) {
|
||||
Py_DECREF(iter);
|
||||
VEC_DECREF(v);
|
||||
Py_DECREF(item);
|
||||
return NULL;
|
||||
}
|
||||
v = VecNested_Append(v, vecitem);
|
||||
Py_DECREF(item);
|
||||
if (VEC_IS_ERROR(v)) {
|
||||
Py_DECREF(iter);
|
||||
VEC_DECREF(v);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
Py_DECREF(iter);
|
||||
if (PyErr_Occurred()) {
|
||||
VEC_DECREF(v);
|
||||
return NULL;
|
||||
}
|
||||
return VecNested_Box(v);
|
||||
}
|
||||
|
||||
VecNestedAPI Vec_NestedAPI = {
|
||||
&VecNestedType,
|
||||
&VecNestedBufType,
|
||||
VecNested_New,
|
||||
VecNested_Box,
|
||||
VecNested_Unbox,
|
||||
VecNested_ConvertFromNested,
|
||||
VecNested_Append,
|
||||
VecNested_Pop,
|
||||
VecNested_Remove,
|
||||
VecNested_Slice,
|
||||
};
|
||||
|
||||
#endif // MYPYC_EXPERIMENTAL
|
||||
501
venv/lib/python3.11/site-packages/mypyc/lib-rt/vecs/vec_t.c
Normal file
501
venv/lib/python3.11/site-packages/mypyc/lib-rt/vecs/vec_t.c
Normal file
|
|
@ -0,0 +1,501 @@
|
|||
#ifdef MYPYC_EXPERIMENTAL
|
||||
// Implementation of generic vec[t], when t is a plain type object (possibly optional).
|
||||
//
|
||||
// Examples of types supported:
|
||||
//
|
||||
// - vec[str]
|
||||
// - vec[str | None]
|
||||
// - vec[object]
|
||||
// - vec[UserClass]
|
||||
|
||||
#define PY_SSIZE_T_CLEAN
|
||||
#include <Python.h>
|
||||
#include "librt_vecs.h"
|
||||
#include "vecs_internal.h"
|
||||
|
||||
static inline VecT vec_error() {
|
||||
VecT v = { .len = -1 };
|
||||
return v;
|
||||
}
|
||||
|
||||
static inline VecTBufObject *alloc_buf(Py_ssize_t size, size_t item_type) {
|
||||
VecTBufObject *buf = PyObject_GC_NewVar(VecTBufObject, &VecTBufType, size);
|
||||
if (buf == NULL)
|
||||
return NULL;
|
||||
buf->item_type = item_type;
|
||||
Py_INCREF(VEC_BUF_ITEM_TYPE(buf));
|
||||
PyObject_GC_Track(buf);
|
||||
return buf;
|
||||
}
|
||||
|
||||
// Alloc a partially initialized vec. Caller *must* immediately initialize len, and buf->items
|
||||
// if size > 0.
|
||||
static VecT vec_alloc(Py_ssize_t size, size_t item_type) {
|
||||
VecTBufObject *buf;
|
||||
|
||||
if (size == 0) {
|
||||
buf = NULL;
|
||||
} else {
|
||||
buf = alloc_buf(size, item_type);
|
||||
if (buf == NULL)
|
||||
return vec_error();
|
||||
}
|
||||
return (VecT) { .buf = buf };
|
||||
}
|
||||
|
||||
// Box a VecT value, stealing 'vec'. On failure, return NULL and decref 'vec'.
|
||||
PyObject *VecT_Box(VecT vec, size_t item_type) {
|
||||
// An unboxed empty vec may have a NULL buf, but a boxed vec must have it
|
||||
// allocated, since it contains the item type
|
||||
if (vec.buf == NULL) {
|
||||
vec.buf = alloc_buf(0, item_type);
|
||||
if (vec.buf == NULL)
|
||||
return NULL;
|
||||
}
|
||||
VecTObject *obj = PyObject_GC_New(VecTObject, &VecTType);
|
||||
if (obj == NULL) {
|
||||
// vec.buf is always defined, so no need for a NULL check
|
||||
Py_DECREF(vec.buf);
|
||||
return NULL;
|
||||
}
|
||||
obj->vec = vec;
|
||||
PyObject_GC_Track(obj);
|
||||
return (PyObject *)obj;
|
||||
}
|
||||
|
||||
VecT VecT_Unbox(PyObject *obj, size_t item_type) {
|
||||
if (obj->ob_type == &VecTType) {
|
||||
VecT result = ((VecTObject *)obj)->vec;
|
||||
if (result.buf->item_type == item_type) {
|
||||
VEC_INCREF(result); // TODO: Should we borrow instead?
|
||||
return result;
|
||||
}
|
||||
}
|
||||
// TODO: Better error message, with name of type
|
||||
PyErr_SetString(PyExc_TypeError, "vec[t] expected");
|
||||
return vec_error();
|
||||
}
|
||||
|
||||
VecT VecT_ConvertFromNested(VecNestedBufItem item) {
|
||||
return (VecT) { item.len, (VecTBufObject *)item.buf };
|
||||
}
|
||||
|
||||
VecT VecT_New(Py_ssize_t size, Py_ssize_t cap, size_t item_type) {
|
||||
if (cap < size)
|
||||
cap = size;
|
||||
VecT vec = vec_alloc(cap, item_type);
|
||||
if (VEC_IS_ERROR(vec))
|
||||
return vec;
|
||||
for (Py_ssize_t i = 0; i < cap; i++) {
|
||||
vec.buf->items[i] = NULL;
|
||||
}
|
||||
vec.len = size;
|
||||
return vec;
|
||||
}
|
||||
|
||||
static PyObject *vec_repr(PyObject *self) {
|
||||
VecTObject *v = (VecTObject *)self;
|
||||
return Vec_GenericRepr(self, v->vec.buf->item_type, 0, 1);
|
||||
}
|
||||
|
||||
static PyObject *vec_get_item(PyObject *o, Py_ssize_t i) {
|
||||
VecT v = ((VecTObject *)o)->vec;
|
||||
if ((size_t)i < (size_t)v.len) {
|
||||
PyObject *item = v.buf->items[i];
|
||||
Py_INCREF(item);
|
||||
return item;
|
||||
} else if ((size_t)i + (size_t)v.len < (size_t)v.len) {
|
||||
PyObject *item = v.buf->items[i + v.len];
|
||||
Py_INCREF(item);
|
||||
return item;
|
||||
} else {
|
||||
PyErr_SetString(PyExc_IndexError, "index out of range");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
VecT VecT_Slice(VecT vec, int64_t start, int64_t end) {
|
||||
if (start < 0)
|
||||
start += vec.len;
|
||||
if (end < 0)
|
||||
end += vec.len;
|
||||
if (start < 0)
|
||||
start = 0;
|
||||
if (start >= vec.len)
|
||||
start = vec.len;
|
||||
if (end < start)
|
||||
end = start;
|
||||
if (end > vec.len)
|
||||
end = vec.len;
|
||||
int64_t slicelength = end - start;
|
||||
if (slicelength == 0)
|
||||
return (VecT) { .len = 0, .buf = NULL };
|
||||
VecT res = vec_alloc(slicelength, vec.buf->item_type);
|
||||
if (VEC_IS_ERROR(res))
|
||||
return res;
|
||||
res.len = slicelength;
|
||||
for (Py_ssize_t i = 0; i < slicelength; i++) {
|
||||
PyObject *item = vec.buf->items[start + i];
|
||||
Py_INCREF(item);
|
||||
res.buf->items[i] = item;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static PyObject *vec_subscript(PyObject *self, PyObject *item) {
|
||||
VecT vec = ((VecTObject *)self)->vec;
|
||||
if (PyIndex_Check(item)) {
|
||||
Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
|
||||
if (i == -1 && PyErr_Occurred())
|
||||
return NULL;
|
||||
if ((size_t)i < (size_t)vec.len) {
|
||||
PyObject *result = vec.buf->items[i];
|
||||
Py_INCREF(result);
|
||||
return result;
|
||||
} else if ((size_t)i + (size_t)vec.len < (size_t)vec.len) {
|
||||
PyObject *result = vec.buf->items[i + vec.len];
|
||||
Py_INCREF(result);
|
||||
return result;
|
||||
} else {
|
||||
PyErr_SetString(PyExc_IndexError, "index out of range");
|
||||
return NULL;
|
||||
}
|
||||
} else if (PySlice_Check(item)) {
|
||||
Py_ssize_t start, stop, step;
|
||||
if (PySlice_Unpack(item, &start, &stop, &step) < 0)
|
||||
return NULL;
|
||||
Py_ssize_t slicelength = PySlice_AdjustIndices(vec.len, &start, &stop, step);
|
||||
VecT res = vec_alloc(slicelength, vec.buf->item_type);
|
||||
if (VEC_IS_ERROR(res))
|
||||
return NULL;
|
||||
res.len = slicelength;
|
||||
Py_ssize_t j = start;
|
||||
for (Py_ssize_t i = 0; i < slicelength; i++) {
|
||||
PyObject *item = vec.buf->items[j];
|
||||
Py_INCREF(item);
|
||||
res.buf->items[i] = item;
|
||||
j += step;
|
||||
}
|
||||
PyObject *result = VecT_Box(res, vec.buf->item_type);
|
||||
if (result == NULL) {
|
||||
VEC_DECREF(res);
|
||||
}
|
||||
return result;
|
||||
} else {
|
||||
PyErr_Format(PyExc_TypeError, "vec indices must be integers or slices, not %.100s",
|
||||
item->ob_type->tp_name);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int vec_ass_item(PyObject *self, Py_ssize_t i, PyObject *o) {
|
||||
VecT v = ((VecTObject *)self)->vec;
|
||||
if (!VecT_ItemCheck(v, o, v.buf->item_type))
|
||||
return -1;
|
||||
if ((size_t)i < (size_t)v.len) {
|
||||
PyObject *old = v.buf->items[i];
|
||||
Py_INCREF(o);
|
||||
v.buf->items[i] = o;
|
||||
Py_XDECREF(old);
|
||||
return 0;
|
||||
} else if ((size_t)i + (size_t)v.len < (size_t)v.len) {
|
||||
PyObject *old = v.buf->items[i + v.len];
|
||||
Py_INCREF(o);
|
||||
v.buf->items[i + v.len] = o;
|
||||
Py_XDECREF(old);
|
||||
return 0;
|
||||
} else {
|
||||
PyErr_SetString(PyExc_IndexError, "index out of range");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static PyObject *vec_richcompare(PyObject *self, PyObject *other, int op) {
|
||||
PyObject *res;
|
||||
if (op == Py_EQ || op == Py_NE) {
|
||||
if (other->ob_type != &VecTType) {
|
||||
res = op == Py_EQ ? Py_False : Py_True;
|
||||
} else {
|
||||
VecT x = ((VecTObject *)self)->vec;
|
||||
VecT y = ((VecTObject *)other)->vec;
|
||||
if (x.buf->item_type != y.buf->item_type) {
|
||||
res = op == Py_EQ ? Py_False : Py_True;
|
||||
} else {
|
||||
// TODO: why pointers to len?
|
||||
return Vec_GenericRichcompare(&x.len, x.buf->items, &y.len, y.buf->items, op);
|
||||
}
|
||||
}
|
||||
} else
|
||||
res = Py_NotImplemented;
|
||||
Py_INCREF(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
// Append item to 'vec', stealing 'vec'. Return 'vec' with item appended.
|
||||
VecT VecT_Append(VecT vec, PyObject *x, size_t item_type) {
|
||||
if (vec.buf == NULL) {
|
||||
VecT new = vec_alloc(1, item_type);
|
||||
if (VEC_IS_ERROR(new))
|
||||
return new;
|
||||
Py_INCREF(x);
|
||||
new.len = 1;
|
||||
new.buf->items[0] = x;
|
||||
return new;
|
||||
}
|
||||
Py_ssize_t cap = VEC_CAP(vec);
|
||||
Py_INCREF(x);
|
||||
if (vec.len < cap) {
|
||||
// Slot may have duplicate ref from prior remove/pop
|
||||
Py_XSETREF(vec.buf->items[vec.len], x);
|
||||
vec.len++;
|
||||
return vec;
|
||||
} else {
|
||||
Py_ssize_t new_size = 2 * cap + 1;
|
||||
// TODO: Avoid initializing to zero here
|
||||
VecT new = vec_alloc(new_size, vec.buf->item_type);
|
||||
if (VEC_IS_ERROR(new)) {
|
||||
Py_DECREF(x);
|
||||
// The input vec is being consumed/stolen by this function, so on error
|
||||
// we must decref it to avoid leaking the buffer.
|
||||
VEC_DECREF(vec);
|
||||
return new;
|
||||
}
|
||||
// Copy items to new vec.
|
||||
memcpy(new.buf->items, vec.buf->items, sizeof(PyObject *) * vec.len);
|
||||
memset(new.buf->items + vec.len, 0, sizeof(PyObject *) * (new_size - vec.len));
|
||||
// Clear the items in the old vec. We avoid reference count manipulation.
|
||||
memset(vec.buf->items, 0, sizeof(PyObject *) * vec.len);
|
||||
new.buf->items[vec.len] = x;
|
||||
new.len = vec.len + 1;
|
||||
VEC_DECREF(vec);
|
||||
return new;
|
||||
}
|
||||
}
|
||||
|
||||
// Remove item from 'vec', stealing 'vec'. Return 'vec' with item removed.
|
||||
VecT VecT_Remove(VecT v, PyObject *arg) {
|
||||
PyObject **items = v.buf->items;
|
||||
for (Py_ssize_t i = 0; i < v.len; i++) {
|
||||
int match = 0;
|
||||
if (items[i] == arg)
|
||||
match = 1;
|
||||
else {
|
||||
int itemcmp = PyObject_RichCompareBool(items[i], arg, Py_EQ);
|
||||
if (itemcmp < 0) {
|
||||
// The input v is being consumed/stolen by this function, so on error
|
||||
// we must decref it to avoid leaking the buffer.
|
||||
VEC_DECREF(v);
|
||||
return vec_error();
|
||||
}
|
||||
match = itemcmp;
|
||||
}
|
||||
if (match) {
|
||||
if (i < v.len - 1) {
|
||||
Py_CLEAR(items[i]);
|
||||
for (; i < v.len - 1; i++) {
|
||||
items[i] = items[i + 1];
|
||||
}
|
||||
// Keep a duplicate item, since there could be another reference
|
||||
// to the buffer with a longer length, and they expect a valid reference.
|
||||
Py_XINCREF(items[v.len - 1]);
|
||||
}
|
||||
v.len--;
|
||||
// Return the stolen reference without INCREF
|
||||
return v;
|
||||
}
|
||||
}
|
||||
PyErr_SetString(PyExc_ValueError, "vec.remove(x): x not in vec");
|
||||
// The input v is being consumed/stolen by this function, so on error
|
||||
// we must decref it to avoid leaking the buffer.
|
||||
VEC_DECREF(v);
|
||||
return vec_error();
|
||||
}
|
||||
|
||||
// Pop item from 'vec', stealing 'vec'. Return struct with modified 'vec' and the popped item.
|
||||
VecTPopResult VecT_Pop(VecT v, Py_ssize_t index) {
|
||||
VecTPopResult result;
|
||||
|
||||
if (index < 0)
|
||||
index += v.len;
|
||||
|
||||
if (index < 0 || index >= v.len) {
|
||||
PyErr_SetString(PyExc_IndexError, "index out of range");
|
||||
// The input v is being consumed/stolen by this function, so on error
|
||||
// we must decref it to avoid leaking the buffer.
|
||||
VEC_DECREF(v);
|
||||
result.f0 = vec_error();
|
||||
result.f1 = NULL;
|
||||
return result;
|
||||
}
|
||||
|
||||
PyObject **items = v.buf->items;
|
||||
result.f1 = items[index];
|
||||
for (Py_ssize_t i = index; i < v.len - 1; i++)
|
||||
items[i] = items[i + 1];
|
||||
// Keep duplicate item, since there could be another reference
|
||||
// to the buffer with a longer length, and they expect a valid reference.
|
||||
Py_XINCREF(items[v.len - 1]);
|
||||
v.len--;
|
||||
// Return the stolen reference without INCREF
|
||||
result.f0 = v;
|
||||
return result;
|
||||
}
|
||||
|
||||
static int
|
||||
VecT_traverse(VecTObject *self, visitproc visit, void *arg)
|
||||
{
|
||||
Py_VISIT(self->vec.buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
VecT_clear(VecTObject *self)
|
||||
{
|
||||
Py_CLEAR(self->vec.buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
VecT_dealloc(VecTObject *self)
|
||||
{
|
||||
PyObject_GC_UnTrack(self);
|
||||
Py_TRASHCAN_BEGIN(self, VecT_dealloc)
|
||||
Py_CLEAR(self->vec.buf);
|
||||
Py_TYPE(self)->tp_free((PyObject *)self);
|
||||
Py_TRASHCAN_END
|
||||
}
|
||||
|
||||
static int
|
||||
VecTBuf_traverse(VecTBufObject *self, visitproc visit, void *arg)
|
||||
{
|
||||
Py_VISIT(VEC_BUF_ITEM_TYPE(self));
|
||||
for (Py_ssize_t i = 0; i < VEC_BUF_SIZE(self); i++) {
|
||||
Py_VISIT(self->items[i]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
VecTBuf_clear(VecTBufObject *self)
|
||||
{
|
||||
if (self->item_type) {
|
||||
Py_DECREF(VEC_BUF_ITEM_TYPE(self));
|
||||
self->item_type = 0;
|
||||
}
|
||||
for (Py_ssize_t i = 0; i < VEC_BUF_SIZE(self); i++) {
|
||||
Py_CLEAR(self->items[i]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
VecTBuf_dealloc(VecTBufObject *self)
|
||||
{
|
||||
PyObject_GC_UnTrack(self);
|
||||
Py_TRASHCAN_BEGIN(self, VecTBuf_dealloc)
|
||||
VecTBuf_clear(self);
|
||||
Py_TYPE(self)->tp_free((PyObject *)self);
|
||||
Py_TRASHCAN_END
|
||||
}
|
||||
|
||||
static Py_ssize_t vec_length(PyObject *o) {
|
||||
return ((VecTObject *)o)->vec.len;
|
||||
}
|
||||
|
||||
static PyMappingMethods VecTMapping = {
|
||||
.mp_length = vec_length,
|
||||
.mp_subscript = vec_subscript,
|
||||
};
|
||||
|
||||
static PySequenceMethods VecTSequence = {
|
||||
.sq_item = vec_get_item,
|
||||
.sq_ass_item = vec_ass_item,
|
||||
};
|
||||
|
||||
static PyMethodDef vec_methods[] = {
|
||||
{NULL, NULL, 0, NULL}, /* Sentinel */
|
||||
};
|
||||
|
||||
PyTypeObject VecTBufType = {
|
||||
PyVarObject_HEAD_INIT(NULL, 0)
|
||||
.tp_name = "vecbuf",
|
||||
.tp_doc = "Internal data buffer used by vec objects",
|
||||
.tp_basicsize = sizeof(VecTBufObject) - sizeof(PyObject *),
|
||||
.tp_itemsize = sizeof(PyObject *),
|
||||
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
|
||||
.tp_traverse = (traverseproc)VecTBuf_traverse,
|
||||
//.tp_new = vecbuf_i64_new, //??
|
||||
.tp_free = PyObject_GC_Del,
|
||||
.tp_clear = (inquiry)VecTBuf_clear,
|
||||
.tp_dealloc = (destructor)VecTBuf_dealloc,
|
||||
};
|
||||
|
||||
PyTypeObject VecTType = {
|
||||
PyVarObject_HEAD_INIT(NULL, 0)
|
||||
.tp_name = "vec",
|
||||
.tp_doc = "Mutable sequence-like container optimized for compilation with mypyc",
|
||||
.tp_basicsize = sizeof(VecTObject),
|
||||
.tp_itemsize = 0,
|
||||
.tp_base = &VecType, // Inherit from base vec type for isinstance() support
|
||||
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
|
||||
.tp_traverse = (traverseproc)VecT_traverse,
|
||||
.tp_clear = (inquiry)VecT_clear,
|
||||
.tp_dealloc = (destructor)VecT_dealloc,
|
||||
//.tp_free = PyObject_GC_Del,
|
||||
.tp_repr = (reprfunc)vec_repr,
|
||||
.tp_as_sequence = &VecTSequence,
|
||||
.tp_as_mapping = &VecTMapping,
|
||||
.tp_richcompare = vec_richcompare,
|
||||
.tp_methods = vec_methods,
|
||||
// TODO: free
|
||||
};
|
||||
|
||||
PyObject *VecT_FromIterable(size_t item_type, PyObject *iterable) {
|
||||
VecT v = vec_alloc(0, item_type);
|
||||
if (VEC_IS_ERROR(v))
|
||||
return NULL;
|
||||
v.len = 0;
|
||||
|
||||
PyObject *iter = PyObject_GetIter(iterable);
|
||||
if (iter == NULL) {
|
||||
VEC_DECREF(v);
|
||||
return NULL;
|
||||
}
|
||||
PyObject *item;
|
||||
while ((item = PyIter_Next(iter)) != NULL) {
|
||||
if (!VecT_ItemCheck(v, item, item_type)) {
|
||||
Py_DECREF(iter);
|
||||
VEC_DECREF(v);
|
||||
Py_DECREF(item);
|
||||
return NULL;
|
||||
}
|
||||
v = VecT_Append(v, item, item_type);
|
||||
Py_DECREF(item);
|
||||
if (VEC_IS_ERROR(v)) {
|
||||
Py_DECREF(iter);
|
||||
VEC_DECREF(v);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
Py_DECREF(iter);
|
||||
if (PyErr_Occurred()) {
|
||||
VEC_DECREF(v);
|
||||
return NULL;
|
||||
}
|
||||
return VecT_Box(v, item_type);
|
||||
}
|
||||
|
||||
VecTAPI Vec_TAPI = {
|
||||
&VecTType,
|
||||
&VecTBufType,
|
||||
VecT_New,
|
||||
VecT_Box,
|
||||
VecT_Unbox,
|
||||
VecT_ConvertFromNested,
|
||||
VecT_Append,
|
||||
VecT_Pop,
|
||||
VecT_Remove,
|
||||
VecT_Slice,
|
||||
};
|
||||
|
||||
#endif // MYPYC_EXPERIMENTAL
|
||||
|
|
@ -0,0 +1,399 @@
|
|||
#ifdef MYPYC_EXPERIMENTAL
|
||||
// NOTE: This file can't be compiled on its own, it must be #included
|
||||
// with certain #defines set, as described below.
|
||||
//
|
||||
// Implementation of a vec class specialized to a specific item type, such
|
||||
// as vec[i64] or vec[float]. Assume that certain #defines are provided that
|
||||
// provide all the item type specific definitions:
|
||||
//
|
||||
// VEC vec C type (e.g. VecI32)
|
||||
// VEC_TYPE boxed vec type object (e.g. VecI32Type)
|
||||
// VEC_OBJECT boxed Python object struct (e.g. VecI32Object)
|
||||
// BUF_OBJECT buffer Python object struct (e.g. VecI32BufObject)
|
||||
// BUF_TYPE buffer type object (e.g. VecI32BufType)
|
||||
// NAME(suffix) macro to create prefixed name with given suffix (e.g. VecI32##suffix)
|
||||
// FUNC(suffix) macro to create prefixed function name with suffix (e.g. VecI32_##suffix)
|
||||
// ITEM_TYPE_STR vec item type as C string literal (e.g. "i32")
|
||||
// ITEM_TYPE_MAGIC integer constant corresponding to the item type (e.g. VEC_ITEM_TYPE_I32)
|
||||
// ITEM_C_TYPE C type used for items (e.g. int32_t)
|
||||
// FEATURES capsule API struct name (e.g. Vec_I32API)
|
||||
// BOX_ITEM C function to box item (e.g. VecI32_BoxItem)
|
||||
// UNBOX_ITEM C function to unbox item (e.g. VecI32_UnboxItem)
|
||||
// IS_UNBOX_ERROR C function to check for unbox error (e.g. VecI32_IsUnboxError)
|
||||
|
||||
#ifndef VEC
|
||||
#error "VEC must be defined"
|
||||
#endif
|
||||
|
||||
#define PY_SSIZE_T_CLEAN
|
||||
#include <Python.h>
|
||||
#include "librt_vecs.h"
|
||||
#include "vecs_internal.h"
|
||||
|
||||
inline static VEC vec_error() {
|
||||
VEC v = { .len = -1 };
|
||||
return v;
|
||||
}
|
||||
|
||||
// Alloc a partially initialized vec. Caller *must* initialize len.
|
||||
static VEC vec_alloc(Py_ssize_t size)
|
||||
{
|
||||
BUF_OBJECT *buf;
|
||||
/* TODO: Check for overflow */
|
||||
if (size == 0) {
|
||||
buf = NULL;
|
||||
} else {
|
||||
buf = PyObject_NewVar(BUF_OBJECT, &BUF_TYPE, size);
|
||||
if (buf == NULL)
|
||||
return vec_error();
|
||||
}
|
||||
VEC res = { .buf = buf };
|
||||
return res;
|
||||
}
|
||||
|
||||
static void vec_dealloc(VEC_OBJECT *self) {
|
||||
Py_CLEAR(self->vec.buf);
|
||||
PyObject_Del(self);
|
||||
}
|
||||
|
||||
// Box a vec[<itemtype>] value, stealing 'vec'. On error, decref 'vec'.
|
||||
PyObject *FUNC(Box)(VEC vec) {
|
||||
VEC_OBJECT *obj = PyObject_New(VEC_OBJECT, &VEC_TYPE);
|
||||
if (obj == NULL) {
|
||||
VEC_DECREF(vec);
|
||||
return NULL;
|
||||
}
|
||||
obj->vec = vec;
|
||||
return (PyObject *)obj;
|
||||
}
|
||||
|
||||
VEC FUNC(Unbox)(PyObject *obj) {
|
||||
if (obj->ob_type == &VEC_TYPE) {
|
||||
VEC result = ((VEC_OBJECT *)obj)->vec;
|
||||
VEC_INCREF(result); // TODO: Should we borrow instead?
|
||||
return result;
|
||||
} else {
|
||||
PyErr_SetString(PyExc_TypeError, "vec[" ITEM_TYPE_STR "] expected");
|
||||
return vec_error();
|
||||
}
|
||||
}
|
||||
|
||||
VEC FUNC(ConvertFromNested)(VecNestedBufItem item) {
|
||||
return (VEC) { item.len, (BUF_OBJECT *)item.buf };
|
||||
}
|
||||
|
||||
VEC FUNC(New)(Py_ssize_t size, Py_ssize_t cap) {
|
||||
if (cap < size)
|
||||
size = cap;
|
||||
VEC vec = vec_alloc(cap);
|
||||
if (VEC_IS_ERROR(vec))
|
||||
return vec;
|
||||
for (Py_ssize_t i = 0; i < cap; i++) {
|
||||
vec.buf->items[i] = 0;
|
||||
}
|
||||
vec.len = size;
|
||||
return vec;
|
||||
}
|
||||
|
||||
PyObject *FUNC(FromIterable)(PyObject *iterable) {
|
||||
VEC v = vec_alloc(0);
|
||||
if (VEC_IS_ERROR(v))
|
||||
return NULL;
|
||||
v.len = 0;
|
||||
|
||||
PyObject *iter = PyObject_GetIter(iterable);
|
||||
if (iter == NULL) {
|
||||
VEC_DECREF(v);
|
||||
return NULL;
|
||||
}
|
||||
PyObject *item;
|
||||
while ((item = PyIter_Next(iter)) != NULL) {
|
||||
ITEM_C_TYPE x = UNBOX_ITEM(item);
|
||||
Py_DECREF(item);
|
||||
if (IS_UNBOX_ERROR(x)) {
|
||||
Py_DECREF(iter);
|
||||
VEC_DECREF(v);
|
||||
return NULL;
|
||||
}
|
||||
v = FUNC(Append)(v, x);
|
||||
if (VEC_IS_ERROR(v)) {
|
||||
Py_DECREF(iter);
|
||||
VEC_DECREF(v);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
Py_DECREF(iter);
|
||||
if (PyErr_Occurred()) {
|
||||
VEC_DECREF(v);
|
||||
return NULL;
|
||||
}
|
||||
return FUNC(Box)(v);
|
||||
}
|
||||
|
||||
static PyObject *vec_new(PyTypeObject *self, PyObject *args, PyObject *kw) {
|
||||
static char *kwlist[] = {"", NULL};
|
||||
PyObject *init = NULL;
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kw, "|O:vec", kwlist, &init)) {
|
||||
return NULL;
|
||||
}
|
||||
if (init == NULL) {
|
||||
return FUNC(Box)(FUNC(New)(0, 0));
|
||||
} else {
|
||||
return (PyObject *)FUNC(FromIterable)(init);
|
||||
}
|
||||
}
|
||||
|
||||
static PyObject *vec_repr(PyObject *self) {
|
||||
return Vec_GenericRepr(self, ITEM_TYPE_MAGIC, 0, 1);
|
||||
}
|
||||
|
||||
static PyObject *vec_get_item(PyObject *o, Py_ssize_t i) {
|
||||
VEC v = ((VEC_OBJECT *)o)->vec;
|
||||
if ((size_t)i < (size_t)v.len) {
|
||||
return BOX_ITEM(v.buf->items[i]);
|
||||
} else if ((size_t)i + (size_t)v.len < (size_t)v.len) {
|
||||
return BOX_ITEM(v.buf->items[i + v.len]);
|
||||
} else {
|
||||
PyErr_SetString(PyExc_IndexError, "index out of range");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
VEC FUNC(Slice)(VEC vec, int64_t start, int64_t end) {
|
||||
if (start < 0)
|
||||
start += vec.len;
|
||||
if (end < 0)
|
||||
end += vec.len;
|
||||
if (start < 0)
|
||||
start = 0;
|
||||
if (start >= vec.len)
|
||||
start = vec.len;
|
||||
if (end < start)
|
||||
end = start;
|
||||
if (end > vec.len)
|
||||
end = vec.len;
|
||||
int64_t slicelength = end - start;
|
||||
VEC res = vec_alloc(slicelength);
|
||||
if (VEC_IS_ERROR(res))
|
||||
return res;
|
||||
res.len = slicelength;
|
||||
for (Py_ssize_t i = 0; i < slicelength; i++)
|
||||
res.buf->items[i] = vec.buf->items[start + i];
|
||||
return res;
|
||||
}
|
||||
|
||||
static PyObject *vec_subscript(PyObject *self, PyObject *item) {
|
||||
VEC vec = ((VEC_OBJECT *)self)->vec;
|
||||
if (PyIndex_Check(item)) {
|
||||
Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
|
||||
if (i == -1 && PyErr_Occurred())
|
||||
return NULL;
|
||||
if ((size_t)i < (size_t)vec.len) {
|
||||
return BOX_ITEM(vec.buf->items[i]);
|
||||
} else if ((size_t)i + (size_t)vec.len < (size_t)vec.len) {
|
||||
return BOX_ITEM(vec.buf->items[i + vec.len]);
|
||||
} else {
|
||||
PyErr_SetString(PyExc_IndexError, "index out of range");
|
||||
return NULL;
|
||||
}
|
||||
} else if (PySlice_Check(item)) {
|
||||
Py_ssize_t start, stop, step;
|
||||
if (PySlice_Unpack(item, &start, &stop, &step) < 0)
|
||||
return NULL;
|
||||
Py_ssize_t slicelength = PySlice_AdjustIndices(vec.len, &start, &stop, step);
|
||||
VEC res = vec_alloc(slicelength);
|
||||
if (VEC_IS_ERROR(res))
|
||||
return NULL;
|
||||
res.len = slicelength;
|
||||
Py_ssize_t j = start;
|
||||
for (Py_ssize_t i = 0; i < slicelength; i++) {
|
||||
res.buf->items[i] = vec.buf->items[j];
|
||||
j += step;
|
||||
}
|
||||
return FUNC(Box)(res);
|
||||
} else {
|
||||
PyErr_Format(PyExc_TypeError, "vec indices must be integers or slices, not %.100s",
|
||||
item->ob_type->tp_name);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int vec_ass_item(PyObject *self, Py_ssize_t i, PyObject *o) {
|
||||
ITEM_C_TYPE x = UNBOX_ITEM(o);
|
||||
if (IS_UNBOX_ERROR(x))
|
||||
return -1;
|
||||
VEC v = ((VEC_OBJECT *)self)->vec;
|
||||
if ((size_t)i < (size_t)v.len) {
|
||||
v.buf->items[i] = x;
|
||||
return 0;
|
||||
} else if ((size_t)i + (size_t)v.len < (size_t)v.len) {
|
||||
v.buf->items[i + v.len] = x;
|
||||
return 0;
|
||||
} else {
|
||||
PyErr_SetString(PyExc_IndexError, "index out of range");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static Py_ssize_t vec_length(PyObject *o) {
|
||||
return ((VEC_OBJECT *)o)->vec.len;
|
||||
}
|
||||
|
||||
static PyObject *vec_richcompare(PyObject *self, PyObject *other, int op) {
|
||||
int cmp = 1;
|
||||
PyObject *res;
|
||||
if (op == Py_EQ || op == Py_NE) {
|
||||
if (other->ob_type != &VEC_TYPE)
|
||||
cmp = 0;
|
||||
else {
|
||||
VEC x = ((VEC_OBJECT *)self)->vec;
|
||||
VEC y = ((VEC_OBJECT *)other)->vec;
|
||||
if (x.len != y.len) {
|
||||
cmp = 0;
|
||||
} else {
|
||||
for (Py_ssize_t i = 0; i < x.len; i++) {
|
||||
if (x.buf->items[i] != y.buf->items[i]) {
|
||||
cmp = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (op == Py_NE)
|
||||
cmp = cmp ^ 1;
|
||||
res = cmp ? Py_True : Py_False;
|
||||
} else
|
||||
res = Py_NotImplemented;
|
||||
Py_INCREF(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
// Append item to 'vec', stealing 'vec'. Return 'vec' with item appended.
|
||||
VEC FUNC(Append)(VEC vec, ITEM_C_TYPE x) {
|
||||
if (vec.buf && vec.len < VEC_CAP(vec)) {
|
||||
vec.buf->items[vec.len] = x;
|
||||
vec.len++;
|
||||
return vec;
|
||||
} else {
|
||||
Py_ssize_t cap = vec.buf ? VEC_CAP(vec) : 0;
|
||||
Py_ssize_t new_size = 2 * cap + 1;
|
||||
VEC new = vec_alloc(new_size);
|
||||
if (VEC_IS_ERROR(new)) {
|
||||
// The input v is being consumed/stolen by this function, so on error
|
||||
// we must decref it to avoid leaking the buffer.
|
||||
VEC_DECREF(vec);
|
||||
return vec_error();
|
||||
}
|
||||
new.len = vec.len + 1;
|
||||
if (vec.len > 0)
|
||||
memcpy(new.buf->items, vec.buf->items, sizeof(ITEM_C_TYPE) * vec.len);
|
||||
new.buf->items[vec.len] = x;
|
||||
Py_XDECREF(vec.buf);
|
||||
return new;
|
||||
}
|
||||
}
|
||||
|
||||
// Remove item from 'vec', stealing 'vec'. Return 'vec' with item removed.
|
||||
VEC FUNC(Remove)(VEC v, ITEM_C_TYPE x) {
|
||||
for (Py_ssize_t i = 0; i < v.len; i++) {
|
||||
if (v.buf->items[i] == x) {
|
||||
for (; i < v.len - 1; i++) {
|
||||
v.buf->items[i] = v.buf->items[i + 1];
|
||||
}
|
||||
v.len--;
|
||||
// Return the stolen reference without INCREF
|
||||
return v;
|
||||
}
|
||||
}
|
||||
PyErr_SetString(PyExc_ValueError, "vec.remove(x): x not in vec");
|
||||
// The input v is being consumed/stolen by this function, so on error
|
||||
// we must decref it to avoid leaking the buffer.
|
||||
VEC_DECREF(v);
|
||||
return vec_error();
|
||||
}
|
||||
|
||||
// Pop item from 'vec', stealing 'vec'. Return struct with modified 'vec' and the popped item.
|
||||
NAME(PopResult) FUNC(Pop)(VEC v, Py_ssize_t index) {
|
||||
NAME(PopResult) result;
|
||||
|
||||
if (index < 0)
|
||||
index += v.len;
|
||||
|
||||
if (index < 0 || index >= v.len) {
|
||||
PyErr_SetString(PyExc_IndexError, "index out of range");
|
||||
// The input v is being consumed/stolen by this function, so on error
|
||||
// we must decref it to avoid leaking the buffer.
|
||||
VEC_DECREF(v);
|
||||
result.f0 = vec_error();
|
||||
result.f1 = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
result.f1 = v.buf->items[index];
|
||||
for (Py_ssize_t i = index; i < v.len - 1; i++) {
|
||||
v.buf->items[i] = v.buf->items[i + 1];
|
||||
}
|
||||
|
||||
v.len--;
|
||||
// Return the stolen reference without INCREF
|
||||
result.f0 = v;
|
||||
return result;
|
||||
}
|
||||
|
||||
static PyMappingMethods vec_mapping_methods = {
|
||||
.mp_length = vec_length,
|
||||
.mp_subscript = vec_subscript,
|
||||
};
|
||||
|
||||
static PySequenceMethods vec_sequence_methods = {
|
||||
.sq_item = vec_get_item,
|
||||
.sq_ass_item = vec_ass_item,
|
||||
};
|
||||
|
||||
static PyMethodDef vec_methods[] = {
|
||||
{NULL, NULL, 0, NULL}, /* Sentinel */
|
||||
};
|
||||
|
||||
PyTypeObject BUF_TYPE = {
|
||||
PyVarObject_HEAD_INIT(NULL, 0)
|
||||
.tp_name = "vecbuf[" ITEM_TYPE_STR "]",
|
||||
.tp_doc = "Internal data buffer used by vec objects",
|
||||
.tp_basicsize = sizeof(BUF_OBJECT) - sizeof(ITEM_C_TYPE),
|
||||
.tp_itemsize = sizeof(ITEM_C_TYPE),
|
||||
.tp_flags = Py_TPFLAGS_DEFAULT,
|
||||
//.tp_new = ??
|
||||
.tp_free = PyObject_Del,
|
||||
};
|
||||
|
||||
PyTypeObject VEC_TYPE = {
|
||||
PyVarObject_HEAD_INIT(NULL, 0)
|
||||
.tp_name = "vec[" ITEM_TYPE_STR "]",
|
||||
.tp_doc = "Mutable sequence-like container optimized for compilation with mypyc",
|
||||
.tp_basicsize = sizeof(VEC_OBJECT),
|
||||
.tp_itemsize = 0,
|
||||
.tp_base = &VecType, // Inherit from base vec type for isinstance() support
|
||||
.tp_flags = Py_TPFLAGS_DEFAULT,
|
||||
.tp_new = vec_new,
|
||||
//.tp_free = PyObject_Del,
|
||||
.tp_dealloc = (destructor)vec_dealloc,
|
||||
.tp_repr = (reprfunc)vec_repr,
|
||||
.tp_as_sequence = &vec_sequence_methods,
|
||||
.tp_as_mapping = &vec_mapping_methods,
|
||||
.tp_richcompare = vec_richcompare,
|
||||
.tp_methods = vec_methods,
|
||||
};
|
||||
|
||||
NAME(API) FEATURES = {
|
||||
&VEC_TYPE,
|
||||
&BUF_TYPE,
|
||||
FUNC(New),
|
||||
FUNC(Box),
|
||||
FUNC(Unbox),
|
||||
FUNC(ConvertFromNested),
|
||||
FUNC(Append),
|
||||
FUNC(Pop),
|
||||
FUNC(Remove),
|
||||
FUNC(Slice),
|
||||
};
|
||||
|
||||
#endif // MYPYC_EXPERIMENTAL
|
||||
20
venv/lib/python3.11/site-packages/mypyc/lib-rt/vecs/vec_u8.c
Normal file
20
venv/lib/python3.11/site-packages/mypyc/lib-rt/vecs/vec_u8.c
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
#ifdef MYPYC_EXPERIMENTAL
|
||||
#define VEC VecU8
|
||||
#define VEC_TYPE VecU8Type
|
||||
#define VEC_OBJECT VecU8Object
|
||||
#define BUF_OBJECT VecU8BufObject
|
||||
#define BUF_TYPE VecU8BufType
|
||||
#define NAME(suffix) VecU8##suffix
|
||||
#define FUNC(suffix) VecU8_##suffix
|
||||
#define ITEM_TYPE_STR "u8"
|
||||
#define ITEM_TYPE_MAGIC VEC_ITEM_TYPE_U8
|
||||
#define ITEM_C_TYPE uint8_t
|
||||
#define FEATURES Vec_U8API
|
||||
|
||||
#define BOX_ITEM VecU8_BoxItem
|
||||
#define UNBOX_ITEM VecU8_UnboxItem
|
||||
#define IS_UNBOX_ERROR VecU8_IsUnboxError
|
||||
|
||||
#include "vec_template.c"
|
||||
|
||||
#endif // MYPYC_EXPERIMENTAL
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
#ifndef VECS_INTERNAL_H_INCL
|
||||
#define VECS_INTERNAL_H_INCL
|
||||
|
||||
// Internal header for mypyc/lib-rt/vecs implementation
|
||||
|
||||
#include <Python.h>
|
||||
|
||||
// The base vec type
|
||||
extern PyTypeObject VecType;
|
||||
|
||||
#endif // VECS_INTERNAL_H_INCL
|
||||
Loading…
Add table
Add a link
Reference in a new issue