From 24e6b162c896cc7c7acadd761d31aa91d7ad5dbc Mon Sep 17 00:00:00 2001 From: blueloveTH Date: Sat, 30 Sep 2023 12:07:44 +0800 Subject: [PATCH] ... --- docs/{quick-start/bind.md => bindings.md} | 113 +++++++++++++++++++++- docs/performance.md | 14 +-- docs/plugins.zip | Bin 3524 -> 0 bytes docs/quick-start/index.yml | 1 - docs/quick-start/wrap.md | 106 -------------------- 5 files changed, 116 insertions(+), 118 deletions(-) rename docs/{quick-start/bind.md => bindings.md} (51%) delete mode 100644 docs/plugins.zip delete mode 100644 docs/quick-start/wrap.md diff --git a/docs/quick-start/bind.md b/docs/bindings.md similarity index 51% rename from docs/quick-start/bind.md rename to docs/bindings.md index 620d7de5..e35cf364 100644 --- a/docs/quick-start/bind.md +++ b/docs/bindings.md @@ -1,9 +1,13 @@ --- -icon: dot -label: 'Bind native function' -order: 60 +icon: star +title: Write bindings +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. This function pointer has the following signature: @@ -100,4 +104,105 @@ vm->bind__add__(type, __add__); 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__", ...)`. \ No newline at end of file +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. \ No newline at end of file diff --git a/docs/performance.md b/docs/performance.md index 2fb8a19e..481edcfb 100644 --- a/docs/performance.md +++ b/docs/performance.md @@ -6,13 +6,11 @@ label: Performance # Performance -Currently, pkpy is completely faster than cpython 3.8. -Here is a benchmark result of the current commit. - -Benchmark files are located in `benchmarks/`. - -See [actions/runs](https://github.com/blueloveTH/pocketpy/actions/runs/5113363233/jobs/9192476164). +Currently, pkpy is as fast as cpython 3.8. +**Performance results for cpython 3.8 are applicable to for pkpy.** +Here is a benchmark result of `v1.0.0`. +Files are located in `benchmarks/`. ``` Testing directory: benchmarks/ @@ -47,4 +45,6 @@ Testing directory: benchmarks/ cpython: 0.020165s (100%) pocketpy: 0.004495s (22.29%) ALL TESTS PASSED -``` \ No newline at end of file +``` + +See [actions/runs](https://github.com/blueloveTH/pocketpy/actions/runs/5113363233/jobs/9192476164). \ No newline at end of file diff --git a/docs/plugins.zip b/docs/plugins.zip deleted file mode 100644 index 57ff7e03bc74f5cd3c2f1ce0b4ac9ce58b86b9af..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3524 zcmZ{n2T)U47snGI1VRrWAOSQ;krqm5QVfP(q=-?f^xiv4m0kpc^sbPlNSEq@ROwwK zT}lK&P>{Ox4|iu*cXqz}-n{efn>)Y%n|I!wbN)IS#3T^FpTjN<^ViK^SF(%X=HzW_ z@8XHjxmd+;F((5MKS{@&lr!h~0|9_+A^?E$msOTR&Q{)7Bkc|pZNz-m?#+0vNDIgw zG%#cfPIm}=!-7uxijv&GO|e1=!M-z(&7uRRhqHHv)P~)p;yIO5V8nO1y6JfMKUuDh z9Jv>I#XO`;bbsH!WLJS4%vVe_#usamK3WcelH;b;DpbkqZ}B=PHQ2467W1LhbZ&R@ zzoKX$dIF14DDERwp{l8=mmtW_3mY}zqxrCvjT8Ziu5l-1{WS8=JT1m1yQkLM#YEye z26*Vidu%WaASzbw>%LsKJRnI(M{Yr~4yzk~#B!27$nDg$L=gc;YQ4k3!1DC2+od8&61HBXhIcI?lMr#Y@seG#Rw z?LO5^B+|yo+sn(^<04Tx_nkdwB%o&jnPb6|r8#us)y3CZkaBN* z9QlXe`+C2O@#veaWg~}Qr4v`(0_Y%y{%G}Ox}v0q$!yvIV~sbC<$njr!l-{|qbqTu z#K!tJa84x+h%{p(>WqD5)O(B*7uQ{Ss(oZ01d%sn;Q55${QAm;J0~?WKq*_Zh?J8T zl7gvns>lZ>yHH0@G4?0h7A)NXV*LhQBOhktJs9Uavo;^O`3sGUGqd4mRmrsAjqzH% z4CILtR54@Ahtbc6cIXVg`F!N+Kncaw^#zL|II=T!Sh2TKSladB>hEThyw7uO4pI_qK7v zFzV`cTyxyx@CGx+X|dGjSB;L>tS-eVHM~j^!iOjj#aR|RB@YM@Tn~dOp8LmQnYC{% zvEml_;_9FxV`l{r)hTw-VM|emMsMmAfvtDz!R?WbVWHz5n}@HqHWvqq5D%LD&Jx-4 zD-_Gy zc|+kCJ}XKi+@?9dK#+miRBixbyNYW!6tQ+(H*KR=%{&!i&tH{)31f)U!P`A~Nb7`E zSJ5zVE0H*vqlxN&f=tV1A<4H&WnGUykvT?xy3*?tANX|Byn1;6%P;_HS8g|Dyj-i7 z+8;*+G#X@xis-d?LqVU_4^m~scE7GNkKQaUP#)S`iLSEd{_5i(h||fa@+BWZEz3Hx z!gl6JkhwF`qV;-WI}*TLW#Q!HF+MY^?lL7M`fWhJ8W^Z z!Mkt$G7`oHdf$oJrL3UWoOFibwyW&G);9|Nsrd8}C8Ri~k5lr!sZ<`p`0H3g5p&myD}svg%1yjPnVZwTqu{y~tGVC$O>%+IvoW-*(xu(JvX2;0ePH?gNJy=xPEbTf zU4-|*r+&ptlqY3)C7+bf_c_BkW>dJMlZulQ7hSYB!+=U>Ch^{>I3ZOY`~@Zy`}ofm6Z@C92yi!;Hz?W*PYo z;Jxdv0?8c!GJLT^G~{|Bn8-bsnY0JOYniKV|8g?sveUR>7iXvO@fpQj*#Ml~f<`N) z+7+pBNK!NpeGVhR6q1A>Zz`g{+{?@=9As$=3-(|2p*BES`_3{uMdZVDFTFFh4L{Z= zQ9zfEcs1gQm|(|6ds!A45Sey+jAQ-bj>>nt;iiuafmXYRl| zs~zFjvZQlaSG?S?o?W()J=a4uyi2LW&g@3ty}qv?_XTYpq_@vK^fhR7xG!|M8s_u% z^C!DtsgyIHCL^|$>h**Dh0LImh>{g-aDAKEhUs|y>SvC<(|F!?h`+6$(B;lou3rXc zZrKXQO~xjKDntNfxgLl$Uo&a?97=h11L?9#eN^dRdKC65wkXJ`)bD2G^|%scDz>Jg zr_R>z6qLVuhv^yT?);pdc9!V^Ag9GmPe>V zhZ!u}Dhf+I8YIL@?I+R?=zB3$NG_S8`|j=2ZB}pZHyqzMIebW~yyRFXvn{*mw@^!x z+d8_%GR35AG+VB?s2~}LJ|L*DyzH51lpaXX59GGJKGSqP94KoTC!Ij;>s2Z2uOaqj zFEpSudbyP@NJzlses)`3K~5Qui+$<~82UWY<*V@A3`r%#OY|%K`MC-5GRQA;>4;wX zd`0SWnM=-VOZZXZ;~))qk%m6oU?Gac@gcS`bx zN3h!&zM>5~iPXDuP`xM>61k+RNKECLx@E`zy_Ls8l z?PBlce^IpS^tH5SP_!*Z+ri8c#0dZyYPzV=E4u3Zg)fu^clGXCJ8LH~uFv6v3S;=r z9{IKmgUt#}Gtu(hJ0F`5d?a{yc-$2=+Iw_jA%tiw(G>GHX>rHK70-SX-C_uyS=s&l zZqHadaMrCr(OLryI>43ia*SzC2-BBFq=lnHQB4xzB4uW3YR9X3j>xScvWOBDL_GFk zwsqHp_nrDTB7#aeYI^cX(qA;iWJV$jWI3p1i|=~0!0W8Y!e*J++1b@wuBdlo@yR2d zZ3~}fB~^`t4R7_$3N)gfNu}c#F>c@4nXJ?z?z->tB($~E4BB7o2jF!`X+Sr^$ZSG| z3)ETDuj_H%H=qjx)-lvV8Vfo21Wh#jaie=g?*6=%)qcZ#%Ah$iV0@ zK&g4z2CV*&8v8T|-L!TZ5|LAs_g0qt>*9S zVFzeNMJw_OtwIJx!4achl8ZSU{~Pp!#z2jUs4LD;$5i@wMDfsYoL|7YyWD4!`C+#+ z_E;00~o{|H%p_kFp|q@w{O;sE?V$8hc9pZzgtulyPQX*(f+za9Vq z%m6AaKJR?*Dc}aWj4$113TXJcgZ9V#FY^C$8Gnbind_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. \ No newline at end of file