|
@@ -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
|
|
|
|
|
+ ...
|
|
|
```
|
|
```
|