This commit is contained in:
blueloveTH 2023-09-30 12:07:44 +08:00
parent ced9662530
commit 24e6b162c8
5 changed files with 116 additions and 118 deletions

View File

@ -1,9 +1,13 @@
--- ---
icon: dot icon: star
label: 'Bind native function' title: Write bindings
order: 60 order: 18
--- ---
!!!
This document is working in progress.
!!!
pkpy allows to wrap a function pointer as a python function or method that can be called in python code. pkpy allows to wrap a function pointer as a python function or method that can be called in python code.
This function pointer has the following signature: This function pointer has the following signature:
@ -101,3 +105,104 @@ vm->bind__add__(type, __add__);
This specialized binding function has optimizations and result in better performance when calling from python code. This specialized binding function has optimizations and result in better performance when calling from python code.
For example, `vm->bind__add__` is preferred over `vm->bind_method<1>(type, "__add__", ...)`. For example, `vm->bind__add__` is preferred over `vm->bind_method<1>(type, "__add__", ...)`.
Add `PY_CLASS` macro into your `struct` and implement a static function `_register`.
Inside the `_register` function, you can bind methods and properties to the class.
```cpp
PY_CLASS(T, mod, name)
// T is the struct type in cpp
// mod is the module name in python
// name is the class name in python
```
## Example
In this example, we will create a `linalg` module
and implement a `vec2` type with some methods.
And make them available in python just like this.
```python
from linalg import vec2
# construct a vec2
a = vec2(1.0, 2.0)
b = vec2(0.0, -1.0)
# add two vec2
print(a + b) # vec2(1.0, 1.0)
# set x component
a.x = 8.0
print(a) # vec2(8.0, 2.0)
# use dot method
print(a.dot(b)) # -2.0
```
### Implement `Vec2` struct in cpp
```cpp
struct Vec2{
float x, y;
Vec2() : x(0.0f), y(0.0f) {}
Vec2(float x, float y) : x(x), y(y) {}
Vec2(const Vec2& v) : x(v.x), y(v.y) {}
Vec2 operator+(const Vec2& v) const { return Vec2(x + v.x, y + v.y); }
float dot(const Vec2& v) const { return x * v.x + y * v.y; }
};
```
### Create `PyVec2` wrapper
```cpp
struct PyVec2: Vec2 {
PY_CLASS(PyVec2, linalg, vec2)
PyVec2() : Vec2() {}
PyVec2(const Vec2& v) : Vec2(v) {}
PyVec2(const PyVec2& v) : Vec2(v) {}
static void _register(VM* vm, PyObject* mod, PyObject* type){
vm->bind_constructor<3>(type, [](VM* vm, ArgsView args){
float x = CAST_F(args[1]);
float y = CAST_F(args[2]);
return VAR(Vec2(x, y));
});
vm->bind__repr__(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* obj){
PyVec2& self = _CAST(PyVec2&, obj);
std::stringstream ss;
ss << "vec2(" << self.x << ", " << self.y << ")";
return VAR(ss.str());
});
vm->bind__add__(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* obj, PyObject* other){
PyVec2& self = _CAST(PyVec2&, obj);
PyVec2& other_ = CAST(PyVec2&, other);
return VAR_T(PyVec2, self + other_);
});
vm->bind(type, "dot(self, other: vec2) -> float", [](VM* vm, ArgsView args){
PyVec2& self = _CAST(PyVec2&, args[0]);
PyVec2& other = CAST(PyVec2&, args[1]);
return VAR(self.dot(other));
});
}
};
```
### Create `linalg` module
```cpp
void add_module_linalg(VM* vm){
PyObject* linalg = vm->new_module("linalg");
// register PyVec2
PyVec2::register_class(vm, linalg);
}
```
### Further reading
See [linalg.h](https://github.com/blueloveTH/pocketpy/blob/main/src/linalg.h) for the complete implementation.

View File

@ -6,13 +6,11 @@ label: Performance
# Performance # Performance
Currently, pkpy is completely faster than cpython 3.8. Currently, pkpy is as fast as cpython 3.8.
Here is a benchmark result of the current commit. **Performance results for cpython 3.8 are applicable to for pkpy.**
Benchmark files are located in `benchmarks/`.
See [actions/runs](https://github.com/blueloveTH/pocketpy/actions/runs/5113363233/jobs/9192476164).
Here is a benchmark result of `v1.0.0`.
Files are located in `benchmarks/`.
``` ```
Testing directory: benchmarks/ Testing directory: benchmarks/
@ -48,3 +46,5 @@ Testing directory: benchmarks/
pocketpy: 0.004495s (22.29%) pocketpy: 0.004495s (22.29%)
ALL TESTS PASSED ALL TESTS PASSED
``` ```
See [actions/runs](https://github.com/blueloveTH/pocketpy/actions/runs/5113363233/jobs/9192476164).

Binary file not shown.

View File

@ -1,3 +1,2 @@
icon: rocket icon: rocket
expanded: true
order: 20 order: 20

View File

@ -1,106 +0,0 @@
---
icon: dot
label: 'Wrap native struct'
order: 50
---
Add `PY_CLASS` macro into your `struct` and implement a static function `_register`.
Inside the `_register` function, you can bind methods and properties to the class.
```cpp
PY_CLASS(T, mod, name)
// T is the struct type in cpp
// mod is the module name in python
// name is the class name in python
```
## Example
In this example, we will create a `linalg` module
and implement a `vec2` type with some methods.
And make them available in python just like this.
```python
from linalg import vec2
# construct a vec2
a = vec2(1.0, 2.0)
b = vec2(0.0, -1.0)
# add two vec2
print(a + b) # vec2(1.0, 1.0)
# set x component
a.x = 8.0
print(a) # vec2(8.0, 2.0)
# use dot method
print(a.dot(b)) # -2.0
```
### Implement `Vec2` struct in cpp
```cpp
struct Vec2{
float x, y;
Vec2() : x(0.0f), y(0.0f) {}
Vec2(float x, float y) : x(x), y(y) {}
Vec2(const Vec2& v) : x(v.x), y(v.y) {}
Vec2 operator+(const Vec2& v) const { return Vec2(x + v.x, y + v.y); }
float dot(const Vec2& v) const { return x * v.x + y * v.y; }
};
```
### Create `PyVec2` wrapper
```cpp
struct PyVec2: Vec2 {
PY_CLASS(PyVec2, linalg, vec2)
PyVec2() : Vec2() {}
PyVec2(const Vec2& v) : Vec2(v) {}
PyVec2(const PyVec2& v) : Vec2(v) {}
static void _register(VM* vm, PyObject* mod, PyObject* type){
vm->bind_constructor<3>(type, [](VM* vm, ArgsView args){
float x = CAST_F(args[1]);
float y = CAST_F(args[2]);
return VAR(Vec2(x, y));
});
vm->bind__repr__(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* obj){
PyVec2& self = _CAST(PyVec2&, obj);
std::stringstream ss;
ss << "vec2(" << self.x << ", " << self.y << ")";
return VAR(ss.str());
});
vm->bind__add__(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* obj, PyObject* other){
PyVec2& self = _CAST(PyVec2&, obj);
PyVec2& other_ = CAST(PyVec2&, other);
return VAR_T(PyVec2, self + other_);
});
vm->bind(type, "dot(self, other: vec2) -> float", [](VM* vm, ArgsView args){
PyVec2& self = _CAST(PyVec2&, args[0]);
PyVec2& other = CAST(PyVec2&, args[1]);
return VAR(self.dot(other));
});
}
};
```
### Create `linalg` module
```cpp
void add_module_linalg(VM* vm){
PyObject* linalg = vm->new_module("linalg");
// register PyVec2
PyVec2::register_class(vm, linalg);
}
```
### Further reading
See [linalg.h](https://github.com/blueloveTH/pocketpy/blob/main/src/linalg.h) for the complete implementation.