mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-20 03:20:18 +00:00
Update 1_5_0.md
This commit is contained in:
parent
e8a76806c7
commit
7828ad2eec
111
docs/1_5_0.md
111
docs/1_5_0.md
@ -21,5 +21,114 @@ vm->bind_method<M>(obj, "get", f_get);
|
|||||||
|
|
||||||
// new ARGC-based binding
|
// new ARGC-based binding
|
||||||
vm->bind_func(obj, "add", N, f_add);
|
vm->bind_func(obj, "add", N, f_add);
|
||||||
vm->bind_func(obj, "get", M+1, f_get);
|
vm->bind_func(obj, "get", M+1, f_get); // +1 for `self`
|
||||||
|
```
|
||||||
|
|
||||||
|
## Class bindings
|
||||||
|
|
||||||
|
Previously, if we want to write bindings for a C++ class, we need to add `PY_CLASS` macro and implement a magic method `_register`. This way was known as an intrusive way. For example:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
struct Point{
|
||||||
|
PY_CLASS(Point, test, Point)
|
||||||
|
|
||||||
|
int x, y;
|
||||||
|
|
||||||
|
static void _register(VM* vm, PyObject* mod, PyObject* type){
|
||||||
|
// do bindings here
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
int main(){
|
||||||
|
VM* vm = new VM();
|
||||||
|
PyObject* mod = vm->new_module("test");
|
||||||
|
Point::register_class(vm, mod);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
In `v1.5.0`, the `PY_CLASS` macro was deprecated. We introduced a non-intrusive way to write class bindings via `vm->register_user_class<>`. The example above can be rewritten as follows:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
struct Point{
|
||||||
|
int x, y;
|
||||||
|
};
|
||||||
|
|
||||||
|
int main(){
|
||||||
|
VM* vm = new VM();
|
||||||
|
PyObject* mod = vm->new_module("test");
|
||||||
|
vm->register_user_class<Point>(mod, "Point",
|
||||||
|
[](VM* vm, PyObject* mod, PyObject* type){
|
||||||
|
// do bindings here
|
||||||
|
});
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The magic method `_register` is kept for users who still wants to use the intrusive way.
|
||||||
|
This is achieved by an overloaded version of `vm->register_user_class<>`. For example:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
struct Point{
|
||||||
|
int x, y;
|
||||||
|
|
||||||
|
static void _register(VM* vm, PyObject* mod, PyObject* type){
|
||||||
|
// do bindings here (if you like the intrusive way)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
int main(){
|
||||||
|
VM* vm = new VM();
|
||||||
|
PyObject* mod = vm->new_module("test");
|
||||||
|
vm->register_user_class<Point>(mod, "Point");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Optimization of `vm->bind__next__`
|
||||||
|
|
||||||
|
`vm->bind__next__` is a special method that is used to implement the iterator protocol.
|
||||||
|
Previously, if you want to return multiple values, you need to pack them into a tuple.
|
||||||
|
For example:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
vm->bind__next__(type, [](VM* vm, PyObject* _0){
|
||||||
|
// ...
|
||||||
|
PyObject* a = VAR(1);
|
||||||
|
PyObject* b = VAR(2);
|
||||||
|
return VAR(Tuple(a, b));
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
```python
|
||||||
|
for a, b in my_iter:
|
||||||
|
# There is tuple creation and destruction for each iteration
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
It is not efficient because unnecessary tuple creation and destruction are involved.
|
||||||
|
In `v1.5.0`, you need to use stack-based style to reimplement the above code:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
vm->bind__next__(type, [](VM* vm, PyObject* _0) -> unsigned{
|
||||||
|
// ...
|
||||||
|
PyObject* a = VAR(1);
|
||||||
|
PyObject* b = VAR(2);
|
||||||
|
vm->s_data.push(a); // directly push to the stack
|
||||||
|
vm->s_data.push(b); // directly push to the stack
|
||||||
|
return 2; // return the number of values
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
In this way, the interpreter only creates a tuple when it is necessary.
|
||||||
|
It can improve ~25% performance when iterating over a large array.
|
||||||
|
|
||||||
|
```python
|
||||||
|
for a, b in my_iter:
|
||||||
|
# No tuple creation and destruction
|
||||||
|
...
|
||||||
|
|
||||||
|
for t in my_iter:
|
||||||
|
# Create a tuple lazily
|
||||||
|
...
|
||||||
```
|
```
|
Loading…
x
Reference in New Issue
Block a user