Compare commits

...

16 Commits

Author SHA1 Message Date
BLUELOVETH
4ba0b7d2e2
Update pybind11.md 2024-06-19 16:19:20 +08:00
BLUELOVETH
2d6def4bbd
Merge pull request #285 from 16bit-ykiko/pybind11-doc
update document.
2024-06-19 16:10:29 +08:00
ykiko
a5a3c75b83 fix typo. 2024-06-19 16:09:54 +08:00
ykiko
8ffcacf99f Update. 2024-06-19 16:06:16 +08:00
ykiko
a2cb91b125 update document. 2024-06-19 15:51:15 +08:00
BLUELOVETH
86006d0b61
Update migrate.md 2024-06-19 15:51:01 +08:00
BLUELOVETH
a08c5af6e9
Update migrate.md 2024-06-19 15:47:41 +08:00
BLUELOVETH
475be8ce80
Merge pull request #283 from 16bit-ykiko/doc
Update README.
2024-06-19 14:24:35 +08:00
ykiko
12d748ba7d fix format. 2024-06-19 14:15:48 +08:00
BLUELOVETH
0c1bd532f8
Merge pull request #282 from 16bit-ykiko/pybind11-fix
some fix.
2024-06-19 13:05:58 +08:00
ykiko
d52cbec80c Update README. 2024-06-19 12:32:58 +08:00
ykiko
e16aa501ef some fix. 2024-06-19 12:19:05 +08:00
blueloveTH
59bbecdbee fix versions 2024-06-19 11:06:19 +08:00
blueloveTH
f5c356a047 some fix 2024-06-19 11:04:32 +08:00
blueloveTH
68f8cd1159 Update migrate.md 2024-06-19 11:02:56 +08:00
blueloveTH
259394d7ad doc fix 2024-06-19 10:58:13 +08:00
17 changed files with 425 additions and 396 deletions

View File

@ -25,7 +25,8 @@ pkpy is extremely easy to embed via a single header file `pocketpy.h`, without e
Please see https://pocketpy.dev for details and try the following resources.
+ [Live Python Demo](https://pocketpy.dev/static/web/): Python REPL of the latest version
+ [Live C++ Examples](https://pocketpy.github.io/examples/): Common usage of pkpy in C++
> We are moving to v2.0 branch, which is a complete refactor of this project in C11. See [Migration Guide](https://pocketpy.dev/migrate/) for more details.
## Supported Platforms
@ -90,39 +91,33 @@ python scripts/run_tests.py
### Example
```cpp
#include "pocketpy.h"
#include <pybind11/pybind11.h>
using namespace pkpy;
namespace py = pybind11;
int main(){
// Create a virtual machine
VM* vm = new VM();
int main() {
// Start the interpreter
py::scoped_interpreter guard{};
// Hello world!
vm->exec("print('Hello world!')");
py::exec("print('Hello world!')");
// Create a list
vm->exec("a = [1, 2, 3]");
py::exec("a = [1, 2, 3]");
// Eval the sum of the list
PyVar result = vm->eval("sum(a)");
std::cout << "Sum of the list: "<< py_cast<int>(vm, result) << std::endl; // 6
auto result = py::eval("sum(a)");
std::cout << "Sum of the list: " << result.cast<int>() << std::endl; // 6
// Bindings
vm->bind(vm->_main, "add(a: int, b: int)",
[](VM* vm, ArgsView args){
int a = py_cast<int>(vm, args[0]);
int b = py_cast<int>(vm, args[1]);
return py_var(vm, a + b);
auto m = py::module_::__main__();
m.def("add", [](int a, int b) {
return a + b;
});
// Call the function
PyVar f_add = vm->_main->attr("add");
result = vm->call(f_add, py_var(vm, 3), py_var(vm, 7));
std::cout << "Sum of 2 variables: "<< py_cast<int>(vm, result) << std::endl; // 10
std::cout << "Sum of 2 variables: " << m.attr("add")(1, 2).cast<int>() << std::endl; // 10
// Dispose the virtual machine
delete vm;
return 0;
}
```

View File

@ -1,333 +0,0 @@
---
icon: log
title: 'Cheatsheet'
order: 22
---
## Basics
Setup pocketpy
```cpp
#include "pocketpy.h"
using namespace pkpy;
```
Create a python virtual machine
```cpp
VM* vm = new VM();
```
Dispose a python virtual machine
```cpp
delete vm;
```
Execute a source string
```cpp
vm->exec("print('Hello!')");
```
Evaluate a source string
```cpp
PyVar obj = vm->eval("123");
std::cout << py_cast<int>(vm, obj); // 123
```
Compile a source string into a code object
```cpp
CodeObject_ co = vm->compile("print('Hello!')", "main.py", EXEC_MODE);
```
Execute a compiled code object
```cpp
try{
vm->_exec(co); // may throw
}catch(Exception& e){
std::cerr << e.summary() << std::endl;
}
```
## Interop with native types
Create primitive objects
```cpp
PyVar obj;
obj = py_var(vm, 1); // create a int
obj = py_var(vm, 1.0); // create a float
obj = py_var(vm, "123"); // create a string
obj = py_var(vm, true); // create a bool
```
Create a tuple object
```cpp
// obj = (1, 1.0, '123')
Tuple t(3);
t[0] = py_var(vm, 1);
t[1] = py_var(vm, 1.0);
t[2] = py_var(vm, "123");
PyVar obj = py_var(vm, std::move(t));
```
Create a list object
```cpp
// obj = [1, 1.0, '123']
List t;
t.push_back(py_var(vm, 1));
t.push_back(py_var(vm, 1.0));
t.push_back(py_var(vm, "123"));
PyVar obj = py_var(vm, std::move(t));
```
Create a dict object
```cpp
// obj = {'x': 1, 'y': '123'}
Dict d(vm);
d.set(py_var(vm, "x"), py_var(vm, 1));
d.set(py_var(vm, "y"), py_var(vm, "123"));
PyVar obj = py_var(vm, std::move(d));
```
Get native types from python objects
```cpp
PyVar obj;
i64 a = py_cast<i64>(vm, obj);
f64 b = py_cast<f64>(vm, obj);
Str& c = py_cast<Str&>(vm, obj); // reference cast
bool d = py_cast<bool>(vm, obj);
Tuple& e = py_cast<Tuple&>(vm, obj); // reference cast
List& f = py_cast<List&>(vm, obj); // reference cast
Dict& g = py_cast<Dict&>(vm, obj); // reference cast
```
Get native types without type checking
```cpp
// unsafe version 1 (for int object you must use `_py_cast`)
i64 a = _py_cast<i64>(vm, obj);
f64 b = _py_cast<f64>(vm, obj);
Tuple& c = _py_cast<Tuple&>(vm, obj);
// unsafe version 2 (for others, you can also use `PK_OBJ_GET` macro)
Str& a_ = PK_OBJ_GET(Str, obj);
List& b_ = PK_OBJ_GET(List, obj);
Tuple& c_ = PK_OBJ_GET(Tuple, obj);
```
## Access python types
Access built-in python types
```cpp
PyVar int_t = vm->_t(VM::tp_int);
PyVar float_t = vm->_t(VM::tp_float);
PyVar object_t = vm->_t(VM::tp_object);
PyVar tuple_t = vm->_t(VM::tp_tuple);
PyVar list_t = vm->_t(VM::tp_list);
```
Access user registered types
```cpp
Type voidp_t = vm->_tp_user<VoidP>();
```
Check if an object is a python type
```cpp
PyVar obj;
bool ok = is_type(obj, VM::tp_int); // check if obj is an int
```
Get the type of a python object
```cpp
PyVar obj = py_var(vm, 1);
PyVar t = vm->_t(obj); // <class 'int'>
Type type = vm->_tp(obj); // VM::tp_int
```
Convert a type object into a type index
```cpp
PyVar int_t = vm->_t(VM::tp_int);
Type t = PK_OBJ_GET(Type, int_t);
// t == VM::tp_int
```
## Access attributes
Check an object supports attribute access
```cpp
PyVar obj;
bool ok = !is_tagged(obj) && obj->is_attr_valid();
```
```python
class MyClass:
def __init__(self, x, y):
self.x = x
self.y = y
def sum(self):
return self.x + self.y
```
Get and set attributes
```cpp
PyVar obj = vm->exec("MyClass(1, 2)");
PyVar x = vm->getattr(obj, "x"); // obj.x
vm->setattr(obj, "x", py_var(vm, 3)); // obj.x = 3
```
## Call python functions
```python
def add(a, b):
return a + b
```
Call a function
```cpp
PyVar f_add = vm->eval("add");
PyVar ret = vm->call(f_add, py_var(vm, 1), py_var(vm, 2));
std::cout << py_cast<int>(vm, ret); // 3
```
Call a method
```cpp
PyVar obj = vm->exec("MyClass(1, 2)");
PyVar ret = vm->call_method(obj, "sum");
std::cout << CAST(i64, ret); // 3
```
Cache the name of a function or method to avoid string-based lookup
```cpp
// cache the name "add" to avoid string-based lookup
const static StrName m_sum("sum");
PyVar ret = vm->call_method(obj, m_sum);
```
## Special operations
Compare two python objects
```cpp
PyVar obj1 = py_var(vm, 1);
PyVar obj2 = py_var(vm, 2);
bool ok = vm->py_eq(obj1, obj2);
```
Convert a python object to string
```cpp
PyVar obj = py_var(vm, 123);
std::cout << vm->py_str(obj); // 123
```
Get the string representation of a python object
```cpp
PyVar obj = py_var(vm, "123");
std::cout << vm->py_repr(obj); // "'123'"
```
Get the JSON representation of a python object
```cpp
PyVar obj = py_var(vm, 123);
std::cout << vm->py_json(obj); // "123"
```
Get the hash value of a python object
```cpp
PyVar obj = py_var(vm, 1);
i64 h = vm->py_hash(obj); // 1
```
Get the iterator of a python object
```cpp
PyVar obj = vm->eval("range(3)");
PyVar iter = vm->py_iter(obj);
```
Get the next item of an iterator
```cpp
PyVar obj = vm->py_next(iter);
if(obj == vm->StopIteration){
// end of iteration
}else{
// process obj
}
```
Convert a python iterable to a list
```cpp
PyVar obj = vm->eval("range(3)");
List list = vm->py_list(obj);
```
## Bindings
Bind a native function
```cpp
vm->bind(obj, "add(a: int, b: int) -> int", [](VM* vm, ArgsView args){
int a = py_cast<int>(vm, args[0]);
int b = py_cast<int>(vm, args[1]);
return py_var(vm, a + b);
});
```
Bind a property
```cpp
// getter and setter of property `x`
vm->bind_property(type, "x: int",
[](VM* vm, ArgsView args){
Point& self = PK_OBJ_GET(Point, args[0]);
return VAR(self.x);
},
[](VM* vm, ArgsView args){
Point& self = PK_OBJ_GET(Point, args[0]);
self.x = py_cast<int>(vm, args[1]);
return vm->None;
});
```
## Modules
Create a source module
```cpp
vm->_lazy_modules["test"] = "pi = 3.14";
// import test
// print(test.pi) # 3.14
```
Create a native module
```cpp
PyVar mod = vm->new_module("test");
vm->setattr(mod, "pi", py_var(vm, 3.14));
```

View File

@ -5,6 +5,12 @@ label: Welcome
# Welcome to pocketpy
!!!
We are moving to v2.0 branch, which is a complete refactor of this project in C11.
See [Migration Guide](migrate.md) for more details.
!!!
pkpy is a lightweight(~15K LOC) Python interpreter for game scripting, built on C++17 with STL.
It aims to be an alternative to lua for game scripting, with elegant syntax, powerful features and competitive performance.

32
docs/migrate.md Normal file
View File

@ -0,0 +1,32 @@
---
icon: log
title: 'Migration Guide'
order: 22
---
## Overview
v2.0 branch is a complete refactor of pocketpy in C11,
which enables users to run pocketpy on platforms that do not support C++.
Also we redesign the core interpreter to be more efficient and maintainable
by using modern C11 language features.
> v2.0 will be released on 2024/08.
## API compatibility
| name | v1.x | v2.0 |
| --- | --- | --- |
| legacy C++ API (v1.x only) | ✅ | ❌ |
| legacy C API (v1.x only) | ✅ | ❌ |
| C11 API (v2.0 only) | ❌ | ✅ (work-in-progress) |
| pybind11 API (both) | ✅ | ✅ (work-in-progress) |
## Suggestions
- If you are a C++ user
- Use **pybind11 API** if you want to upgrade to v2.0 in the future
- Use **legacy C++ API** if you want to stay in v1.x
- If you are a C user
- Use **v2.0's C11 API** (will be available soon)
- Use **legacy C API** if you want to stay in v1.x

291
docs/pybind11.md Normal file
View File

@ -0,0 +1,291 @@
---
icon: log
title: 'pybind11 User Guide'
order: 21
---
## Quick Start
pkpy provides a [pybind11](https://pybind11.readthedocs.io/en/stable/) compatible layer which allows users to do convenient bindings.
To begin with, use `py::scoped_interpreter guard{}` to start the interpreter before using any Python objects.
Or explicitly call `py::interpreter::initialize()` and `py::interpreter::finalize()`.
### module
```cpp
#include <pybind11/pybind11.h>
namespace py = pybind11;
PYBIND11_MODULE(example, m) {
m.def("add", [](int a, int b) {
return a + b;
});
auto math = m.def_submodule("math");
}
```
### function
```cpp
int add(int a, int b) { return a + b; }
int add(int a, int b, int c) { return a + b + c; }
void register_function(py::module_& m)
{
m.def("add", py::overload_cast<int, int>(&add));
// support function overload
m.def("add", py::overload_cast<int, int, int>(&add));
// bind with default arguments
m.def("sub", [](int a, int b) {
return a - b;
}, py::arg("a") = 1, py::arg("b") = 2);
// bind *args
m.def("add", [](py::args args) {
int sum = 0;
for (auto& arg : args) {
sum += arg.cast<int>();
}
return sum;
});
// bind **kwargs
m.def("add", [](py::kwargs kwargs) {
int sum = 0;
for (auto item : kwargs) {
sum += item.second.cast<int>();
}
return sum;
});
}
```
### class
```cpp
struct Point
{
const int x;
int y;
public:
Point() : x(0), y(0) {}
Point(int x, int y) : x(x), y(y) {}
Point(const Point& p) : x(p.x), y(p.y) {}
std::string stringfy() const {
return "(" + std::to_string(x) + ", " + std::to_string(y) + ")";
}
};
struct Point3D : Point
{
private:
int z;
public:
Point3D(int x, int y, int z) : Point(x, y), z(z) {}
int get_z() const { return z; }
void set_z(int z) { this->z = z; }
};
void bind_class(py::module_& m)
{
py::class_<Point>(m, "Point")
.def(py::init<>())
.def(py::init<int, int>())
.def(py::init<const Point&>())
.def_readonly("x", &Point::x)
.def_readwrite("y", &Point::y)
.def("__str__", &Point::stringfy);
// only support single inheritance
py::class_<Point3D, Point>(m, "Point3D", py::dynamic_attr())
.def(py::init<int, int, int>())
.def_property("z", &Point3D::get_z, &Point3D::set_z);
// dynamic_attr will enable the dict of bound class
}
```
### operators
```cpp
#include <pybind11/operators.h>
namespace py = pybind11;
struct Int {
int value;
Int(int value) : value(value) {}
Int operator+(const Int& other) const {
return Int(value + other.value);
}
Int operator-(const Int& other) const {
return Int(value - other.value);
}
bool operator==(const Int& other) const {
return value == other.value;
}
bool operator!=(const Int& other) const {
return value != other.value;
}
};
void bind_operators(py::module_& m)
{
py::class_<Int>(m, "Int")
.def(py::init<int>())
.def(py::self + py::self)
.def(py::self - py::self)
.def(py::self == py::self)
.def(py::self != py::self);
// other operators are similar
}
```
### py::object
`py::object` is just simple wrapper around `PyVar`. It supports some convenient methods to interact with Python objects.
here are some common methods:
```cpp
obj.attr("x"); // access attribute
obj[1]; // access item
obj.is_none(); // same as obj is None in Python
obj.is(obj2); // same as obj is obj2 in Python
// operators
obj + obj2; // same as obj + obj2 in Python
// ...
obj == obj2; // same as obj == obj2 in Python
// ...
obj(...); // same as obj.__call__(...)
py::cast(obj); // cast to Python object
obj.cast<T>; // cast to C++ type
py::type::of(obj); // get type of obj
py::type::of<T>(); // get type of T, if T is registered
```
you can also create some builtin objects with their according wrappers:
```cpp
py::bool_ b = {true};
py::int_ i = {1};
py::float_ f = {1.0};
py::str s = {"hello"};
py::list l = {1, 2, 3};
py::tuple t = {1, 2, 3};
// ...
```
## More Examples
More examples please see the test [folder](https://github.com/pocketpy/gsoc-2024-dev/tree/main/pybind11/tests) in the GSoC repository. All tested features are supported.
## Limits and Comparison
This is a feature list of pybind11 for pocketpy. It lists all completed and pending features. It also lists the features that cannot be implemented in the current version of pocketpy.
### [Function](https://pybind11.readthedocs.io/en/stable/advanced/functions.html)
- [x] Function overloading
- [x] Return value policy
- [x] is_prepend
- [x] `*args` and `**kwargs`
- [ ] Keep-alive
- [ ] Call Guard
- [x] Default arguments
- [ ] Keyword-Only arguments
- [ ] Positional-Only arguments
- [ ] Allow/Prohibiting None arguments
### [Class](https://pybind11.readthedocs.io/en/stable/classes.html)
- [x] Creating bindings for a custom type
- [x] Binding lambda functions
- [x] Dynamic attributes
- [x] Inheritance and automatic downcasting
- [x] Enumerations and internal types
- [ ] Instance and static fields
> Binding static fields may never be implemented in pocketpy because it requires a metaclass, which is a heavy and infrequently used feature.
### [Exceptions](https://pybind11.readthedocs.io/en/stable/advanced/exceptions.html)
Need further discussion.
### [Smart pointers](https://pybind11.readthedocs.io/en/stable/advanced/smart_ptrs.html)
- [ ] std::shared_ptr
- [ ] std::unique_ptr
- [ ] Custom smart pointers
### [Type conversions](https://pybind11.readthedocs.io/en/stable/advanced/cast/index.html)
- [x] Python built-in types
- [x] STL Containers
- [ ] Functional
- [ ] Chrono
### [Python C++ interface](https://pybind11.readthedocs.io/en/stable/advanced/pycpp/object.html)
Need further discussion.
- [x] `object`
- [x] `none`
- [x] `type`
- [x] `bool_`
- [x] `int_`
- [x] `float_`
- [x] `str`
- [ ] `bytes`
- [ ] `bytearray`
- [x] `tuple`
- [x] `list`
- [ ] `set`
- [x] `dict`
- [ ] `slice`
- [x] `iterable`
- [x] `iterator`
- [ ] `function`
- [ ] `buffer`
- [ ] `memoryview`
- [x] `capsule`
### [Miscellaneous](https://pybind11.readthedocs.io/en/stable/advanced/misc.html)
- [ ] Global Interpreter Lock (GIL)
- [ ] Binding sequence data types, iterators, the slicing protocol, etc.
- [x] Convenient operators binding
### Differences between CPython and pocketpy
- only `add`, `sub` and `mul` have corresponding right versions in pocketpy. So if you bind `int() >> py::self`, it will has no effect in pocketpy.
- `__new__` and `__del__` are not supported in pocketpy.
- in-place operators, such as `+=`, `-=`, `*=`, etc., are not supported in pocketpy.
- thre return value of `globals` is immutable in pocketpy.

View File

@ -3,7 +3,7 @@ output: .retype
url: https://pocketpy.dev
branding:
title: pocketpy
label: v1.5.0
label: v1.4.6
logo: "./static/logo.png"
favicon: "./static/logo.png"
meta:
@ -16,10 +16,10 @@ links:
icon: play
link: "https://pocketpy.dev/static/web/"
target: blank
- text: "Live Examples"
icon: play
link: "https://pocketpy.github.io/examples/"
target: blank
# - text: "Live Examples"
# icon: play
# link: "https://pocketpy.github.io/examples/"
# target: blank
- text: "Github"
icon: mark-github
link: https://github.com/blueloveth/pocketpy

View File

@ -20,10 +20,10 @@
#include <typeindex>
#include <initializer_list>
#define PK_VERSION "1.5.0"
#define PK_VERSION "1.4.6"
#define PK_VERSION_MAJOR 1
#define PK_VERSION_MINOR 5
#define PK_VERSION_PATCH 0
#define PK_VERSION_MINOR 4
#define PK_VERSION_PATCH 6
#include "config.h"
#include "export.h"

View File

@ -81,9 +81,13 @@ inline bool isinstance(const handle& obj, const handle& type) {
inline int64_t hash(const handle& obj) { return vm->py_hash(obj.ptr()); }
namespace impl {
template <typename T, typename SFINAE = void>
struct type_caster;
}
template <typename T>
handle cast(T&& value, return_value_policy policy, handle parent) {
// decay_t can resolve c-array type, but remove_cv_ref_t can't.
@ -107,7 +111,7 @@ handle cast(T&& value, return_value_policy policy, handle parent) {
: return_value_policy::move;
}
return type_caster<underlying_type>::cast(std::forward<T>(value), policy, parent);
return impl::type_caster<underlying_type>::cast(std::forward<T>(value), policy, parent);
}
}
@ -115,7 +119,7 @@ template <typename T>
T cast(const handle& obj, bool convert) {
assert(obj.ptr() != nullptr);
type_caster<T> caster = {};
impl::type_caster<T> caster = {};
if(caster.load(obj, convert)) {
return caster.value;

View File

@ -2,7 +2,7 @@
#include "instance.h"
#include "accessor.h"
namespace pybind11 {
namespace pybind11::impl {
using pkpy::is_floating_point_v;
using pkpy::is_integral_v;

View File

@ -169,15 +169,15 @@ public:
}
enum_& value(const char* name, T value) {
handle var = type_caster<T>::cast(value, return_value_policy::copy);
this->m_ptr->attr().set(name, var.ptr());
handle var = pybind11::cast(value, return_value_policy::copy);
setattr(*this, name, var);
m_values.emplace_back(name, var);
return *this;
}
enum_& export_values() {
for(auto& [name, value]: m_values) {
Base::m_scope.ptr()->attr().set(name, value.ptr());
setattr(Base::m_scope, name, value);
}
return *this;
}

View File

@ -176,7 +176,7 @@ public:
template <typename Fn, std::size_t... Is, typename... Args>
handle invoke(Fn&& fn,
std::index_sequence<Is...>,
std::tuple<type_caster<Args>...>& casters,
std::tuple<impl::type_caster<Args>...>& casters,
return_value_policy policy,
handle parent) {
using underlying_type = std::decay_t<Fn>;
@ -361,10 +361,10 @@ struct template_parser<Callable, std::tuple<Extras...>, std::tuple<Args...>, std
// resolve keyword arguments
const auto n = vm->s_data._sp - view.end();
std::size_t index = 0;
int index = 0;
if constexpr(named_argc > 0) {
std::size_t arg_index = 0;
int arg_index = 0;
auto& arguments = *record.arguments;
while(arg_index < named_argc && index < n) {
@ -403,7 +403,7 @@ struct template_parser<Callable, std::tuple<Extras...>, std::tuple<Args...>, std
}
// ok, all the arguments are valid, call the function
std::tuple<type_caster<Args>...> casters;
std::tuple<impl::type_caster<Args>...> casters;
// check type compatibility
if(((std::get<Is>(casters).load(stack[Is], convert)) && ...)) {
@ -489,14 +489,14 @@ pkpy::PyVar setter_wrapper(pkpy::VM* vm, pkpy::ArgsView view) {
if constexpr(std::is_member_object_pointer_v<Setter>) {
// specialize for pointer to data member
type_caster<member_type_t<Setter>> caster;
impl::type_caster<member_type_t<Setter>> caster;
if(caster.load(view[1], true)) {
self.*setter = caster.value;
return vm->None;
}
} else {
// specialize for pointer to member function
type_caster<std::tuple_element_t<1, callable_args_t<Setter>>> caster;
impl::type_caster<std::tuple_element_t<1, callable_args_t<Setter>>> caster;
if(caster.load(view[1], true)) {
(self.*setter)(caster.value);
return vm->None;
@ -507,7 +507,7 @@ pkpy::PyVar setter_wrapper(pkpy::VM* vm, pkpy::ArgsView view) {
using Self = remove_cvref_t<std::tuple_element_t<0, callable_args_t<Setter>>>;
auto& self = handle(view[0])._as<instance>()._as<Self>();
type_caster<std::tuple_element_t<1, callable_args_t<Setter>>> caster;
impl::type_caster<std::tuple_element_t<1, callable_args_t<Setter>>> caster;
if(caster.load(view[1], true)) {
setter(self, caster.value);
return vm->None;

View File

@ -37,7 +37,7 @@ class handle;
class object;
class iterator;
class str;
class arg;
struct arg;
struct args_proxy;
struct kwargs_proxy;
@ -210,12 +210,7 @@ constexpr inline bool is_pyobject_v = std::is_base_of_v<object, T>;
#if PK_VERSION_MAJOR == 2
using error_already_set = pkpy::TopLevelException;
#else
class error_already_set : std::exception {
public:
error_already_set() = default;
const char* what() const noexcept override { return "An error occurred while calling a Python function."; }
};
using error_already_set = pkpy::Exception;
#endif
inline void setattr(const handle& obj, const handle& name, const handle& value);

View File

@ -19,8 +19,10 @@ public:
}
module_ def_submodule(const char* name, const char* doc = nullptr) {
auto package = this->package()._as<pkpy::Str>() + "." + this->name()._as<pkpy::Str>();
auto m = vm->new_module(name, package);
// TODO: resolve package
//auto package = this->package()._as<pkpy::Str>() + "." + this->name()._as<pkpy::Str>();
auto fname = this->name()._as<pkpy::Str>() + "." + name;
auto m = vm->new_module(fname, "");
setattr(*this, name, m);
return m;
}

View File

@ -69,6 +69,9 @@ public:
template <typename T>
decltype(auto) _as() const {
static_assert(!std::is_reference_v<T>, "T must not be a reference type.");
if constexpr(std::is_same_v<T, empty>) {
return empty();
} else {
#if PK_VERSION_MAJOR == 2
if constexpr(pkpy::is_sso_v<T>) {
return pkpy::_py_cast<T>(vm, ptr());
@ -79,6 +82,7 @@ public:
return (((pkpy::Py_<T>*)ptr())->_value);
#endif
}
}
};
/// a lightweight wrapper for python objects

View File

@ -25,9 +25,9 @@ struct function_traits {
static_assert(dependent_false<Fn>, "unsupported function type");
};
#define PYBIND11_FUNCTION_TRAITS_SPECIALIZE(qualifiers) \
#define PYBIND11_FUNCTION_TRAITS_SPECIALIZE(...) \
template <typename R, typename... Args> \
struct function_traits<R(Args...) qualifiers> { \
struct function_traits<R(Args...) __VA_ARGS__> { \
using return_type = R; \
using args_type = std::tuple<Args...>; \
constexpr static std::size_t args_count = sizeof...(Args); \
@ -167,4 +167,32 @@ constexpr auto type_name() {
#endif
}
template <typename... Args>
struct overload_cast_t {
template <typename Return>
constexpr auto operator() (Return (*pf)(Args...)) const noexcept -> decltype(pf) {
return pf;
}
template <typename Return, typename Class>
constexpr auto operator() (Return (Class::*pmf)(Args...), std::false_type = {}) const noexcept -> decltype(pmf) {
return pmf;
}
template <typename Return, typename Class>
constexpr auto operator() (Return (Class::*pmf)(Args...) const, std::true_type) const noexcept -> decltype(pmf) {
return pmf;
}
};
/// Syntax sugar for resolving overloaded function pointers:
/// - regular: static_cast<Return (Class::*)(Arg0, Arg1, Arg2)>(&Class::func)
/// - sweet: overload_cast<Arg0, Arg1, Arg2>(&Class::func)
template <typename... Args>
constexpr inline overload_cast_t<Args...> overload_cast;
/// Const member function selector for overload_cast
/// - regular: static_cast<Return (Class::*)(Arg) const>(&Class::func)
/// - sweet: overload_cast<Arg>(&Class::func, const_)
constexpr static auto const_ = std::true_type{};
} // namespace pybind11

View File

@ -49,6 +49,11 @@ public:
return type_visitor::type<T>();
}
template <typename T>
static type of() {
return type_visitor::type<T>();
}
static type of(const handle& obj) { return type(vm->_t(obj.ptr())); }
};
@ -385,11 +390,11 @@ public:
};
class args : public tuple {
PYBIND11_TYPE_IMPLEMENT(tuple, struct empty, vm->tp_tuple);
PYBIND11_TYPE_IMPLEMENT(tuple, pybind11::empty, vm->tp_tuple);
};
class kwargs : public dict {
PYBIND11_TYPE_IMPLEMENT(dict, struct empty, vm->tp_dict);
PYBIND11_TYPE_IMPLEMENT(dict, pybind11::empty, vm->tp_dict);
};
} // namespace pybind11

View File

@ -9,7 +9,7 @@
#include <map>
#include <unordered_map>
namespace pybind11 {
namespace pybind11::impl {
template <typename T, std::size_t N>
struct type_caster<std::array<T, N>> {
@ -140,5 +140,5 @@ struct type_caster<T, std::enable_if_t<is_py_map_like_v<T>>> {
}
};
} // namespace pybind11
} // namespace pybind11::impl