[CI] run clang-format (#24)
This commit is contained in:
@@ -18,60 +18,83 @@ NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
||||
/// @{
|
||||
|
||||
/// Annotation for methods
|
||||
struct is_method { handle class_; is_method(const handle &c) : class_(c) { } };
|
||||
struct is_method {
|
||||
handle class_;
|
||||
is_method(const handle &c) : class_(c) {}
|
||||
};
|
||||
|
||||
/// Annotation for operators
|
||||
struct is_operator { };
|
||||
struct is_operator {};
|
||||
|
||||
/// Annotation for parent scope
|
||||
struct scope { handle value; scope(const handle &s) : value(s) { } };
|
||||
struct scope {
|
||||
handle value;
|
||||
scope(const handle &s) : value(s) {}
|
||||
};
|
||||
|
||||
/// Annotation for documentation
|
||||
struct doc { const char *value; doc(const char *value) : value(value) { } };
|
||||
struct doc {
|
||||
const char *value;
|
||||
doc(const char *value) : value(value) {}
|
||||
};
|
||||
|
||||
/// Annotation for function names
|
||||
struct name { const char *value; name(const char *value) : value(value) { } };
|
||||
struct name {
|
||||
const char *value;
|
||||
name(const char *value) : value(value) {}
|
||||
};
|
||||
|
||||
/// Annotation indicating that a function is an overload associated with a given "sibling"
|
||||
struct sibling { handle value; sibling(const handle &value) : value(value.ptr()) { } };
|
||||
/// Annotation indicating that a function is an overload associated with a given
|
||||
/// "sibling"
|
||||
struct sibling {
|
||||
handle value;
|
||||
sibling(const handle &value) : value(value.ptr()) {}
|
||||
};
|
||||
|
||||
/// Annotation indicating that a class derives from another given type
|
||||
template <typename T> struct base {
|
||||
PYBIND11_DEPRECATED("base<T>() was deprecated in favor of specifying 'T' as a template argument to class_")
|
||||
base() { }
|
||||
PYBIND11_DEPRECATED("base<T>() was deprecated in favor of specifying 'T' as "
|
||||
"a template argument to class_")
|
||||
base() {}
|
||||
};
|
||||
|
||||
/// Keep patient alive while nurse lives
|
||||
template <size_t Nurse, size_t Patient> struct keep_alive { };
|
||||
template <size_t Nurse, size_t Patient> struct keep_alive {};
|
||||
|
||||
/// Annotation indicating that a class is involved in a multiple inheritance relationship
|
||||
struct multiple_inheritance { };
|
||||
/// Annotation indicating that a class is involved in a multiple inheritance
|
||||
/// relationship
|
||||
struct multiple_inheritance {};
|
||||
|
||||
/// Annotation which enables dynamic attributes, i.e. adds `__dict__` to a class
|
||||
struct dynamic_attr { };
|
||||
struct dynamic_attr {};
|
||||
|
||||
/// Annotation which enables the buffer protocol for a type
|
||||
struct buffer_protocol { };
|
||||
struct buffer_protocol {};
|
||||
|
||||
/// Annotation which requests that a special metaclass is created for a type
|
||||
struct metaclass {
|
||||
handle value;
|
||||
handle value;
|
||||
|
||||
PYBIND11_DEPRECATED("py::metaclass() is no longer required. It's turned on by default now.")
|
||||
metaclass() {}
|
||||
PYBIND11_DEPRECATED(
|
||||
"py::metaclass() is no longer required. It's turned on by default now.")
|
||||
metaclass() {}
|
||||
|
||||
/// Override pybind11's default metaclass
|
||||
explicit metaclass(handle value) : value(value) { }
|
||||
/// Override pybind11's default metaclass
|
||||
explicit metaclass(handle value) : value(value) {}
|
||||
};
|
||||
|
||||
/// Annotation that marks a class as local to the module:
|
||||
struct module_local { const bool value; constexpr module_local(bool v = true) : value(v) { } };
|
||||
struct module_local {
|
||||
const bool value;
|
||||
constexpr module_local(bool v = true) : value(v) {}
|
||||
};
|
||||
|
||||
/// Annotation to mark enums as an arithmetic type
|
||||
struct arithmetic { };
|
||||
struct arithmetic {};
|
||||
|
||||
/** \rst
|
||||
A call policy which places one or more guard variables (``Ts...``) around the function call.
|
||||
A call policy which places one or more guard variables (``Ts...``) around
|
||||
the function call.
|
||||
|
||||
For example, this definition:
|
||||
|
||||
@@ -92,20 +115,19 @@ template <typename... Ts> struct call_guard;
|
||||
|
||||
template <> struct call_guard<> { using type = detail::void_type; };
|
||||
|
||||
template <typename T>
|
||||
struct call_guard<T> {
|
||||
static_assert(std::is_default_constructible<T>::value,
|
||||
"The guard type must be default constructible");
|
||||
template <typename T> struct call_guard<T> {
|
||||
static_assert(std::is_default_constructible<T>::value,
|
||||
"The guard type must be default constructible");
|
||||
|
||||
using type = T;
|
||||
using type = T;
|
||||
};
|
||||
|
||||
template <typename T, typename... Ts>
|
||||
struct call_guard<T, Ts...> {
|
||||
struct type {
|
||||
T guard{}; // Compose multiple guard types with left-to-right default-constructor order
|
||||
typename call_guard<Ts...>::type next{};
|
||||
};
|
||||
template <typename T, typename... Ts> struct call_guard<T, Ts...> {
|
||||
struct type {
|
||||
T guard{}; // Compose multiple guard types with left-to-right
|
||||
// default-constructor order
|
||||
typename call_guard<Ts...>::type next{};
|
||||
};
|
||||
};
|
||||
|
||||
/// @} annotations
|
||||
@@ -115,181 +137,190 @@ NAMESPACE_BEGIN(detail)
|
||||
enum op_id : int;
|
||||
enum op_type : int;
|
||||
struct undefined_t;
|
||||
template <op_id id, op_type ot, typename L = undefined_t, typename R = undefined_t> struct op_;
|
||||
inline void keep_alive_impl(size_t Nurse, size_t Patient, function_call &call, handle ret);
|
||||
template <op_id id, op_type ot, typename L = undefined_t,
|
||||
typename R = undefined_t>
|
||||
struct op_;
|
||||
inline void keep_alive_impl(size_t Nurse, size_t Patient, function_call &call,
|
||||
handle ret);
|
||||
|
||||
/// Internal data structure which holds metadata about a keyword argument
|
||||
struct argument_record {
|
||||
const char *name; ///< Argument name
|
||||
const char *descr; ///< Human-readable version of the argument value
|
||||
handle value; ///< Associated Python object
|
||||
bool convert : 1; ///< True if the argument is allowed to convert when loading
|
||||
bool none : 1; ///< True if None is allowed when loading
|
||||
const char *name; ///< Argument name
|
||||
const char *descr; ///< Human-readable version of the argument value
|
||||
handle value; ///< Associated Python object
|
||||
bool convert : 1; ///< True if the argument is allowed to convert when loading
|
||||
bool none : 1; ///< True if None is allowed when loading
|
||||
|
||||
argument_record(const char *name, const char *descr, handle value, bool convert, bool none)
|
||||
: name(name), descr(descr), value(value), convert(convert), none(none) { }
|
||||
argument_record(const char *name, const char *descr, handle value,
|
||||
bool convert, bool none)
|
||||
: name(name), descr(descr), value(value), convert(convert), none(none) {}
|
||||
};
|
||||
|
||||
/// Internal data structure which holds metadata about a bound function (signature, overloads, etc.)
|
||||
/// Internal data structure which holds metadata about a bound function
|
||||
/// (signature, overloads, etc.)
|
||||
struct function_record {
|
||||
function_record()
|
||||
: is_constructor(false), is_new_style_constructor(false), is_stateless(false),
|
||||
is_operator(false), has_args(false), has_kwargs(false), is_method(false) { }
|
||||
function_record()
|
||||
: is_constructor(false), is_new_style_constructor(false),
|
||||
is_stateless(false), is_operator(false), has_args(false),
|
||||
has_kwargs(false), is_method(false) {}
|
||||
|
||||
/// Function name
|
||||
char *name = nullptr; /* why no C++ strings? They generate heavier code.. */
|
||||
/// Function name
|
||||
char *name = nullptr; /* why no C++ strings? They generate heavier code.. */
|
||||
|
||||
// User-specified documentation string
|
||||
char *doc = nullptr;
|
||||
// User-specified documentation string
|
||||
char *doc = nullptr;
|
||||
|
||||
/// Human-readable version of the function signature
|
||||
char *signature = nullptr;
|
||||
/// Human-readable version of the function signature
|
||||
char *signature = nullptr;
|
||||
|
||||
/// List of registered keyword arguments
|
||||
std::vector<argument_record> args;
|
||||
/// List of registered keyword arguments
|
||||
std::vector<argument_record> args;
|
||||
|
||||
/// Pointer to lambda function which converts arguments and performs the actual call
|
||||
handle (*impl) (function_call &) = nullptr;
|
||||
/// Pointer to lambda function which converts arguments and performs the
|
||||
/// actual call
|
||||
handle (*impl)(function_call &) = nullptr;
|
||||
|
||||
/// Storage for the wrapped function pointer and captured data, if any
|
||||
void *data[3] = { };
|
||||
/// Storage for the wrapped function pointer and captured data, if any
|
||||
void *data[3] = {};
|
||||
|
||||
/// Pointer to custom destructor for 'data' (if needed)
|
||||
void (*free_data) (function_record *ptr) = nullptr;
|
||||
/// Pointer to custom destructor for 'data' (if needed)
|
||||
void (*free_data)(function_record *ptr) = nullptr;
|
||||
|
||||
/// Return value policy associated with this function
|
||||
return_value_policy policy = return_value_policy::automatic;
|
||||
/// Return value policy associated with this function
|
||||
return_value_policy policy = return_value_policy::automatic;
|
||||
|
||||
/// True if name == '__init__'
|
||||
bool is_constructor : 1;
|
||||
/// True if name == '__init__'
|
||||
bool is_constructor : 1;
|
||||
|
||||
/// True if this is a new-style `__init__` defined in `detail/init.h`
|
||||
bool is_new_style_constructor : 1;
|
||||
/// True if this is a new-style `__init__` defined in `detail/init.h`
|
||||
bool is_new_style_constructor : 1;
|
||||
|
||||
/// True if this is a stateless function pointer
|
||||
bool is_stateless : 1;
|
||||
/// True if this is a stateless function pointer
|
||||
bool is_stateless : 1;
|
||||
|
||||
/// True if this is an operator (__add__), etc.
|
||||
bool is_operator : 1;
|
||||
/// True if this is an operator (__add__), etc.
|
||||
bool is_operator : 1;
|
||||
|
||||
/// True if the function has a '*args' argument
|
||||
bool has_args : 1;
|
||||
/// True if the function has a '*args' argument
|
||||
bool has_args : 1;
|
||||
|
||||
/// True if the function has a '**kwargs' argument
|
||||
bool has_kwargs : 1;
|
||||
/// True if the function has a '**kwargs' argument
|
||||
bool has_kwargs : 1;
|
||||
|
||||
/// True if this is a method
|
||||
bool is_method : 1;
|
||||
/// True if this is a method
|
||||
bool is_method : 1;
|
||||
|
||||
/// Number of arguments (including py::args and/or py::kwargs, if present)
|
||||
std::uint16_t nargs;
|
||||
/// Number of arguments (including py::args and/or py::kwargs, if present)
|
||||
std::uint16_t nargs;
|
||||
|
||||
/// Python method object
|
||||
PyMethodDef *def = nullptr;
|
||||
/// Python method object
|
||||
PyMethodDef *def = nullptr;
|
||||
|
||||
/// Python handle to the parent scope (a class or a module)
|
||||
handle scope;
|
||||
/// Python handle to the parent scope (a class or a module)
|
||||
handle scope;
|
||||
|
||||
/// Python handle to the sibling function representing an overload chain
|
||||
handle sibling;
|
||||
/// Python handle to the sibling function representing an overload chain
|
||||
handle sibling;
|
||||
|
||||
/// Pointer to next overload
|
||||
function_record *next = nullptr;
|
||||
/// Pointer to next overload
|
||||
function_record *next = nullptr;
|
||||
};
|
||||
|
||||
/// Special data structure which (temporarily) holds metadata about a bound class
|
||||
/// Special data structure which (temporarily) holds metadata about a bound
|
||||
/// class
|
||||
struct type_record {
|
||||
PYBIND11_NOINLINE type_record()
|
||||
: multiple_inheritance(false), dynamic_attr(false), buffer_protocol(false),
|
||||
default_holder(true), module_local(false) { }
|
||||
PYBIND11_NOINLINE type_record()
|
||||
: multiple_inheritance(false), dynamic_attr(false),
|
||||
buffer_protocol(false), default_holder(true), module_local(false) {}
|
||||
|
||||
/// Handle to the parent scope
|
||||
handle scope;
|
||||
/// Handle to the parent scope
|
||||
handle scope;
|
||||
|
||||
/// Name of the class
|
||||
const char *name = nullptr;
|
||||
/// Name of the class
|
||||
const char *name = nullptr;
|
||||
|
||||
// Pointer to RTTI type_info data structure
|
||||
const std::type_info *type = nullptr;
|
||||
// Pointer to RTTI type_info data structure
|
||||
const std::type_info *type = nullptr;
|
||||
|
||||
/// How large is the underlying C++ type?
|
||||
size_t type_size = 0;
|
||||
/// How large is the underlying C++ type?
|
||||
size_t type_size = 0;
|
||||
|
||||
/// What is the alignment of the underlying C++ type?
|
||||
size_t type_align = 0;
|
||||
/// What is the alignment of the underlying C++ type?
|
||||
size_t type_align = 0;
|
||||
|
||||
/// How large is the type's holder?
|
||||
size_t holder_size = 0;
|
||||
/// How large is the type's holder?
|
||||
size_t holder_size = 0;
|
||||
|
||||
/// The global operator new can be overridden with a class-specific variant
|
||||
void *(*operator_new)(size_t) = nullptr;
|
||||
/// The global operator new can be overridden with a class-specific variant
|
||||
void *(*operator_new)(size_t) = nullptr;
|
||||
|
||||
/// Function pointer to class_<..>::init_instance
|
||||
void (*init_instance)(instance *, const void *) = nullptr;
|
||||
/// Function pointer to class_<..>::init_instance
|
||||
void (*init_instance)(instance *, const void *) = nullptr;
|
||||
|
||||
/// Function pointer to class_<..>::dealloc
|
||||
void (*dealloc)(detail::value_and_holder &) = nullptr;
|
||||
/// Function pointer to class_<..>::dealloc
|
||||
void (*dealloc)(detail::value_and_holder &) = nullptr;
|
||||
|
||||
/// List of base classes of the newly created type
|
||||
list bases;
|
||||
/// List of base classes of the newly created type
|
||||
list bases;
|
||||
|
||||
/// Optional docstring
|
||||
const char *doc = nullptr;
|
||||
/// Optional docstring
|
||||
const char *doc = nullptr;
|
||||
|
||||
/// Custom metaclass (optional)
|
||||
handle metaclass;
|
||||
/// Custom metaclass (optional)
|
||||
handle metaclass;
|
||||
|
||||
/// Multiple inheritance marker
|
||||
bool multiple_inheritance : 1;
|
||||
/// Multiple inheritance marker
|
||||
bool multiple_inheritance : 1;
|
||||
|
||||
/// Does the class manage a __dict__?
|
||||
bool dynamic_attr : 1;
|
||||
/// Does the class manage a __dict__?
|
||||
bool dynamic_attr : 1;
|
||||
|
||||
/// Does the class implement the buffer protocol?
|
||||
bool buffer_protocol : 1;
|
||||
/// Does the class implement the buffer protocol?
|
||||
bool buffer_protocol : 1;
|
||||
|
||||
/// Is the default (unique_ptr) holder type used?
|
||||
bool default_holder : 1;
|
||||
/// Is the default (unique_ptr) holder type used?
|
||||
bool default_holder : 1;
|
||||
|
||||
/// Is the class definition local to the module shared object?
|
||||
bool module_local : 1;
|
||||
/// Is the class definition local to the module shared object?
|
||||
bool module_local : 1;
|
||||
|
||||
PYBIND11_NOINLINE void add_base(const std::type_info &base, void *(*caster)(void *)) {
|
||||
auto base_info = detail::get_type_info(base, false);
|
||||
if (!base_info) {
|
||||
std::string tname(base.name());
|
||||
detail::clean_type_id(tname);
|
||||
pybind11_fail("generic_type: type \"" + std::string(name) +
|
||||
"\" referenced unknown base type \"" + tname + "\"");
|
||||
}
|
||||
|
||||
if (default_holder != base_info->default_holder) {
|
||||
std::string tname(base.name());
|
||||
detail::clean_type_id(tname);
|
||||
pybind11_fail("generic_type: type \"" + std::string(name) + "\" " +
|
||||
(default_holder ? "does not have" : "has") +
|
||||
" a non-default holder type while its base \"" + tname + "\" " +
|
||||
(base_info->default_holder ? "does not" : "does"));
|
||||
}
|
||||
|
||||
bases.append((PyObject *) base_info->type);
|
||||
|
||||
if (base_info->type->tp_dictoffset != 0)
|
||||
dynamic_attr = true;
|
||||
|
||||
if (caster)
|
||||
base_info->implicit_casts.emplace_back(type, caster);
|
||||
PYBIND11_NOINLINE void add_base(const std::type_info &base,
|
||||
void *(*caster)(void *)) {
|
||||
auto base_info = detail::get_type_info(base, false);
|
||||
if (!base_info) {
|
||||
std::string tname(base.name());
|
||||
detail::clean_type_id(tname);
|
||||
pybind11_fail("generic_type: type \"" + std::string(name) +
|
||||
"\" referenced unknown base type \"" + tname + "\"");
|
||||
}
|
||||
|
||||
if (default_holder != base_info->default_holder) {
|
||||
std::string tname(base.name());
|
||||
detail::clean_type_id(tname);
|
||||
pybind11_fail("generic_type: type \"" + std::string(name) + "\" " +
|
||||
(default_holder ? "does not have" : "has") +
|
||||
" a non-default holder type while its base \"" + tname +
|
||||
"\" " + (base_info->default_holder ? "does not" : "does"));
|
||||
}
|
||||
|
||||
bases.append((PyObject *)base_info->type);
|
||||
|
||||
if (base_info->type->tp_dictoffset != 0)
|
||||
dynamic_attr = true;
|
||||
|
||||
if (caster)
|
||||
base_info->implicit_casts.emplace_back(type, caster);
|
||||
}
|
||||
};
|
||||
|
||||
inline function_call::function_call(const function_record &f, handle p) :
|
||||
func(f), parent(p) {
|
||||
args.reserve(f.nargs);
|
||||
args_convert.reserve(f.nargs);
|
||||
inline function_call::function_call(const function_record &f, handle p)
|
||||
: func(f), parent(p) {
|
||||
args.reserve(f.nargs);
|
||||
args_convert.reserve(f.nargs);
|
||||
}
|
||||
|
||||
/// Tag for a new-style `__init__` defined in `detail/init.h`
|
||||
struct is_new_style_constructor { };
|
||||
struct is_new_style_constructor {};
|
||||
|
||||
/**
|
||||
* Partial template specializations to process custom attributes provided to
|
||||
@@ -300,135 +331,191 @@ struct is_new_style_constructor { };
|
||||
template <typename T, typename SFINAE = void> struct process_attribute;
|
||||
|
||||
template <typename T> struct process_attribute_default {
|
||||
/// Default implementation: do nothing
|
||||
static void init(const T &, function_record *) { }
|
||||
static void init(const T &, type_record *) { }
|
||||
static void precall(function_call &) { }
|
||||
static void postcall(function_call &, handle) { }
|
||||
/// Default implementation: do nothing
|
||||
static void init(const T &, function_record *) {}
|
||||
static void init(const T &, type_record *) {}
|
||||
static void precall(function_call &) {}
|
||||
static void postcall(function_call &, handle) {}
|
||||
};
|
||||
|
||||
/// Process an attribute specifying the function's name
|
||||
template <> struct process_attribute<name> : process_attribute_default<name> {
|
||||
static void init(const name &n, function_record *r) { r->name = const_cast<char *>(n.value); }
|
||||
static void init(const name &n, function_record *r) {
|
||||
r->name = const_cast<char *>(n.value);
|
||||
}
|
||||
};
|
||||
|
||||
/// Process an attribute specifying the function's docstring
|
||||
template <> struct process_attribute<doc> : process_attribute_default<doc> {
|
||||
static void init(const doc &n, function_record *r) { r->doc = const_cast<char *>(n.value); }
|
||||
static void init(const doc &n, function_record *r) {
|
||||
r->doc = const_cast<char *>(n.value);
|
||||
}
|
||||
};
|
||||
|
||||
/// Process an attribute specifying the function's docstring (provided as a C-style string)
|
||||
template <> struct process_attribute<const char *> : process_attribute_default<const char *> {
|
||||
static void init(const char *d, function_record *r) { r->doc = const_cast<char *>(d); }
|
||||
static void init(const char *d, type_record *r) { r->doc = const_cast<char *>(d); }
|
||||
/// Process an attribute specifying the function's docstring (provided as a
|
||||
/// C-style string)
|
||||
template <>
|
||||
struct process_attribute<const char *>
|
||||
: process_attribute_default<const char *> {
|
||||
static void init(const char *d, function_record *r) {
|
||||
r->doc = const_cast<char *>(d);
|
||||
}
|
||||
static void init(const char *d, type_record *r) {
|
||||
r->doc = const_cast<char *>(d);
|
||||
}
|
||||
};
|
||||
template <> struct process_attribute<char *> : process_attribute<const char *> { };
|
||||
template <>
|
||||
struct process_attribute<char *> : process_attribute<const char *> {};
|
||||
|
||||
/// Process an attribute indicating the function's return value policy
|
||||
template <> struct process_attribute<return_value_policy> : process_attribute_default<return_value_policy> {
|
||||
static void init(const return_value_policy &p, function_record *r) { r->policy = p; }
|
||||
template <>
|
||||
struct process_attribute<return_value_policy>
|
||||
: process_attribute_default<return_value_policy> {
|
||||
static void init(const return_value_policy &p, function_record *r) {
|
||||
r->policy = p;
|
||||
}
|
||||
};
|
||||
|
||||
/// Process an attribute which indicates that this is an overloaded function associated with a given sibling
|
||||
template <> struct process_attribute<sibling> : process_attribute_default<sibling> {
|
||||
static void init(const sibling &s, function_record *r) { r->sibling = s.value; }
|
||||
/// Process an attribute which indicates that this is an overloaded function
|
||||
/// associated with a given sibling
|
||||
template <>
|
||||
struct process_attribute<sibling> : process_attribute_default<sibling> {
|
||||
static void init(const sibling &s, function_record *r) {
|
||||
r->sibling = s.value;
|
||||
}
|
||||
};
|
||||
|
||||
/// Process an attribute which indicates that this function is a method
|
||||
template <> struct process_attribute<is_method> : process_attribute_default<is_method> {
|
||||
static void init(const is_method &s, function_record *r) { r->is_method = true; r->scope = s.class_; }
|
||||
template <>
|
||||
struct process_attribute<is_method> : process_attribute_default<is_method> {
|
||||
static void init(const is_method &s, function_record *r) {
|
||||
r->is_method = true;
|
||||
r->scope = s.class_;
|
||||
}
|
||||
};
|
||||
|
||||
/// Process an attribute which indicates the parent scope of a method
|
||||
template <> struct process_attribute<scope> : process_attribute_default<scope> {
|
||||
static void init(const scope &s, function_record *r) { r->scope = s.value; }
|
||||
static void init(const scope &s, function_record *r) { r->scope = s.value; }
|
||||
};
|
||||
|
||||
/// Process an attribute which indicates that this function is an operator
|
||||
template <> struct process_attribute<is_operator> : process_attribute_default<is_operator> {
|
||||
static void init(const is_operator &, function_record *r) { r->is_operator = true; }
|
||||
template <>
|
||||
struct process_attribute<is_operator> : process_attribute_default<is_operator> {
|
||||
static void init(const is_operator &, function_record *r) {
|
||||
r->is_operator = true;
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct process_attribute<is_new_style_constructor> : process_attribute_default<is_new_style_constructor> {
|
||||
static void init(const is_new_style_constructor &, function_record *r) { r->is_new_style_constructor = true; }
|
||||
template <>
|
||||
struct process_attribute<is_new_style_constructor>
|
||||
: process_attribute_default<is_new_style_constructor> {
|
||||
static void init(const is_new_style_constructor &, function_record *r) {
|
||||
r->is_new_style_constructor = true;
|
||||
}
|
||||
};
|
||||
|
||||
/// Process a keyword argument attribute (*without* a default value)
|
||||
template <> struct process_attribute<arg> : process_attribute_default<arg> {
|
||||
static void init(const arg &a, function_record *r) {
|
||||
if (r->is_method && r->args.empty())
|
||||
r->args.emplace_back("self", nullptr, handle(), true /*convert*/, false /*none not allowed*/);
|
||||
r->args.emplace_back(a.name, nullptr, handle(), !a.flag_noconvert, a.flag_none);
|
||||
}
|
||||
static void init(const arg &a, function_record *r) {
|
||||
if (r->is_method && r->args.empty())
|
||||
r->args.emplace_back("self", nullptr, handle(), true /*convert*/,
|
||||
false /*none not allowed*/);
|
||||
r->args.emplace_back(a.name, nullptr, handle(), !a.flag_noconvert,
|
||||
a.flag_none);
|
||||
}
|
||||
};
|
||||
|
||||
/// Process a keyword argument attribute (*with* a default value)
|
||||
template <> struct process_attribute<arg_v> : process_attribute_default<arg_v> {
|
||||
static void init(const arg_v &a, function_record *r) {
|
||||
if (r->is_method && r->args.empty())
|
||||
r->args.emplace_back("self", nullptr /*descr*/, handle() /*parent*/, true /*convert*/, false /*none not allowed*/);
|
||||
static void init(const arg_v &a, function_record *r) {
|
||||
if (r->is_method && r->args.empty())
|
||||
r->args.emplace_back("self", nullptr /*descr*/, handle() /*parent*/,
|
||||
true /*convert*/, false /*none not allowed*/);
|
||||
|
||||
if (!a.value) {
|
||||
if (!a.value) {
|
||||
#if !defined(NDEBUG)
|
||||
std::string descr("'");
|
||||
if (a.name) descr += std::string(a.name) + ": ";
|
||||
descr += a.type + "'";
|
||||
if (r->is_method) {
|
||||
if (r->name)
|
||||
descr += " in method '" + (std::string) str(r->scope) + "." + (std::string) r->name + "'";
|
||||
else
|
||||
descr += " in method of '" + (std::string) str(r->scope) + "'";
|
||||
} else if (r->name) {
|
||||
descr += " in function '" + (std::string) r->name + "'";
|
||||
}
|
||||
pybind11_fail("arg(): could not convert default argument "
|
||||
+ descr + " into a Python object (type not registered yet?)");
|
||||
std::string descr("'");
|
||||
if (a.name)
|
||||
descr += std::string(a.name) + ": ";
|
||||
descr += a.type + "'";
|
||||
if (r->is_method) {
|
||||
if (r->name)
|
||||
descr += " in method '" + (std::string)str(r->scope) + "." +
|
||||
(std::string)r->name + "'";
|
||||
else
|
||||
descr += " in method of '" + (std::string)str(r->scope) + "'";
|
||||
} else if (r->name) {
|
||||
descr += " in function '" + (std::string)r->name + "'";
|
||||
}
|
||||
pybind11_fail("arg(): could not convert default argument " + descr +
|
||||
" into a Python object (type not registered yet?)");
|
||||
#else
|
||||
pybind11_fail("arg(): could not convert default argument "
|
||||
"into a Python object (type not registered yet?). "
|
||||
"Compile in debug mode for more information.");
|
||||
pybind11_fail("arg(): could not convert default argument "
|
||||
"into a Python object (type not registered yet?). "
|
||||
"Compile in debug mode for more information.");
|
||||
#endif
|
||||
}
|
||||
r->args.emplace_back(a.name, a.descr, a.value.inc_ref(), !a.flag_noconvert, a.flag_none);
|
||||
}
|
||||
r->args.emplace_back(a.name, a.descr, a.value.inc_ref(), !a.flag_noconvert,
|
||||
a.flag_none);
|
||||
}
|
||||
};
|
||||
|
||||
/// Process a parent class attribute. Single inheritance only (class_ itself already guarantees that)
|
||||
/// Process a parent class attribute. Single inheritance only (class_ itself
|
||||
/// already guarantees that)
|
||||
template <typename T>
|
||||
struct process_attribute<T, enable_if_t<is_pyobject<T>::value>> : process_attribute_default<handle> {
|
||||
static void init(const handle &h, type_record *r) { r->bases.append(h); }
|
||||
struct process_attribute<T, enable_if_t<is_pyobject<T>::value>>
|
||||
: process_attribute_default<handle> {
|
||||
static void init(const handle &h, type_record *r) { r->bases.append(h); }
|
||||
};
|
||||
|
||||
/// Process a parent class attribute (deprecated, does not support multiple inheritance)
|
||||
/// Process a parent class attribute (deprecated, does not support multiple
|
||||
/// inheritance)
|
||||
template <typename T>
|
||||
struct process_attribute<base<T>> : process_attribute_default<base<T>> {
|
||||
static void init(const base<T> &, type_record *r) { r->add_base(typeid(T), nullptr); }
|
||||
static void init(const base<T> &, type_record *r) {
|
||||
r->add_base(typeid(T), nullptr);
|
||||
}
|
||||
};
|
||||
|
||||
/// Process a multiple inheritance attribute
|
||||
template <>
|
||||
struct process_attribute<multiple_inheritance> : process_attribute_default<multiple_inheritance> {
|
||||
static void init(const multiple_inheritance &, type_record *r) { r->multiple_inheritance = true; }
|
||||
struct process_attribute<multiple_inheritance>
|
||||
: process_attribute_default<multiple_inheritance> {
|
||||
static void init(const multiple_inheritance &, type_record *r) {
|
||||
r->multiple_inheritance = true;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct process_attribute<dynamic_attr> : process_attribute_default<dynamic_attr> {
|
||||
static void init(const dynamic_attr &, type_record *r) { r->dynamic_attr = true; }
|
||||
struct process_attribute<dynamic_attr>
|
||||
: process_attribute_default<dynamic_attr> {
|
||||
static void init(const dynamic_attr &, type_record *r) {
|
||||
r->dynamic_attr = true;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct process_attribute<buffer_protocol> : process_attribute_default<buffer_protocol> {
|
||||
static void init(const buffer_protocol &, type_record *r) { r->buffer_protocol = true; }
|
||||
struct process_attribute<buffer_protocol>
|
||||
: process_attribute_default<buffer_protocol> {
|
||||
static void init(const buffer_protocol &, type_record *r) {
|
||||
r->buffer_protocol = true;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct process_attribute<metaclass> : process_attribute_default<metaclass> {
|
||||
static void init(const metaclass &m, type_record *r) { r->metaclass = m.value; }
|
||||
static void init(const metaclass &m, type_record *r) {
|
||||
r->metaclass = m.value;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct process_attribute<module_local> : process_attribute_default<module_local> {
|
||||
static void init(const module_local &l, type_record *r) { r->module_local = l.value; }
|
||||
struct process_attribute<module_local>
|
||||
: process_attribute_default<module_local> {
|
||||
static void init(const module_local &l, type_record *r) {
|
||||
r->module_local = l.value;
|
||||
}
|
||||
};
|
||||
|
||||
/// Process an 'arithmetic' attribute for enums (does nothing here)
|
||||
@@ -436,57 +523,78 @@ template <>
|
||||
struct process_attribute<arithmetic> : process_attribute_default<arithmetic> {};
|
||||
|
||||
template <typename... Ts>
|
||||
struct process_attribute<call_guard<Ts...>> : process_attribute_default<call_guard<Ts...>> { };
|
||||
struct process_attribute<call_guard<Ts...>>
|
||||
: process_attribute_default<call_guard<Ts...>> {};
|
||||
|
||||
/**
|
||||
* Process a keep_alive call policy -- invokes keep_alive_impl during the
|
||||
* pre-call handler if both Nurse, Patient != 0 and use the post-call handler
|
||||
* otherwise
|
||||
*/
|
||||
template <size_t Nurse, size_t Patient> struct process_attribute<keep_alive<Nurse, Patient>> : public process_attribute_default<keep_alive<Nurse, Patient>> {
|
||||
template <size_t N = Nurse, size_t P = Patient, enable_if_t<N != 0 && P != 0, int> = 0>
|
||||
static void precall(function_call &call) { keep_alive_impl(Nurse, Patient, call, handle()); }
|
||||
template <size_t N = Nurse, size_t P = Patient, enable_if_t<N != 0 && P != 0, int> = 0>
|
||||
static void postcall(function_call &, handle) { }
|
||||
template <size_t N = Nurse, size_t P = Patient, enable_if_t<N == 0 || P == 0, int> = 0>
|
||||
static void precall(function_call &) { }
|
||||
template <size_t N = Nurse, size_t P = Patient, enable_if_t<N == 0 || P == 0, int> = 0>
|
||||
static void postcall(function_call &call, handle ret) { keep_alive_impl(Nurse, Patient, call, ret); }
|
||||
template <size_t Nurse, size_t Patient>
|
||||
struct process_attribute<keep_alive<Nurse, Patient>>
|
||||
: public process_attribute_default<keep_alive<Nurse, Patient>> {
|
||||
template <size_t N = Nurse, size_t P = Patient,
|
||||
enable_if_t<N != 0 && P != 0, int> = 0>
|
||||
static void precall(function_call &call) {
|
||||
keep_alive_impl(Nurse, Patient, call, handle());
|
||||
}
|
||||
template <size_t N = Nurse, size_t P = Patient,
|
||||
enable_if_t<N != 0 && P != 0, int> = 0>
|
||||
static void postcall(function_call &, handle) {}
|
||||
template <size_t N = Nurse, size_t P = Patient,
|
||||
enable_if_t<N == 0 || P == 0, int> = 0>
|
||||
static void precall(function_call &) {}
|
||||
template <size_t N = Nurse, size_t P = Patient,
|
||||
enable_if_t<N == 0 || P == 0, int> = 0>
|
||||
static void postcall(function_call &call, handle ret) {
|
||||
keep_alive_impl(Nurse, Patient, call, ret);
|
||||
}
|
||||
};
|
||||
|
||||
/// Recursively iterate over variadic template arguments
|
||||
template <typename... Args> struct process_attributes {
|
||||
static void init(const Args&... args, function_record *r) {
|
||||
int unused[] = { 0, (process_attribute<typename std::decay<Args>::type>::init(args, r), 0) ... };
|
||||
ignore_unused(unused);
|
||||
}
|
||||
static void init(const Args&... args, type_record *r) {
|
||||
int unused[] = { 0, (process_attribute<typename std::decay<Args>::type>::init(args, r), 0) ... };
|
||||
ignore_unused(unused);
|
||||
}
|
||||
static void precall(function_call &call) {
|
||||
int unused[] = { 0, (process_attribute<typename std::decay<Args>::type>::precall(call), 0) ... };
|
||||
ignore_unused(unused);
|
||||
}
|
||||
static void postcall(function_call &call, handle fn_ret) {
|
||||
int unused[] = { 0, (process_attribute<typename std::decay<Args>::type>::postcall(call, fn_ret), 0) ... };
|
||||
ignore_unused(unused);
|
||||
}
|
||||
static void init(const Args &... args, function_record *r) {
|
||||
int unused[] = {
|
||||
0, (process_attribute<typename std::decay<Args>::type>::init(args, r),
|
||||
0)...};
|
||||
ignore_unused(unused);
|
||||
}
|
||||
static void init(const Args &... args, type_record *r) {
|
||||
int unused[] = {
|
||||
0, (process_attribute<typename std::decay<Args>::type>::init(args, r),
|
||||
0)...};
|
||||
ignore_unused(unused);
|
||||
}
|
||||
static void precall(function_call &call) {
|
||||
int unused[] = {
|
||||
0, (process_attribute<typename std::decay<Args>::type>::precall(call),
|
||||
0)...};
|
||||
ignore_unused(unused);
|
||||
}
|
||||
static void postcall(function_call &call, handle fn_ret) {
|
||||
int unused[] = {
|
||||
0, (process_attribute<typename std::decay<Args>::type>::postcall(
|
||||
call, fn_ret),
|
||||
0)...};
|
||||
ignore_unused(unused);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
using is_call_guard = is_instantiation<call_guard, T>;
|
||||
template <typename T> using is_call_guard = is_instantiation<call_guard, T>;
|
||||
|
||||
/// Extract the ``type`` from the first `call_guard` in `Extras...` (or `void_type` if none found)
|
||||
/// Extract the ``type`` from the first `call_guard` in `Extras...` (or
|
||||
/// `void_type` if none found)
|
||||
template <typename... Extra>
|
||||
using extract_guard_t = typename exactly_one_t<is_call_guard, call_guard<>, Extra...>::type;
|
||||
using extract_guard_t =
|
||||
typename exactly_one_t<is_call_guard, call_guard<>, Extra...>::type;
|
||||
|
||||
/// Check the number of named arguments at compile time
|
||||
template <typename... Extra,
|
||||
size_t named = constexpr_sum(std::is_base_of<arg, Extra>::value...),
|
||||
size_t self = constexpr_sum(std::is_same<is_method, Extra>::value...)>
|
||||
size_t self = constexpr_sum(std::is_same<is_method, Extra>::value...)>
|
||||
constexpr bool expected_num_args(size_t nargs, bool has_args, bool has_kwargs) {
|
||||
return named == 0 || (self + named + has_args + has_kwargs) == nargs;
|
||||
return named == 0 || (self + named + has_args + has_kwargs) == nargs;
|
||||
}
|
||||
|
||||
NAMESPACE_END(detail)
|
||||
|
@@ -15,93 +15,112 @@ NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
||||
|
||||
/// Information record describing a Python buffer object
|
||||
struct buffer_info {
|
||||
void *ptr = nullptr; // Pointer to the underlying storage
|
||||
ssize_t itemsize = 0; // Size of individual items in bytes
|
||||
ssize_t size = 0; // Total number of entries
|
||||
std::string format; // For homogeneous buffers, this should be set to format_descriptor<T>::format()
|
||||
ssize_t ndim = 0; // Number of dimensions
|
||||
std::vector<ssize_t> shape; // Shape of the tensor (1 entry per dimension)
|
||||
std::vector<ssize_t> strides; // Number of entries between adjacent entries (for each per dimension)
|
||||
void *ptr = nullptr; // Pointer to the underlying storage
|
||||
ssize_t itemsize = 0; // Size of individual items in bytes
|
||||
ssize_t size = 0; // Total number of entries
|
||||
std::string format; // For homogeneous buffers, this should be set to
|
||||
// format_descriptor<T>::format()
|
||||
ssize_t ndim = 0; // Number of dimensions
|
||||
std::vector<ssize_t> shape; // Shape of the tensor (1 entry per dimension)
|
||||
std::vector<ssize_t> strides; // Number of entries between adjacent entries
|
||||
// (for each per dimension)
|
||||
|
||||
buffer_info() { }
|
||||
buffer_info() {}
|
||||
|
||||
buffer_info(void *ptr, ssize_t itemsize, const std::string &format, ssize_t ndim,
|
||||
detail::any_container<ssize_t> shape_in, detail::any_container<ssize_t> strides_in)
|
||||
: ptr(ptr), itemsize(itemsize), size(1), format(format), ndim(ndim),
|
||||
shape(std::move(shape_in)), strides(std::move(strides_in)) {
|
||||
if (ndim != (ssize_t) shape.size() || ndim != (ssize_t) strides.size())
|
||||
pybind11_fail("buffer_info: ndim doesn't match shape and/or strides length");
|
||||
for (size_t i = 0; i < (size_t) ndim; ++i)
|
||||
size *= shape[i];
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
buffer_info(T *ptr, detail::any_container<ssize_t> shape_in, detail::any_container<ssize_t> strides_in)
|
||||
: buffer_info(private_ctr_tag(), ptr, sizeof(T), format_descriptor<T>::format(), static_cast<ssize_t>(shape_in->size()), std::move(shape_in), std::move(strides_in)) { }
|
||||
|
||||
buffer_info(void *ptr, ssize_t itemsize, const std::string &format, ssize_t size)
|
||||
: buffer_info(ptr, itemsize, format, 1, {size}, {itemsize}) { }
|
||||
|
||||
template <typename T>
|
||||
buffer_info(T *ptr, ssize_t size)
|
||||
: buffer_info(ptr, sizeof(T), format_descriptor<T>::format(), size) { }
|
||||
|
||||
explicit buffer_info(Py_buffer *view, bool ownview = true)
|
||||
: buffer_info(view->buf, view->itemsize, view->format, view->ndim,
|
||||
{view->shape, view->shape + view->ndim}, {view->strides, view->strides + view->ndim}) {
|
||||
this->view = view;
|
||||
this->ownview = ownview;
|
||||
}
|
||||
|
||||
buffer_info(const buffer_info &) = delete;
|
||||
buffer_info& operator=(const buffer_info &) = delete;
|
||||
|
||||
buffer_info(buffer_info &&other) {
|
||||
(*this) = std::move(other);
|
||||
}
|
||||
|
||||
buffer_info& operator=(buffer_info &&rhs) {
|
||||
ptr = rhs.ptr;
|
||||
itemsize = rhs.itemsize;
|
||||
size = rhs.size;
|
||||
format = std::move(rhs.format);
|
||||
ndim = rhs.ndim;
|
||||
shape = std::move(rhs.shape);
|
||||
strides = std::move(rhs.strides);
|
||||
std::swap(view, rhs.view);
|
||||
std::swap(ownview, rhs.ownview);
|
||||
return *this;
|
||||
}
|
||||
|
||||
~buffer_info() {
|
||||
if (view && ownview) { PyBuffer_Release(view); delete view; }
|
||||
buffer_info(void *ptr, ssize_t itemsize, const std::string &format,
|
||||
ssize_t ndim, detail::any_container<ssize_t> shape_in,
|
||||
detail::any_container<ssize_t> strides_in)
|
||||
: ptr(ptr), itemsize(itemsize), size(1), format(format), ndim(ndim),
|
||||
shape(std::move(shape_in)), strides(std::move(strides_in)) {
|
||||
if (ndim != (ssize_t)shape.size() || ndim != (ssize_t)strides.size())
|
||||
pybind11_fail(
|
||||
"buffer_info: ndim doesn't match shape and/or strides length");
|
||||
for (size_t i = 0; i < (size_t)ndim; ++i)
|
||||
size *= shape[i];
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
buffer_info(T *ptr, detail::any_container<ssize_t> shape_in,
|
||||
detail::any_container<ssize_t> strides_in)
|
||||
: buffer_info(private_ctr_tag(), ptr, sizeof(T),
|
||||
format_descriptor<T>::format(),
|
||||
static_cast<ssize_t>(shape_in->size()), std::move(shape_in),
|
||||
std::move(strides_in)) {}
|
||||
|
||||
buffer_info(void *ptr, ssize_t itemsize, const std::string &format,
|
||||
ssize_t size)
|
||||
: buffer_info(ptr, itemsize, format, 1, {size}, {itemsize}) {}
|
||||
|
||||
template <typename T>
|
||||
buffer_info(T *ptr, ssize_t size)
|
||||
: buffer_info(ptr, sizeof(T), format_descriptor<T>::format(), size) {}
|
||||
|
||||
explicit buffer_info(Py_buffer *view, bool ownview = true)
|
||||
: buffer_info(view->buf, view->itemsize, view->format, view->ndim,
|
||||
{view->shape, view->shape + view->ndim},
|
||||
{view->strides, view->strides + view->ndim}) {
|
||||
this->view = view;
|
||||
this->ownview = ownview;
|
||||
}
|
||||
|
||||
buffer_info(const buffer_info &) = delete;
|
||||
buffer_info &operator=(const buffer_info &) = delete;
|
||||
|
||||
buffer_info(buffer_info &&other) { (*this) = std::move(other); }
|
||||
|
||||
buffer_info &operator=(buffer_info &&rhs) {
|
||||
ptr = rhs.ptr;
|
||||
itemsize = rhs.itemsize;
|
||||
size = rhs.size;
|
||||
format = std::move(rhs.format);
|
||||
ndim = rhs.ndim;
|
||||
shape = std::move(rhs.shape);
|
||||
strides = std::move(rhs.strides);
|
||||
std::swap(view, rhs.view);
|
||||
std::swap(ownview, rhs.ownview);
|
||||
return *this;
|
||||
}
|
||||
|
||||
~buffer_info() {
|
||||
if (view && ownview) {
|
||||
PyBuffer_Release(view);
|
||||
delete view;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
struct private_ctr_tag { };
|
||||
struct private_ctr_tag {};
|
||||
|
||||
buffer_info(private_ctr_tag, void *ptr, ssize_t itemsize, const std::string &format, ssize_t ndim,
|
||||
detail::any_container<ssize_t> &&shape_in, detail::any_container<ssize_t> &&strides_in)
|
||||
: buffer_info(ptr, itemsize, format, ndim, std::move(shape_in), std::move(strides_in)) { }
|
||||
buffer_info(private_ctr_tag, void *ptr, ssize_t itemsize,
|
||||
const std::string &format, ssize_t ndim,
|
||||
detail::any_container<ssize_t> &&shape_in,
|
||||
detail::any_container<ssize_t> &&strides_in)
|
||||
: buffer_info(ptr, itemsize, format, ndim, std::move(shape_in),
|
||||
std::move(strides_in)) {}
|
||||
|
||||
Py_buffer *view = nullptr;
|
||||
bool ownview = false;
|
||||
Py_buffer *view = nullptr;
|
||||
bool ownview = false;
|
||||
};
|
||||
|
||||
NAMESPACE_BEGIN(detail)
|
||||
|
||||
template <typename T, typename SFINAE = void> struct compare_buffer_info {
|
||||
static bool compare(const buffer_info& b) {
|
||||
return b.format == format_descriptor<T>::format() && b.itemsize == (ssize_t) sizeof(T);
|
||||
}
|
||||
static bool compare(const buffer_info &b) {
|
||||
return b.format == format_descriptor<T>::format() &&
|
||||
b.itemsize == (ssize_t)sizeof(T);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T> struct compare_buffer_info<T, detail::enable_if_t<std::is_integral<T>::value>> {
|
||||
static bool compare(const buffer_info& b) {
|
||||
return (size_t) b.itemsize == sizeof(T) && (b.format == format_descriptor<T>::value ||
|
||||
((sizeof(T) == sizeof(long)) && b.format == (std::is_unsigned<T>::value ? "L" : "l")) ||
|
||||
((sizeof(T) == sizeof(size_t)) && b.format == (std::is_unsigned<T>::value ? "N" : "n")));
|
||||
}
|
||||
template <typename T>
|
||||
struct compare_buffer_info<T, detail::enable_if_t<std::is_integral<T>::value>> {
|
||||
static bool compare(const buffer_info &b) {
|
||||
return (size_t)b.itemsize == sizeof(T) &&
|
||||
(b.format == format_descriptor<T>::value ||
|
||||
((sizeof(T) == sizeof(long)) &&
|
||||
b.format == (std::is_unsigned<T>::value ? "L" : "l")) ||
|
||||
((sizeof(T) == sizeof(size_t)) &&
|
||||
b.format == (std::is_unsigned<T>::value ? "N" : "n")));
|
||||
}
|
||||
};
|
||||
|
||||
NAMESPACE_END(detail)
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
pybind11/chrono.h: Transparent conversion between std::chrono and python's datetime
|
||||
pybind11/chrono.h: Transparent conversion between std::chrono and python's
|
||||
datetime
|
||||
|
||||
Copyright (c) 2016 Trent Houliston <trent@houliston.me> and
|
||||
Wenzel Jakob <wenzel.jakob@epfl.ch>
|
||||
@@ -11,20 +12,21 @@
|
||||
#pragma once
|
||||
|
||||
#include "pybind11.h"
|
||||
#include <chrono>
|
||||
#include <cmath>
|
||||
#include <ctime>
|
||||
#include <chrono>
|
||||
#include <datetime.h>
|
||||
|
||||
// Backport the PyDateTime_DELTA functions from Python3.3 if required
|
||||
#ifndef PyDateTime_DELTA_GET_DAYS
|
||||
#define PyDateTime_DELTA_GET_DAYS(o) (((PyDateTime_Delta*)o)->days)
|
||||
#define PyDateTime_DELTA_GET_DAYS(o) (((PyDateTime_Delta *)o)->days)
|
||||
#endif
|
||||
#ifndef PyDateTime_DELTA_GET_SECONDS
|
||||
#define PyDateTime_DELTA_GET_SECONDS(o) (((PyDateTime_Delta*)o)->seconds)
|
||||
#define PyDateTime_DELTA_GET_SECONDS(o) (((PyDateTime_Delta *)o)->seconds)
|
||||
#endif
|
||||
#ifndef PyDateTime_DELTA_GET_MICROSECONDS
|
||||
#define PyDateTime_DELTA_GET_MICROSECONDS(o) (((PyDateTime_Delta*)o)->microseconds)
|
||||
#define PyDateTime_DELTA_GET_MICROSECONDS(o) \
|
||||
(((PyDateTime_Delta *)o)->microseconds)
|
||||
#endif
|
||||
|
||||
NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
||||
@@ -32,131 +34,154 @@ NAMESPACE_BEGIN(detail)
|
||||
|
||||
template <typename type> class duration_caster {
|
||||
public:
|
||||
typedef typename type::rep rep;
|
||||
typedef typename type::period period;
|
||||
typedef typename type::rep rep;
|
||||
typedef typename type::period period;
|
||||
|
||||
typedef std::chrono::duration<uint_fast32_t, std::ratio<86400>> days;
|
||||
typedef std::chrono::duration<uint_fast32_t, std::ratio<86400>> days;
|
||||
|
||||
bool load(handle src, bool) {
|
||||
using namespace std::chrono;
|
||||
bool load(handle src, bool) {
|
||||
using namespace std::chrono;
|
||||
|
||||
// Lazy initialise the PyDateTime import
|
||||
if (!PyDateTimeAPI) { PyDateTime_IMPORT; }
|
||||
|
||||
if (!src) return false;
|
||||
// If invoked with datetime.delta object
|
||||
if (PyDelta_Check(src.ptr())) {
|
||||
value = type(duration_cast<duration<rep, period>>(
|
||||
days(PyDateTime_DELTA_GET_DAYS(src.ptr()))
|
||||
+ seconds(PyDateTime_DELTA_GET_SECONDS(src.ptr()))
|
||||
+ microseconds(PyDateTime_DELTA_GET_MICROSECONDS(src.ptr()))));
|
||||
return true;
|
||||
}
|
||||
// If invoked with a float we assume it is seconds and convert
|
||||
else if (PyFloat_Check(src.ptr())) {
|
||||
value = type(duration_cast<duration<rep, period>>(duration<double>(PyFloat_AsDouble(src.ptr()))));
|
||||
return true;
|
||||
}
|
||||
else return false;
|
||||
// Lazy initialise the PyDateTime import
|
||||
if (!PyDateTimeAPI) {
|
||||
PyDateTime_IMPORT;
|
||||
}
|
||||
|
||||
// If this is a duration just return it back
|
||||
static const std::chrono::duration<rep, period>& get_duration(const std::chrono::duration<rep, period> &src) {
|
||||
return src;
|
||||
if (!src)
|
||||
return false;
|
||||
// If invoked with datetime.delta object
|
||||
if (PyDelta_Check(src.ptr())) {
|
||||
value = type(duration_cast<duration<rep, period>>(
|
||||
days(PyDateTime_DELTA_GET_DAYS(src.ptr())) +
|
||||
seconds(PyDateTime_DELTA_GET_SECONDS(src.ptr())) +
|
||||
microseconds(PyDateTime_DELTA_GET_MICROSECONDS(src.ptr()))));
|
||||
return true;
|
||||
}
|
||||
// If invoked with a float we assume it is seconds and convert
|
||||
else if (PyFloat_Check(src.ptr())) {
|
||||
value = type(duration_cast<duration<rep, period>>(
|
||||
duration<double>(PyFloat_AsDouble(src.ptr()))));
|
||||
return true;
|
||||
} else
|
||||
return false;
|
||||
}
|
||||
|
||||
// If this is a duration just return it back
|
||||
static const std::chrono::duration<rep, period> &
|
||||
get_duration(const std::chrono::duration<rep, period> &src) {
|
||||
return src;
|
||||
}
|
||||
|
||||
// If this is a time_point get the time_since_epoch
|
||||
template <typename Clock>
|
||||
static std::chrono::duration<rep, period> get_duration(
|
||||
const std::chrono::time_point<Clock, std::chrono::duration<rep, period>>
|
||||
&src) {
|
||||
return src.time_since_epoch();
|
||||
}
|
||||
|
||||
static handle cast(const type &src, return_value_policy /* policy */,
|
||||
handle /* parent */) {
|
||||
using namespace std::chrono;
|
||||
|
||||
// Use overloaded function to get our duration from our source
|
||||
// Works out if it is a duration or time_point and get the duration
|
||||
auto d = get_duration(src);
|
||||
|
||||
// Lazy initialise the PyDateTime import
|
||||
if (!PyDateTimeAPI) {
|
||||
PyDateTime_IMPORT;
|
||||
}
|
||||
|
||||
// If this is a time_point get the time_since_epoch
|
||||
template <typename Clock> static std::chrono::duration<rep, period> get_duration(const std::chrono::time_point<Clock, std::chrono::duration<rep, period>> &src) {
|
||||
return src.time_since_epoch();
|
||||
}
|
||||
// Declare these special duration types so the conversions happen with the
|
||||
// correct primitive types (int)
|
||||
using dd_t = duration<int, std::ratio<86400>>;
|
||||
using ss_t = duration<int, std::ratio<1>>;
|
||||
using us_t = duration<int, std::micro>;
|
||||
|
||||
static handle cast(const type &src, return_value_policy /* policy */, handle /* parent */) {
|
||||
using namespace std::chrono;
|
||||
auto dd = duration_cast<dd_t>(d);
|
||||
auto subd = d - dd;
|
||||
auto ss = duration_cast<ss_t>(subd);
|
||||
auto us = duration_cast<us_t>(subd - ss);
|
||||
return PyDelta_FromDSU(dd.count(), ss.count(), us.count());
|
||||
}
|
||||
|
||||
// Use overloaded function to get our duration from our source
|
||||
// Works out if it is a duration or time_point and get the duration
|
||||
auto d = get_duration(src);
|
||||
|
||||
// Lazy initialise the PyDateTime import
|
||||
if (!PyDateTimeAPI) { PyDateTime_IMPORT; }
|
||||
|
||||
// Declare these special duration types so the conversions happen with the correct primitive types (int)
|
||||
using dd_t = duration<int, std::ratio<86400>>;
|
||||
using ss_t = duration<int, std::ratio<1>>;
|
||||
using us_t = duration<int, std::micro>;
|
||||
|
||||
auto dd = duration_cast<dd_t>(d);
|
||||
auto subd = d - dd;
|
||||
auto ss = duration_cast<ss_t>(subd);
|
||||
auto us = duration_cast<us_t>(subd - ss);
|
||||
return PyDelta_FromDSU(dd.count(), ss.count(), us.count());
|
||||
}
|
||||
|
||||
PYBIND11_TYPE_CASTER(type, _("datetime.timedelta"));
|
||||
PYBIND11_TYPE_CASTER(type, _("datetime.timedelta"));
|
||||
};
|
||||
|
||||
// This is for casting times on the system clock into datetime.datetime instances
|
||||
template <typename Duration> class type_caster<std::chrono::time_point<std::chrono::system_clock, Duration>> {
|
||||
// This is for casting times on the system clock into datetime.datetime
|
||||
// instances
|
||||
template <typename Duration>
|
||||
class type_caster<
|
||||
std::chrono::time_point<std::chrono::system_clock, Duration>> {
|
||||
public:
|
||||
typedef std::chrono::time_point<std::chrono::system_clock, Duration> type;
|
||||
bool load(handle src, bool) {
|
||||
using namespace std::chrono;
|
||||
typedef std::chrono::time_point<std::chrono::system_clock, Duration> type;
|
||||
bool load(handle src, bool) {
|
||||
using namespace std::chrono;
|
||||
|
||||
// Lazy initialise the PyDateTime import
|
||||
if (!PyDateTimeAPI) { PyDateTime_IMPORT; }
|
||||
|
||||
if (!src) return false;
|
||||
if (PyDateTime_Check(src.ptr())) {
|
||||
std::tm cal;
|
||||
cal.tm_sec = PyDateTime_DATE_GET_SECOND(src.ptr());
|
||||
cal.tm_min = PyDateTime_DATE_GET_MINUTE(src.ptr());
|
||||
cal.tm_hour = PyDateTime_DATE_GET_HOUR(src.ptr());
|
||||
cal.tm_mday = PyDateTime_GET_DAY(src.ptr());
|
||||
cal.tm_mon = PyDateTime_GET_MONTH(src.ptr()) - 1;
|
||||
cal.tm_year = PyDateTime_GET_YEAR(src.ptr()) - 1900;
|
||||
cal.tm_isdst = -1;
|
||||
|
||||
value = system_clock::from_time_t(std::mktime(&cal)) + microseconds(PyDateTime_DATE_GET_MICROSECOND(src.ptr()));
|
||||
return true;
|
||||
}
|
||||
else return false;
|
||||
// Lazy initialise the PyDateTime import
|
||||
if (!PyDateTimeAPI) {
|
||||
PyDateTime_IMPORT;
|
||||
}
|
||||
|
||||
static handle cast(const std::chrono::time_point<std::chrono::system_clock, Duration> &src, return_value_policy /* policy */, handle /* parent */) {
|
||||
using namespace std::chrono;
|
||||
if (!src)
|
||||
return false;
|
||||
if (PyDateTime_Check(src.ptr())) {
|
||||
std::tm cal;
|
||||
cal.tm_sec = PyDateTime_DATE_GET_SECOND(src.ptr());
|
||||
cal.tm_min = PyDateTime_DATE_GET_MINUTE(src.ptr());
|
||||
cal.tm_hour = PyDateTime_DATE_GET_HOUR(src.ptr());
|
||||
cal.tm_mday = PyDateTime_GET_DAY(src.ptr());
|
||||
cal.tm_mon = PyDateTime_GET_MONTH(src.ptr()) - 1;
|
||||
cal.tm_year = PyDateTime_GET_YEAR(src.ptr()) - 1900;
|
||||
cal.tm_isdst = -1;
|
||||
|
||||
// Lazy initialise the PyDateTime import
|
||||
if (!PyDateTimeAPI) { PyDateTime_IMPORT; }
|
||||
value = system_clock::from_time_t(std::mktime(&cal)) +
|
||||
microseconds(PyDateTime_DATE_GET_MICROSECOND(src.ptr()));
|
||||
return true;
|
||||
} else
|
||||
return false;
|
||||
}
|
||||
|
||||
std::time_t tt = system_clock::to_time_t(src);
|
||||
// this function uses static memory so it's best to copy it out asap just in case
|
||||
// otherwise other code that is using localtime may break this (not just python code)
|
||||
std::tm localtime = *std::localtime(&tt);
|
||||
static handle
|
||||
cast(const std::chrono::time_point<std::chrono::system_clock, Duration> &src,
|
||||
return_value_policy /* policy */, handle /* parent */) {
|
||||
using namespace std::chrono;
|
||||
|
||||
// Declare these special duration types so the conversions happen with the correct primitive types (int)
|
||||
using us_t = duration<int, std::micro>;
|
||||
|
||||
return PyDateTime_FromDateAndTime(localtime.tm_year + 1900,
|
||||
localtime.tm_mon + 1,
|
||||
localtime.tm_mday,
|
||||
localtime.tm_hour,
|
||||
localtime.tm_min,
|
||||
localtime.tm_sec,
|
||||
(duration_cast<us_t>(src.time_since_epoch() % seconds(1))).count());
|
||||
// Lazy initialise the PyDateTime import
|
||||
if (!PyDateTimeAPI) {
|
||||
PyDateTime_IMPORT;
|
||||
}
|
||||
PYBIND11_TYPE_CASTER(type, _("datetime.datetime"));
|
||||
|
||||
std::time_t tt = system_clock::to_time_t(src);
|
||||
// this function uses static memory so it's best to copy it out asap just in
|
||||
// case otherwise other code that is using localtime may break this (not
|
||||
// just python code)
|
||||
std::tm localtime = *std::localtime(&tt);
|
||||
|
||||
// Declare these special duration types so the conversions happen with the
|
||||
// correct primitive types (int)
|
||||
using us_t = duration<int, std::micro>;
|
||||
|
||||
return PyDateTime_FromDateAndTime(
|
||||
localtime.tm_year + 1900, localtime.tm_mon + 1, localtime.tm_mday,
|
||||
localtime.tm_hour, localtime.tm_min, localtime.tm_sec,
|
||||
(duration_cast<us_t>(src.time_since_epoch() % seconds(1))).count());
|
||||
}
|
||||
PYBIND11_TYPE_CASTER(type, _("datetime.datetime"));
|
||||
};
|
||||
|
||||
// Other clocks that are not the system clock are not measured as datetime.datetime objects
|
||||
// since they are not measured on calendar time. So instead we just make them timedeltas
|
||||
// Or if they have passed us a time as a float we convert that
|
||||
template <typename Clock, typename Duration> class type_caster<std::chrono::time_point<Clock, Duration>>
|
||||
: public duration_caster<std::chrono::time_point<Clock, Duration>> {
|
||||
};
|
||||
// Other clocks that are not the system clock are not measured as
|
||||
// datetime.datetime objects since they are not measured on calendar time. So
|
||||
// instead we just make them timedeltas Or if they have passed us a time as a
|
||||
// float we convert that
|
||||
template <typename Clock, typename Duration>
|
||||
class type_caster<std::chrono::time_point<Clock, Duration>>
|
||||
: public duration_caster<std::chrono::time_point<Clock, Duration>> {};
|
||||
|
||||
template <typename Rep, typename Period> class type_caster<std::chrono::duration<Rep, Period>>
|
||||
: public duration_caster<std::chrono::duration<Rep, Period>> {
|
||||
};
|
||||
template <typename Rep, typename Period>
|
||||
class type_caster<std::chrono::duration<Rep, Period>>
|
||||
: public duration_caster<std::chrono::duration<Rep, Period>> {};
|
||||
|
||||
NAMESPACE_END(detail)
|
||||
NAMESPACE_END(PYBIND11_NAMESPACE)
|
||||
|
@@ -1,2 +1,3 @@
|
||||
#include "detail/common.h"
|
||||
#warning "Including 'common.h' is deprecated. It will be removed in v3.0. Use 'pybind11.h'."
|
||||
#warning \
|
||||
"Including 'common.h' is deprecated. It will be removed in v3.0. Use 'pybind11.h'."
|
||||
|
@@ -14,52 +14,59 @@
|
||||
|
||||
/// glibc defines I as a macro which breaks things, e.g., boost template names
|
||||
#ifdef I
|
||||
# undef I
|
||||
#undef I
|
||||
#endif
|
||||
|
||||
NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
||||
|
||||
template <typename T> struct format_descriptor<std::complex<T>, detail::enable_if_t<std::is_floating_point<T>::value>> {
|
||||
static constexpr const char c = format_descriptor<T>::c;
|
||||
static constexpr const char value[3] = { 'Z', c, '\0' };
|
||||
static std::string format() { return std::string(value); }
|
||||
template <typename T>
|
||||
struct format_descriptor<
|
||||
std::complex<T>, detail::enable_if_t<std::is_floating_point<T>::value>> {
|
||||
static constexpr const char c = format_descriptor<T>::c;
|
||||
static constexpr const char value[3] = {'Z', c, '\0'};
|
||||
static std::string format() { return std::string(value); }
|
||||
};
|
||||
|
||||
#ifndef PYBIND11_CPP17
|
||||
|
||||
template <typename T> constexpr const char format_descriptor<
|
||||
std::complex<T>, detail::enable_if_t<std::is_floating_point<T>::value>>::value[3];
|
||||
template <typename T>
|
||||
constexpr const char format_descriptor<
|
||||
std::complex<T>,
|
||||
detail::enable_if_t<std::is_floating_point<T>::value>>::value[3];
|
||||
|
||||
#endif
|
||||
|
||||
NAMESPACE_BEGIN(detail)
|
||||
|
||||
template <typename T> struct is_fmt_numeric<std::complex<T>, detail::enable_if_t<std::is_floating_point<T>::value>> {
|
||||
static constexpr bool value = true;
|
||||
static constexpr int index = is_fmt_numeric<T>::index + 3;
|
||||
template <typename T>
|
||||
struct is_fmt_numeric<std::complex<T>,
|
||||
detail::enable_if_t<std::is_floating_point<T>::value>> {
|
||||
static constexpr bool value = true;
|
||||
static constexpr int index = is_fmt_numeric<T>::index + 3;
|
||||
};
|
||||
|
||||
template <typename T> class type_caster<std::complex<T>> {
|
||||
public:
|
||||
bool load(handle src, bool convert) {
|
||||
if (!src)
|
||||
return false;
|
||||
if (!convert && !PyComplex_Check(src.ptr()))
|
||||
return false;
|
||||
Py_complex result = PyComplex_AsCComplex(src.ptr());
|
||||
if (result.real == -1.0 && PyErr_Occurred()) {
|
||||
PyErr_Clear();
|
||||
return false;
|
||||
}
|
||||
value = std::complex<T>((T) result.real, (T) result.imag);
|
||||
return true;
|
||||
bool load(handle src, bool convert) {
|
||||
if (!src)
|
||||
return false;
|
||||
if (!convert && !PyComplex_Check(src.ptr()))
|
||||
return false;
|
||||
Py_complex result = PyComplex_AsCComplex(src.ptr());
|
||||
if (result.real == -1.0 && PyErr_Occurred()) {
|
||||
PyErr_Clear();
|
||||
return false;
|
||||
}
|
||||
value = std::complex<T>((T)result.real, (T)result.imag);
|
||||
return true;
|
||||
}
|
||||
|
||||
static handle cast(const std::complex<T> &src, return_value_policy /* policy */, handle /* parent */) {
|
||||
return PyComplex_FromDoubles((double) src.real(), (double) src.imag());
|
||||
}
|
||||
static handle cast(const std::complex<T> &src,
|
||||
return_value_policy /* policy */, handle /* parent */) {
|
||||
return PyComplex_FromDoubles((double)src.real(), (double)src.imag());
|
||||
}
|
||||
|
||||
PYBIND11_TYPE_CASTER(std::complex<T>, _("complex"));
|
||||
PYBIND11_TYPE_CASTER(std::complex<T>, _("complex"));
|
||||
};
|
||||
NAMESPACE_END(detail)
|
||||
NAMESPACE_END(PYBIND11_NAMESPACE)
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
pybind11/detail/descr.h: Helper type for concatenating type signatures at compile time
|
||||
pybind11/detail/descr.h: Helper type for concatenating type signatures at
|
||||
compile time
|
||||
|
||||
Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
|
||||
|
||||
@@ -15,67 +16,82 @@ NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
||||
NAMESPACE_BEGIN(detail)
|
||||
|
||||
#if !defined(_MSC_VER)
|
||||
# define PYBIND11_DESCR_CONSTEXPR static constexpr
|
||||
#define PYBIND11_DESCR_CONSTEXPR static constexpr
|
||||
#else
|
||||
# define PYBIND11_DESCR_CONSTEXPR const
|
||||
#define PYBIND11_DESCR_CONSTEXPR const
|
||||
#endif
|
||||
|
||||
/* Concatenate type signatures at compile time */
|
||||
template <size_t N, typename... Ts>
|
||||
struct descr {
|
||||
char text[N + 1];
|
||||
template <size_t N, typename... Ts> struct descr {
|
||||
char text[N + 1];
|
||||
|
||||
constexpr descr() : text{'\0'} { }
|
||||
constexpr descr(char const (&s)[N+1]) : descr(s, make_index_sequence<N>()) { }
|
||||
constexpr descr() : text{'\0'} {}
|
||||
constexpr descr(char const (&s)[N + 1])
|
||||
: descr(s, make_index_sequence<N>()) {}
|
||||
|
||||
template <size_t... Is>
|
||||
constexpr descr(char const (&s)[N+1], index_sequence<Is...>) : text{s[Is]..., '\0'} { }
|
||||
template <size_t... Is>
|
||||
constexpr descr(char const (&s)[N + 1], index_sequence<Is...>)
|
||||
: text{s[Is]..., '\0'} {}
|
||||
|
||||
template <typename... Chars>
|
||||
constexpr descr(char c, Chars... cs) : text{c, static_cast<char>(cs)..., '\0'} { }
|
||||
template <typename... Chars>
|
||||
constexpr descr(char c, Chars... cs)
|
||||
: text{c, static_cast<char>(cs)..., '\0'} {}
|
||||
|
||||
static constexpr std::array<const std::type_info *, sizeof...(Ts) + 1> types() {
|
||||
return {{&typeid(Ts)..., nullptr}};
|
||||
}
|
||||
static constexpr std::array<const std::type_info *, sizeof...(Ts) + 1>
|
||||
types() {
|
||||
return {{&typeid(Ts)..., nullptr}};
|
||||
}
|
||||
};
|
||||
|
||||
template <size_t N1, size_t N2, typename... Ts1, typename... Ts2, size_t... Is1, size_t... Is2>
|
||||
constexpr descr<N1 + N2, Ts1..., Ts2...> plus_impl(const descr<N1, Ts1...> &a, const descr<N2, Ts2...> &b,
|
||||
index_sequence<Is1...>, index_sequence<Is2...>) {
|
||||
return {a.text[Is1]..., b.text[Is2]...};
|
||||
template <size_t N1, size_t N2, typename... Ts1, typename... Ts2, size_t... Is1,
|
||||
size_t... Is2>
|
||||
constexpr descr<N1 + N2, Ts1..., Ts2...>
|
||||
plus_impl(const descr<N1, Ts1...> &a, const descr<N2, Ts2...> &b,
|
||||
index_sequence<Is1...>, index_sequence<Is2...>) {
|
||||
return {a.text[Is1]..., b.text[Is2]...};
|
||||
}
|
||||
|
||||
template <size_t N1, size_t N2, typename... Ts1, typename... Ts2>
|
||||
constexpr descr<N1 + N2, Ts1..., Ts2...> operator+(const descr<N1, Ts1...> &a, const descr<N2, Ts2...> &b) {
|
||||
return plus_impl(a, b, make_index_sequence<N1>(), make_index_sequence<N2>());
|
||||
constexpr descr<N1 + N2, Ts1..., Ts2...> operator+(const descr<N1, Ts1...> &a,
|
||||
const descr<N2, Ts2...> &b) {
|
||||
return plus_impl(a, b, make_index_sequence<N1>(), make_index_sequence<N2>());
|
||||
}
|
||||
|
||||
template <size_t N>
|
||||
constexpr descr<N - 1> _(char const(&text)[N]) { return descr<N - 1>(text); }
|
||||
constexpr descr<0> _(char const(&)[1]) { return {}; }
|
||||
template <size_t N> constexpr descr<N - 1> _(char const (&text)[N]) {
|
||||
return descr<N - 1>(text);
|
||||
}
|
||||
constexpr descr<0> _(char const (&)[1]) { return {}; }
|
||||
|
||||
template <size_t Rem, size_t... Digits> struct int_to_str : int_to_str<Rem/10, Rem%10, Digits...> { };
|
||||
template <size_t...Digits> struct int_to_str<0, Digits...> {
|
||||
static constexpr auto digits = descr<sizeof...(Digits)>(('0' + Digits)...);
|
||||
template <size_t Rem, size_t... Digits>
|
||||
struct int_to_str : int_to_str<Rem / 10, Rem % 10, Digits...> {};
|
||||
template <size_t... Digits> struct int_to_str<0, Digits...> {
|
||||
static constexpr auto digits = descr<sizeof...(Digits)>(('0' + Digits)...);
|
||||
};
|
||||
|
||||
// Ternary description (like std::conditional)
|
||||
template <bool B, size_t N1, size_t N2>
|
||||
constexpr enable_if_t<B, descr<N1 - 1>> _(char const(&text1)[N1], char const(&)[N2]) {
|
||||
return _(text1);
|
||||
constexpr enable_if_t<B, descr<N1 - 1>> _(char const (&text1)[N1],
|
||||
char const (&)[N2]) {
|
||||
return _(text1);
|
||||
}
|
||||
template <bool B, size_t N1, size_t N2>
|
||||
constexpr enable_if_t<!B, descr<N2 - 1>> _(char const(&)[N1], char const(&text2)[N2]) {
|
||||
return _(text2);
|
||||
constexpr enable_if_t<!B, descr<N2 - 1>> _(char const (&)[N1],
|
||||
char const (&text2)[N2]) {
|
||||
return _(text2);
|
||||
}
|
||||
|
||||
template <bool B, typename T1, typename T2>
|
||||
constexpr enable_if_t<B, T1> _(const T1 &d, const T2 &) { return d; }
|
||||
constexpr enable_if_t<B, T1> _(const T1 &d, const T2 &) {
|
||||
return d;
|
||||
}
|
||||
template <bool B, typename T1, typename T2>
|
||||
constexpr enable_if_t<!B, T2> _(const T1 &, const T2 &d) { return d; }
|
||||
constexpr enable_if_t<!B, T2> _(const T1 &, const T2 &d) {
|
||||
return d;
|
||||
}
|
||||
|
||||
template <size_t Size> auto constexpr _() -> decltype(int_to_str<Size / 10, Size % 10>::digits) {
|
||||
return int_to_str<Size / 10, Size % 10>::digits;
|
||||
template <size_t Size>
|
||||
auto constexpr _() -> decltype(int_to_str<Size / 10, Size % 10>::digits) {
|
||||
return int_to_str<Size / 10, Size % 10>::digits;
|
||||
}
|
||||
|
||||
template <typename Type> constexpr descr<1, Type> _() { return {'%'}; }
|
||||
@@ -83,17 +99,19 @@ template <typename Type> constexpr descr<1, Type> _() { return {'%'}; }
|
||||
constexpr descr<0> concat() { return {}; }
|
||||
|
||||
template <size_t N, typename... Ts>
|
||||
constexpr descr<N, Ts...> concat(const descr<N, Ts...> &descr) { return descr; }
|
||||
constexpr descr<N, Ts...> concat(const descr<N, Ts...> &descr) {
|
||||
return descr;
|
||||
}
|
||||
|
||||
template <size_t N, typename... Ts, typename... Args>
|
||||
constexpr auto concat(const descr<N, Ts...> &d, const Args &...args)
|
||||
constexpr auto concat(const descr<N, Ts...> &d, const Args &... args)
|
||||
-> decltype(std::declval<descr<N + 2, Ts...>>() + concat(args...)) {
|
||||
return d + _(", ") + concat(args...);
|
||||
return d + _(", ") + concat(args...);
|
||||
}
|
||||
|
||||
template <size_t N, typename... Ts>
|
||||
constexpr descr<N + 2, Ts...> type_descr(const descr<N, Ts...> &descr) {
|
||||
return _("{") + descr + _("}");
|
||||
return _("{") + descr + _("}");
|
||||
}
|
||||
|
||||
NAMESPACE_END(detail)
|
||||
|
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
pybind11/detail/init.h: init factory function implementation and support code.
|
||||
pybind11/detail/init.h: init factory function implementation and support
|
||||
code.
|
||||
|
||||
Copyright (c) 2017 Jason Rhinelander <jason@imaginary.ca>
|
||||
|
||||
@@ -14,26 +15,26 @@
|
||||
NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
||||
NAMESPACE_BEGIN(detail)
|
||||
|
||||
template <>
|
||||
class type_caster<value_and_holder> {
|
||||
template <> class type_caster<value_and_holder> {
|
||||
public:
|
||||
bool load(handle h, bool) {
|
||||
value = reinterpret_cast<value_and_holder *>(h.ptr());
|
||||
return true;
|
||||
}
|
||||
bool load(handle h, bool) {
|
||||
value = reinterpret_cast<value_and_holder *>(h.ptr());
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename> using cast_op_type = value_and_holder &;
|
||||
operator value_and_holder &() { return *value; }
|
||||
static constexpr auto name = _<value_and_holder>();
|
||||
template <typename> using cast_op_type = value_and_holder &;
|
||||
operator value_and_holder &() { return *value; }
|
||||
static constexpr auto name = _<value_and_holder>();
|
||||
|
||||
private:
|
||||
value_and_holder *value = nullptr;
|
||||
value_and_holder *value = nullptr;
|
||||
};
|
||||
|
||||
NAMESPACE_BEGIN(initimpl)
|
||||
|
||||
inline void no_nullptr(void *ptr) {
|
||||
if (!ptr) throw type_error("pybind11::init(): factory function returned nullptr");
|
||||
if (!ptr)
|
||||
throw type_error("pybind11::init(): factory function returned nullptr");
|
||||
}
|
||||
|
||||
// Implementing functions for all forms of py::init<...> and py::init(...)
|
||||
@@ -41,293 +42,372 @@ template <typename Class> using Cpp = typename Class::type;
|
||||
template <typename Class> using Alias = typename Class::type_alias;
|
||||
template <typename Class> using Holder = typename Class::holder_type;
|
||||
|
||||
template <typename Class> using is_alias_constructible = std::is_constructible<Alias<Class>, Cpp<Class> &&>;
|
||||
template <typename Class>
|
||||
using is_alias_constructible =
|
||||
std::is_constructible<Alias<Class>, Cpp<Class> &&>;
|
||||
|
||||
// Takes a Cpp pointer and returns true if it actually is a polymorphic Alias instance.
|
||||
// Takes a Cpp pointer and returns true if it actually is a polymorphic Alias
|
||||
// instance.
|
||||
template <typename Class, enable_if_t<Class::has_alias, int> = 0>
|
||||
bool is_alias(Cpp<Class> *ptr) {
|
||||
return dynamic_cast<Alias<Class> *>(ptr) != nullptr;
|
||||
return dynamic_cast<Alias<Class> *>(ptr) != nullptr;
|
||||
}
|
||||
// Failing fallback version of the above for a no-alias class (always returns false)
|
||||
template <typename /*Class*/>
|
||||
constexpr bool is_alias(void *) { return false; }
|
||||
// Failing fallback version of the above for a no-alias class (always returns
|
||||
// false)
|
||||
template <typename /*Class*/> constexpr bool is_alias(void *) { return false; }
|
||||
|
||||
// Constructs and returns a new object; if the given arguments don't map to a constructor, we fall
|
||||
// back to brace aggregate initiailization so that for aggregate initialization can be used with
|
||||
// py::init, e.g. `py::init<int, int>` to initialize a `struct T { int a; int b; }`. For
|
||||
// non-aggregate types, we need to use an ordinary T(...) constructor (invoking as `T{...}` usually
|
||||
// works, but will not do the expected thing when `T` has an `initializer_list<T>` constructor).
|
||||
template <typename Class, typename... Args, detail::enable_if_t<std::is_constructible<Class, Args...>::value, int> = 0>
|
||||
inline Class *construct_or_initialize(Args &&...args) { return new Class(std::forward<Args>(args)...); }
|
||||
template <typename Class, typename... Args, detail::enable_if_t<!std::is_constructible<Class, Args...>::value, int> = 0>
|
||||
inline Class *construct_or_initialize(Args &&...args) { return new Class{std::forward<Args>(args)...}; }
|
||||
// Constructs and returns a new object; if the given arguments don't map to a
|
||||
// constructor, we fall back to brace aggregate initiailization so that for
|
||||
// aggregate initialization can be used with py::init, e.g. `py::init<int,
|
||||
// int>` to initialize a `struct T { int a; int b; }`. For non-aggregate types,
|
||||
// we need to use an ordinary T(...) constructor (invoking as `T{...}` usually
|
||||
// works, but will not do the expected thing when `T` has an
|
||||
// `initializer_list<T>` constructor).
|
||||
template <
|
||||
typename Class, typename... Args,
|
||||
detail::enable_if_t<std::is_constructible<Class, Args...>::value, int> = 0>
|
||||
inline Class *construct_or_initialize(Args &&... args) {
|
||||
return new Class(std::forward<Args>(args)...);
|
||||
}
|
||||
template <
|
||||
typename Class, typename... Args,
|
||||
detail::enable_if_t<!std::is_constructible<Class, Args...>::value, int> = 0>
|
||||
inline Class *construct_or_initialize(Args &&... args) {
|
||||
return new Class{std::forward<Args>(args)...};
|
||||
}
|
||||
|
||||
// Attempts to constructs an alias using a `Alias(Cpp &&)` constructor. This allows types with
|
||||
// an alias to provide only a single Cpp factory function as long as the Alias can be
|
||||
// constructed from an rvalue reference of the base Cpp type. This means that Alias classes
|
||||
// can, when appropriate, simply define a `Alias(Cpp &&)` constructor rather than needing to
|
||||
// inherit all the base class constructors.
|
||||
// Attempts to constructs an alias using a `Alias(Cpp &&)` constructor. This
|
||||
// allows types with an alias to provide only a single Cpp factory function as
|
||||
// long as the Alias can be constructed from an rvalue reference of the base Cpp
|
||||
// type. This means that Alias classes can, when appropriate, simply define a
|
||||
// `Alias(Cpp &&)` constructor rather than needing to inherit all the base class
|
||||
// constructors.
|
||||
template <typename Class>
|
||||
void construct_alias_from_cpp(std::true_type /*is_alias_constructible*/,
|
||||
value_and_holder &v_h, Cpp<Class> &&base) {
|
||||
v_h.value_ptr() = new Alias<Class>(std::move(base));
|
||||
v_h.value_ptr() = new Alias<Class>(std::move(base));
|
||||
}
|
||||
template <typename Class>
|
||||
[[noreturn]] void construct_alias_from_cpp(std::false_type /*!is_alias_constructible*/,
|
||||
value_and_holder &, Cpp<Class> &&) {
|
||||
throw type_error("pybind11::init(): unable to convert returned instance to required "
|
||||
"alias class: no `Alias<Class>(Class &&)` constructor available");
|
||||
[[noreturn]] void
|
||||
construct_alias_from_cpp(std::false_type /*!is_alias_constructible*/,
|
||||
value_and_holder &, Cpp<Class> &&) {
|
||||
throw type_error(
|
||||
"pybind11::init(): unable to convert returned instance to required "
|
||||
"alias class: no `Alias<Class>(Class &&)` constructor available");
|
||||
}
|
||||
|
||||
// Error-generating fallback for factories that don't match one of the below construction
|
||||
// mechanisms.
|
||||
template <typename Class>
|
||||
void construct(...) {
|
||||
static_assert(!std::is_same<Class, Class>::value /* always false */,
|
||||
"pybind11::init(): init function must return a compatible pointer, "
|
||||
"holder, or value");
|
||||
// Error-generating fallback for factories that don't match one of the below
|
||||
// construction mechanisms.
|
||||
template <typename Class> void construct(...) {
|
||||
static_assert(
|
||||
!std::is_same<Class, Class>::value /* always false */,
|
||||
"pybind11::init(): init function must return a compatible pointer, "
|
||||
"holder, or value");
|
||||
}
|
||||
|
||||
// Pointer return v1: the factory function returns a class pointer for a registered class.
|
||||
// If we don't need an alias (because this class doesn't have one, or because the final type is
|
||||
// inherited on the Python side) we can simply take over ownership. Otherwise we need to try to
|
||||
// construct an Alias from the returned base instance.
|
||||
// Pointer return v1: the factory function returns a class pointer for a
|
||||
// registered class. If we don't need an alias (because this class doesn't have
|
||||
// one, or because the final type is inherited on the Python side) we can simply
|
||||
// take over ownership. Otherwise we need to try to construct an Alias from the
|
||||
// returned base instance.
|
||||
template <typename Class>
|
||||
void construct(value_and_holder &v_h, Cpp<Class> *ptr, bool need_alias) {
|
||||
no_nullptr(ptr);
|
||||
if (Class::has_alias && need_alias && !is_alias<Class>(ptr)) {
|
||||
// We're going to try to construct an alias by moving the cpp type. Whether or not
|
||||
// that succeeds, we still need to destroy the original cpp pointer (either the
|
||||
// moved away leftover, if the alias construction works, or the value itself if we
|
||||
// throw an error), but we can't just call `delete ptr`: it might have a special
|
||||
// deleter, or might be shared_from_this. So we construct a holder around it as if
|
||||
// it was a normal instance, then steal the holder away into a local variable; thus
|
||||
// the holder and destruction happens when we leave the C++ scope, and the holder
|
||||
// class gets to handle the destruction however it likes.
|
||||
v_h.value_ptr() = ptr;
|
||||
v_h.set_instance_registered(true); // To prevent init_instance from registering it
|
||||
v_h.type->init_instance(v_h.inst, nullptr); // Set up the holder
|
||||
Holder<Class> temp_holder(std::move(v_h.holder<Holder<Class>>())); // Steal the holder
|
||||
v_h.type->dealloc(v_h); // Destroys the moved-out holder remains, resets value ptr to null
|
||||
v_h.set_instance_registered(false);
|
||||
no_nullptr(ptr);
|
||||
if (Class::has_alias && need_alias && !is_alias<Class>(ptr)) {
|
||||
// We're going to try to construct an alias by moving the cpp type. Whether
|
||||
// or not that succeeds, we still need to destroy the original cpp pointer
|
||||
// (either the moved away leftover, if the alias construction works, or the
|
||||
// value itself if we throw an error), but we can't just call `delete ptr`:
|
||||
// it might have a special deleter, or might be shared_from_this. So we
|
||||
// construct a holder around it as if it was a normal instance, then steal
|
||||
// the holder away into a local variable; thus the holder and destruction
|
||||
// happens when we leave the C++ scope, and the holder class gets to handle
|
||||
// the destruction however it likes.
|
||||
v_h.value_ptr() = ptr;
|
||||
v_h.set_instance_registered(
|
||||
true); // To prevent init_instance from registering it
|
||||
v_h.type->init_instance(v_h.inst, nullptr); // Set up the holder
|
||||
Holder<Class> temp_holder(
|
||||
std::move(v_h.holder<Holder<Class>>())); // Steal the holder
|
||||
v_h.type->dealloc(
|
||||
v_h); // Destroys the moved-out holder remains, resets value ptr to null
|
||||
v_h.set_instance_registered(false);
|
||||
|
||||
construct_alias_from_cpp<Class>(is_alias_constructible<Class>{}, v_h, std::move(*ptr));
|
||||
} else {
|
||||
// Otherwise the type isn't inherited, so we don't need an Alias
|
||||
v_h.value_ptr() = ptr;
|
||||
}
|
||||
construct_alias_from_cpp<Class>(is_alias_constructible<Class>{}, v_h,
|
||||
std::move(*ptr));
|
||||
} else {
|
||||
// Otherwise the type isn't inherited, so we don't need an Alias
|
||||
v_h.value_ptr() = ptr;
|
||||
}
|
||||
}
|
||||
|
||||
// Pointer return v2: a factory that always returns an alias instance ptr. We simply take over
|
||||
// ownership of the pointer.
|
||||
// Pointer return v2: a factory that always returns an alias instance ptr. We
|
||||
// simply take over ownership of the pointer.
|
||||
template <typename Class, enable_if_t<Class::has_alias, int> = 0>
|
||||
void construct(value_and_holder &v_h, Alias<Class> *alias_ptr, bool) {
|
||||
no_nullptr(alias_ptr);
|
||||
v_h.value_ptr() = static_cast<Cpp<Class> *>(alias_ptr);
|
||||
no_nullptr(alias_ptr);
|
||||
v_h.value_ptr() = static_cast<Cpp<Class> *>(alias_ptr);
|
||||
}
|
||||
|
||||
// Holder return: copy its pointer, and move or copy the returned holder into the new instance's
|
||||
// holder. This also handles types like std::shared_ptr<T> and std::unique_ptr<T> where T is a
|
||||
// derived type (through those holder's implicit conversion from derived class holder constructors).
|
||||
// Holder return: copy its pointer, and move or copy the returned holder into
|
||||
// the new instance's holder. This also handles types like std::shared_ptr<T>
|
||||
// and std::unique_ptr<T> where T is a derived type (through those holder's
|
||||
// implicit conversion from derived class holder constructors).
|
||||
template <typename Class>
|
||||
void construct(value_and_holder &v_h, Holder<Class> holder, bool need_alias) {
|
||||
auto *ptr = holder_helper<Holder<Class>>::get(holder);
|
||||
// If we need an alias, check that the held pointer is actually an alias instance
|
||||
if (Class::has_alias && need_alias && !is_alias<Class>(ptr))
|
||||
throw type_error("pybind11::init(): construction failed: returned holder-wrapped instance "
|
||||
"is not an alias instance");
|
||||
auto *ptr = holder_helper<Holder<Class>>::get(holder);
|
||||
// If we need an alias, check that the held pointer is actually an alias
|
||||
// instance
|
||||
if (Class::has_alias && need_alias && !is_alias<Class>(ptr))
|
||||
throw type_error("pybind11::init(): construction failed: returned "
|
||||
"holder-wrapped instance "
|
||||
"is not an alias instance");
|
||||
|
||||
v_h.value_ptr() = ptr;
|
||||
v_h.type->init_instance(v_h.inst, &holder);
|
||||
v_h.value_ptr() = ptr;
|
||||
v_h.type->init_instance(v_h.inst, &holder);
|
||||
}
|
||||
|
||||
// return-by-value version 1: returning a cpp class by value. If the class has an alias and an
|
||||
// alias is required the alias must have an `Alias(Cpp &&)` constructor so that we can construct
|
||||
// the alias from the base when needed (i.e. because of Python-side inheritance). When we don't
|
||||
// need it, we simply move-construct the cpp value into a new instance.
|
||||
// return-by-value version 1: returning a cpp class by value. If the class has
|
||||
// an alias and an alias is required the alias must have an `Alias(Cpp &&)`
|
||||
// constructor so that we can construct the alias from the base when needed
|
||||
// (i.e. because of Python-side inheritance). When we don't need it, we simply
|
||||
// move-construct the cpp value into a new instance.
|
||||
template <typename Class>
|
||||
void construct(value_and_holder &v_h, Cpp<Class> &&result, bool need_alias) {
|
||||
static_assert(std::is_move_constructible<Cpp<Class>>::value,
|
||||
"pybind11::init() return-by-value factory function requires a movable class");
|
||||
if (Class::has_alias && need_alias)
|
||||
construct_alias_from_cpp<Class>(is_alias_constructible<Class>{}, v_h, std::move(result));
|
||||
else
|
||||
v_h.value_ptr() = new Cpp<Class>(std::move(result));
|
||||
static_assert(std::is_move_constructible<Cpp<Class>>::value,
|
||||
"pybind11::init() return-by-value factory function requires a "
|
||||
"movable class");
|
||||
if (Class::has_alias && need_alias)
|
||||
construct_alias_from_cpp<Class>(is_alias_constructible<Class>{}, v_h,
|
||||
std::move(result));
|
||||
else
|
||||
v_h.value_ptr() = new Cpp<Class>(std::move(result));
|
||||
}
|
||||
|
||||
// return-by-value version 2: returning a value of the alias type itself. We move-construct an
|
||||
// Alias instance (even if no the python-side inheritance is involved). The is intended for
|
||||
// cases where Alias initialization is always desired.
|
||||
// return-by-value version 2: returning a value of the alias type itself. We
|
||||
// move-construct an Alias instance (even if no the python-side inheritance is
|
||||
// involved). The is intended for cases where Alias initialization is always
|
||||
// desired.
|
||||
template <typename Class>
|
||||
void construct(value_and_holder &v_h, Alias<Class> &&result, bool) {
|
||||
static_assert(std::is_move_constructible<Alias<Class>>::value,
|
||||
"pybind11::init() return-by-alias-value factory function requires a movable alias class");
|
||||
v_h.value_ptr() = new Alias<Class>(std::move(result));
|
||||
static_assert(std::is_move_constructible<Alias<Class>>::value,
|
||||
"pybind11::init() return-by-alias-value factory function "
|
||||
"requires a movable alias class");
|
||||
v_h.value_ptr() = new Alias<Class>(std::move(result));
|
||||
}
|
||||
|
||||
// Implementing class for py::init<...>()
|
||||
template <typename... Args>
|
||||
struct constructor {
|
||||
template <typename Class, typename... Extra, enable_if_t<!Class::has_alias, int> = 0>
|
||||
static void execute(Class &cl, const Extra&... extra) {
|
||||
cl.def("__init__", [](value_and_holder &v_h, Args... args) {
|
||||
v_h.value_ptr() = construct_or_initialize<Cpp<Class>>(std::forward<Args>(args)...);
|
||||
}, is_new_style_constructor(), extra...);
|
||||
}
|
||||
template <typename... Args> struct constructor {
|
||||
template <typename Class, typename... Extra,
|
||||
enable_if_t<!Class::has_alias, int> = 0>
|
||||
static void execute(Class &cl, const Extra &... extra) {
|
||||
cl.def(
|
||||
"__init__",
|
||||
[](value_and_holder &v_h, Args... args) {
|
||||
v_h.value_ptr() =
|
||||
construct_or_initialize<Cpp<Class>>(std::forward<Args>(args)...);
|
||||
},
|
||||
is_new_style_constructor(), extra...);
|
||||
}
|
||||
|
||||
template <typename Class, typename... Extra,
|
||||
enable_if_t<Class::has_alias &&
|
||||
std::is_constructible<Cpp<Class>, Args...>::value, int> = 0>
|
||||
static void execute(Class &cl, const Extra&... extra) {
|
||||
cl.def("__init__", [](value_and_holder &v_h, Args... args) {
|
||||
if (Py_TYPE(v_h.inst) == v_h.type->type)
|
||||
v_h.value_ptr() = construct_or_initialize<Cpp<Class>>(std::forward<Args>(args)...);
|
||||
else
|
||||
v_h.value_ptr() = construct_or_initialize<Alias<Class>>(std::forward<Args>(args)...);
|
||||
}, is_new_style_constructor(), extra...);
|
||||
}
|
||||
template <typename Class, typename... Extra,
|
||||
enable_if_t<Class::has_alias &&
|
||||
std::is_constructible<Cpp<Class>, Args...>::value,
|
||||
int> = 0>
|
||||
static void execute(Class &cl, const Extra &... extra) {
|
||||
cl.def(
|
||||
"__init__",
|
||||
[](value_and_holder &v_h, Args... args) {
|
||||
if (Py_TYPE(v_h.inst) == v_h.type->type)
|
||||
v_h.value_ptr() = construct_or_initialize<Cpp<Class>>(
|
||||
std::forward<Args>(args)...);
|
||||
else
|
||||
v_h.value_ptr() = construct_or_initialize<Alias<Class>>(
|
||||
std::forward<Args>(args)...);
|
||||
},
|
||||
is_new_style_constructor(), extra...);
|
||||
}
|
||||
|
||||
template <typename Class, typename... Extra,
|
||||
enable_if_t<Class::has_alias &&
|
||||
!std::is_constructible<Cpp<Class>, Args...>::value, int> = 0>
|
||||
static void execute(Class &cl, const Extra&... extra) {
|
||||
cl.def("__init__", [](value_and_holder &v_h, Args... args) {
|
||||
v_h.value_ptr() = construct_or_initialize<Alias<Class>>(std::forward<Args>(args)...);
|
||||
}, is_new_style_constructor(), extra...);
|
||||
}
|
||||
template <typename Class, typename... Extra,
|
||||
enable_if_t<Class::has_alias &&
|
||||
!std::is_constructible<Cpp<Class>, Args...>::value,
|
||||
int> = 0>
|
||||
static void execute(Class &cl, const Extra &... extra) {
|
||||
cl.def(
|
||||
"__init__",
|
||||
[](value_and_holder &v_h, Args... args) {
|
||||
v_h.value_ptr() = construct_or_initialize<Alias<Class>>(
|
||||
std::forward<Args>(args)...);
|
||||
},
|
||||
is_new_style_constructor(), extra...);
|
||||
}
|
||||
};
|
||||
|
||||
// Implementing class for py::init_alias<...>()
|
||||
template <typename... Args> struct alias_constructor {
|
||||
template <typename Class, typename... Extra,
|
||||
enable_if_t<Class::has_alias && std::is_constructible<Alias<Class>, Args...>::value, int> = 0>
|
||||
static void execute(Class &cl, const Extra&... extra) {
|
||||
cl.def("__init__", [](value_and_holder &v_h, Args... args) {
|
||||
v_h.value_ptr() = construct_or_initialize<Alias<Class>>(std::forward<Args>(args)...);
|
||||
}, is_new_style_constructor(), extra...);
|
||||
}
|
||||
template <typename Class, typename... Extra,
|
||||
enable_if_t<Class::has_alias &&
|
||||
std::is_constructible<Alias<Class>, Args...>::value,
|
||||
int> = 0>
|
||||
static void execute(Class &cl, const Extra &... extra) {
|
||||
cl.def(
|
||||
"__init__",
|
||||
[](value_and_holder &v_h, Args... args) {
|
||||
v_h.value_ptr() = construct_or_initialize<Alias<Class>>(
|
||||
std::forward<Args>(args)...);
|
||||
},
|
||||
is_new_style_constructor(), extra...);
|
||||
}
|
||||
};
|
||||
|
||||
// Implementation class for py::init(Func) and py::init(Func, AliasFunc)
|
||||
template <typename CFunc, typename AFunc = void_type (*)(),
|
||||
typename = function_signature_t<CFunc>, typename = function_signature_t<AFunc>>
|
||||
typename = function_signature_t<CFunc>,
|
||||
typename = function_signature_t<AFunc>>
|
||||
struct factory;
|
||||
|
||||
// Specialization for py::init(Func)
|
||||
template <typename Func, typename Return, typename... Args>
|
||||
struct factory<Func, void_type (*)(), Return(Args...)> {
|
||||
remove_reference_t<Func> class_factory;
|
||||
remove_reference_t<Func> class_factory;
|
||||
|
||||
factory(Func &&f) : class_factory(std::forward<Func>(f)) { }
|
||||
factory(Func &&f) : class_factory(std::forward<Func>(f)) {}
|
||||
|
||||
// The given class either has no alias or has no separate alias factory;
|
||||
// this always constructs the class itself. If the class is registered with an alias
|
||||
// type and an alias instance is needed (i.e. because the final type is a Python class
|
||||
// inheriting from the C++ type) the returned value needs to either already be an alias
|
||||
// instance, or the alias needs to be constructible from a `Class &&` argument.
|
||||
template <typename Class, typename... Extra>
|
||||
void execute(Class &cl, const Extra &...extra) && {
|
||||
#if defined(PYBIND11_CPP14)
|
||||
cl.def("__init__", [func = std::move(class_factory)]
|
||||
#else
|
||||
auto &func = class_factory;
|
||||
cl.def("__init__", [func]
|
||||
#endif
|
||||
// The given class either has no alias or has no separate alias factory;
|
||||
// this always constructs the class itself. If the class is registered with
|
||||
// an alias type and an alias instance is needed (i.e. because the final type
|
||||
// is a Python class inheriting from the C++ type) the returned value needs to
|
||||
// either already be an alias instance, or the alias needs to be constructible
|
||||
// from a `Class &&` argument.
|
||||
template <typename Class, typename... Extra>
|
||||
void execute(Class &cl, const Extra &... extra) && {
|
||||
#if defined(PYBIND11_CPP14)
|
||||
cl.def(
|
||||
"__init__",
|
||||
[func = std::move(class_factory)]
|
||||
#else
|
||||
auto &func = class_factory;
|
||||
cl.def(
|
||||
"__init__",
|
||||
[func]
|
||||
#endif
|
||||
(value_and_holder &v_h, Args... args) {
|
||||
construct<Class>(v_h, func(std::forward<Args>(args)...),
|
||||
Py_TYPE(v_h.inst) != v_h.type->type);
|
||||
}, is_new_style_constructor(), extra...);
|
||||
}
|
||||
construct<Class>(v_h, func(std::forward<Args>(args)...),
|
||||
Py_TYPE(v_h.inst) != v_h.type->type);
|
||||
},
|
||||
is_new_style_constructor(), extra...);
|
||||
}
|
||||
};
|
||||
|
||||
// Specialization for py::init(Func, AliasFunc)
|
||||
template <typename CFunc, typename AFunc,
|
||||
typename CReturn, typename... CArgs, typename AReturn, typename... AArgs>
|
||||
template <typename CFunc, typename AFunc, typename CReturn, typename... CArgs,
|
||||
typename AReturn, typename... AArgs>
|
||||
struct factory<CFunc, AFunc, CReturn(CArgs...), AReturn(AArgs...)> {
|
||||
static_assert(sizeof...(CArgs) == sizeof...(AArgs),
|
||||
"pybind11::init(class_factory, alias_factory): class and alias factories "
|
||||
"must have identical argument signatures");
|
||||
static_assert(all_of<std::is_same<CArgs, AArgs>...>::value,
|
||||
"pybind11::init(class_factory, alias_factory): class and alias factories "
|
||||
"must have identical argument signatures");
|
||||
static_assert(
|
||||
sizeof...(CArgs) == sizeof...(AArgs),
|
||||
"pybind11::init(class_factory, alias_factory): class and alias factories "
|
||||
"must have identical argument signatures");
|
||||
static_assert(
|
||||
all_of<std::is_same<CArgs, AArgs>...>::value,
|
||||
"pybind11::init(class_factory, alias_factory): class and alias factories "
|
||||
"must have identical argument signatures");
|
||||
|
||||
remove_reference_t<CFunc> class_factory;
|
||||
remove_reference_t<AFunc> alias_factory;
|
||||
remove_reference_t<CFunc> class_factory;
|
||||
remove_reference_t<AFunc> alias_factory;
|
||||
|
||||
factory(CFunc &&c, AFunc &&a)
|
||||
: class_factory(std::forward<CFunc>(c)), alias_factory(std::forward<AFunc>(a)) { }
|
||||
factory(CFunc &&c, AFunc &&a)
|
||||
: class_factory(std::forward<CFunc>(c)),
|
||||
alias_factory(std::forward<AFunc>(a)) {}
|
||||
|
||||
// The class factory is called when the `self` type passed to `__init__` is the direct
|
||||
// class (i.e. not inherited), the alias factory when `self` is a Python-side subtype.
|
||||
template <typename Class, typename... Extra>
|
||||
void execute(Class &cl, const Extra&... extra) && {
|
||||
static_assert(Class::has_alias, "The two-argument version of `py::init()` can "
|
||||
"only be used if the class has an alias");
|
||||
#if defined(PYBIND11_CPP14)
|
||||
cl.def("__init__", [class_func = std::move(class_factory), alias_func = std::move(alias_factory)]
|
||||
#else
|
||||
auto &class_func = class_factory;
|
||||
auto &alias_func = alias_factory;
|
||||
cl.def("__init__", [class_func, alias_func]
|
||||
#endif
|
||||
// The class factory is called when the `self` type passed to `__init__` is
|
||||
// the direct class (i.e. not inherited), the alias factory when `self` is a
|
||||
// Python-side subtype.
|
||||
template <typename Class, typename... Extra>
|
||||
void execute(Class &cl, const Extra &... extra) && {
|
||||
static_assert(Class::has_alias,
|
||||
"The two-argument version of `py::init()` can "
|
||||
"only be used if the class has an alias");
|
||||
#if defined(PYBIND11_CPP14)
|
||||
cl.def(
|
||||
"__init__",
|
||||
[class_func = std::move(class_factory),
|
||||
alias_func = std::move(alias_factory)]
|
||||
#else
|
||||
auto &class_func = class_factory;
|
||||
auto &alias_func = alias_factory;
|
||||
cl.def(
|
||||
"__init__",
|
||||
[class_func, alias_func]
|
||||
#endif
|
||||
(value_and_holder &v_h, CArgs... args) {
|
||||
if (Py_TYPE(v_h.inst) == v_h.type->type)
|
||||
// If the instance type equals the registered type we don't have inheritance, so
|
||||
// don't need the alias and can construct using the class function:
|
||||
construct<Class>(v_h, class_func(std::forward<CArgs>(args)...), false);
|
||||
else
|
||||
construct<Class>(v_h, alias_func(std::forward<CArgs>(args)...), true);
|
||||
}, is_new_style_constructor(), extra...);
|
||||
}
|
||||
if (Py_TYPE(v_h.inst) == v_h.type->type)
|
||||
// If the instance type equals the registered type we don't have
|
||||
// inheritance, so don't need the alias and can construct using the
|
||||
// class function:
|
||||
construct<Class>(v_h, class_func(std::forward<CArgs>(args)...),
|
||||
false);
|
||||
else
|
||||
construct<Class>(v_h, alias_func(std::forward<CArgs>(args)...),
|
||||
true);
|
||||
},
|
||||
is_new_style_constructor(), extra...);
|
||||
}
|
||||
};
|
||||
|
||||
/// Set just the C++ state. Same as `__init__`.
|
||||
template <typename Class, typename T>
|
||||
void setstate(value_and_holder &v_h, T &&result, bool need_alias) {
|
||||
construct<Class>(v_h, std::forward<T>(result), need_alias);
|
||||
construct<Class>(v_h, std::forward<T>(result), need_alias);
|
||||
}
|
||||
|
||||
/// Set both the C++ and Python states
|
||||
template <typename Class, typename T, typename O,
|
||||
enable_if_t<std::is_convertible<O, handle>::value, int> = 0>
|
||||
void setstate(value_and_holder &v_h, std::pair<T, O> &&result, bool need_alias) {
|
||||
construct<Class>(v_h, std::move(result.first), need_alias);
|
||||
setattr((PyObject *) v_h.inst, "__dict__", result.second);
|
||||
void setstate(value_and_holder &v_h, std::pair<T, O> &&result,
|
||||
bool need_alias) {
|
||||
construct<Class>(v_h, std::move(result.first), need_alias);
|
||||
setattr((PyObject *)v_h.inst, "__dict__", result.second);
|
||||
}
|
||||
|
||||
/// Implementation for py::pickle(GetState, SetState)
|
||||
template <typename Get, typename Set,
|
||||
typename = function_signature_t<Get>, typename = function_signature_t<Set>>
|
||||
template <typename Get, typename Set, typename = function_signature_t<Get>,
|
||||
typename = function_signature_t<Set>>
|
||||
struct pickle_factory;
|
||||
|
||||
template <typename Get, typename Set,
|
||||
typename RetState, typename Self, typename NewInstance, typename ArgState>
|
||||
template <typename Get, typename Set, typename RetState, typename Self,
|
||||
typename NewInstance, typename ArgState>
|
||||
struct pickle_factory<Get, Set, RetState(Self), NewInstance(ArgState)> {
|
||||
static_assert(std::is_same<intrinsic_t<RetState>, intrinsic_t<ArgState>>::value,
|
||||
"The type returned by `__getstate__` must be the same "
|
||||
"as the argument accepted by `__setstate__`");
|
||||
static_assert(
|
||||
std::is_same<intrinsic_t<RetState>, intrinsic_t<ArgState>>::value,
|
||||
"The type returned by `__getstate__` must be the same "
|
||||
"as the argument accepted by `__setstate__`");
|
||||
|
||||
remove_reference_t<Get> get;
|
||||
remove_reference_t<Set> set;
|
||||
remove_reference_t<Get> get;
|
||||
remove_reference_t<Set> set;
|
||||
|
||||
pickle_factory(Get get, Set set)
|
||||
: get(std::forward<Get>(get)), set(std::forward<Set>(set)) { }
|
||||
pickle_factory(Get get, Set set)
|
||||
: get(std::forward<Get>(get)), set(std::forward<Set>(set)) {}
|
||||
|
||||
template <typename Class, typename... Extra>
|
||||
void execute(Class &cl, const Extra &...extra) && {
|
||||
cl.def("__getstate__", std::move(get));
|
||||
template <typename Class, typename... Extra>
|
||||
void execute(Class &cl, const Extra &... extra) && {
|
||||
cl.def("__getstate__", std::move(get));
|
||||
|
||||
#if defined(PYBIND11_CPP14)
|
||||
cl.def("__setstate__", [func = std::move(set)]
|
||||
cl.def(
|
||||
"__setstate__",
|
||||
[func = std::move(set)]
|
||||
#else
|
||||
auto &func = set;
|
||||
cl.def("__setstate__", [func]
|
||||
auto &func = set;
|
||||
cl.def(
|
||||
"__setstate__",
|
||||
[func]
|
||||
#endif
|
||||
(value_and_holder &v_h, ArgState state) {
|
||||
setstate<Class>(v_h, func(std::forward<ArgState>(state)),
|
||||
Py_TYPE(v_h.inst) != v_h.type->type);
|
||||
}, is_new_style_constructor(), extra...);
|
||||
}
|
||||
setstate<Class>(v_h, func(std::forward<ArgState>(state)),
|
||||
Py_TYPE(v_h.inst) != v_h.type->type);
|
||||
},
|
||||
is_new_style_constructor(), extra...);
|
||||
}
|
||||
};
|
||||
|
||||
NAMESPACE_END(initimpl)
|
||||
|
@@ -18,276 +18,323 @@ inline PyTypeObject *make_static_property_type();
|
||||
inline PyTypeObject *make_default_metaclass();
|
||||
inline PyObject *make_object_base_type(PyTypeObject *metaclass);
|
||||
|
||||
// The old Python Thread Local Storage (TLS) API is deprecated in Python 3.7 in favor of the new
|
||||
// Thread Specific Storage (TSS) API.
|
||||
// The old Python Thread Local Storage (TLS) API is deprecated in Python 3.7 in
|
||||
// favor of the new Thread Specific Storage (TSS) API.
|
||||
#if PY_VERSION_HEX >= 0x03070000
|
||||
# define PYBIND11_TLS_KEY_INIT(var) Py_tss_t *var = nullptr
|
||||
# define PYBIND11_TLS_GET_VALUE(key) PyThread_tss_get((key))
|
||||
# define PYBIND11_TLS_REPLACE_VALUE(key, value) PyThread_tss_set((key), (value))
|
||||
# define PYBIND11_TLS_DELETE_VALUE(key) PyThread_tss_set((key), nullptr)
|
||||
#define PYBIND11_TLS_KEY_INIT(var) Py_tss_t *var = nullptr
|
||||
#define PYBIND11_TLS_GET_VALUE(key) PyThread_tss_get((key))
|
||||
#define PYBIND11_TLS_REPLACE_VALUE(key, value) PyThread_tss_set((key), (value))
|
||||
#define PYBIND11_TLS_DELETE_VALUE(key) PyThread_tss_set((key), nullptr)
|
||||
#else
|
||||
// Usually an int but a long on Cygwin64 with Python 3.x
|
||||
# define PYBIND11_TLS_KEY_INIT(var) decltype(PyThread_create_key()) var = 0
|
||||
# define PYBIND11_TLS_GET_VALUE(key) PyThread_get_key_value((key))
|
||||
# if PY_MAJOR_VERSION < 3
|
||||
# define PYBIND11_TLS_DELETE_VALUE(key) \
|
||||
PyThread_delete_key_value(key)
|
||||
# define PYBIND11_TLS_REPLACE_VALUE(key, value) \
|
||||
do { \
|
||||
PyThread_delete_key_value((key)); \
|
||||
PyThread_set_key_value((key), (value)); \
|
||||
} while (false)
|
||||
# else
|
||||
# define PYBIND11_TLS_DELETE_VALUE(key) \
|
||||
PyThread_set_key_value((key), nullptr)
|
||||
# define PYBIND11_TLS_REPLACE_VALUE(key, value) \
|
||||
PyThread_set_key_value((key), (value))
|
||||
# endif
|
||||
// Usually an int but a long on Cygwin64 with Python 3.x
|
||||
#define PYBIND11_TLS_KEY_INIT(var) decltype(PyThread_create_key()) var = 0
|
||||
#define PYBIND11_TLS_GET_VALUE(key) PyThread_get_key_value((key))
|
||||
#if PY_MAJOR_VERSION < 3
|
||||
#define PYBIND11_TLS_DELETE_VALUE(key) PyThread_delete_key_value(key)
|
||||
#define PYBIND11_TLS_REPLACE_VALUE(key, value) \
|
||||
do { \
|
||||
PyThread_delete_key_value((key)); \
|
||||
PyThread_set_key_value((key), (value)); \
|
||||
} while (false)
|
||||
#else
|
||||
#define PYBIND11_TLS_DELETE_VALUE(key) PyThread_set_key_value((key), nullptr)
|
||||
#define PYBIND11_TLS_REPLACE_VALUE(key, value) \
|
||||
PyThread_set_key_value((key), (value))
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Python loads modules by default with dlopen with the RTLD_LOCAL flag; under libc++ and possibly
|
||||
// other STLs, this means `typeid(A)` from one module won't equal `typeid(A)` from another module
|
||||
// even when `A` is the same, non-hidden-visibility type (e.g. from a common include). Under
|
||||
// libstdc++, this doesn't happen: equality and the type_index hash are based on the type name,
|
||||
// which works. If not under a known-good stl, provide our own name-based hash and equality
|
||||
// functions that use the type name.
|
||||
// Python loads modules by default with dlopen with the RTLD_LOCAL flag; under
|
||||
// libc++ and possibly other STLs, this means `typeid(A)` from one module won't
|
||||
// equal `typeid(A)` from another module even when `A` is the same,
|
||||
// non-hidden-visibility type (e.g. from a common include). Under libstdc++,
|
||||
// this doesn't happen: equality and the type_index hash are based on the type
|
||||
// name, which works. If not under a known-good stl, provide our own name-based
|
||||
// hash and equality functions that use the type name.
|
||||
#if defined(__GLIBCXX__)
|
||||
inline bool same_type(const std::type_info &lhs, const std::type_info &rhs) { return lhs == rhs; }
|
||||
inline bool same_type(const std::type_info &lhs, const std::type_info &rhs) {
|
||||
return lhs == rhs;
|
||||
}
|
||||
using type_hash = std::hash<std::type_index>;
|
||||
using type_equal_to = std::equal_to<std::type_index>;
|
||||
#else
|
||||
inline bool same_type(const std::type_info &lhs, const std::type_info &rhs) {
|
||||
return lhs.name() == rhs.name() || std::strcmp(lhs.name(), rhs.name()) == 0;
|
||||
return lhs.name() == rhs.name() || std::strcmp(lhs.name(), rhs.name()) == 0;
|
||||
}
|
||||
|
||||
struct type_hash {
|
||||
size_t operator()(const std::type_index &t) const {
|
||||
size_t hash = 5381;
|
||||
const char *ptr = t.name();
|
||||
while (auto c = static_cast<unsigned char>(*ptr++))
|
||||
hash = (hash * 33) ^ c;
|
||||
return hash;
|
||||
}
|
||||
size_t operator()(const std::type_index &t) const {
|
||||
size_t hash = 5381;
|
||||
const char *ptr = t.name();
|
||||
while (auto c = static_cast<unsigned char>(*ptr++))
|
||||
hash = (hash * 33) ^ c;
|
||||
return hash;
|
||||
}
|
||||
};
|
||||
|
||||
struct type_equal_to {
|
||||
bool operator()(const std::type_index &lhs, const std::type_index &rhs) const {
|
||||
return lhs.name() == rhs.name() || std::strcmp(lhs.name(), rhs.name()) == 0;
|
||||
}
|
||||
bool operator()(const std::type_index &lhs,
|
||||
const std::type_index &rhs) const {
|
||||
return lhs.name() == rhs.name() || std::strcmp(lhs.name(), rhs.name()) == 0;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
template <typename value_type>
|
||||
using type_map = std::unordered_map<std::type_index, value_type, type_hash, type_equal_to>;
|
||||
using type_map =
|
||||
std::unordered_map<std::type_index, value_type, type_hash, type_equal_to>;
|
||||
|
||||
struct overload_hash {
|
||||
inline size_t operator()(const std::pair<const PyObject *, const char *>& v) const {
|
||||
size_t value = std::hash<const void *>()(v.first);
|
||||
value ^= std::hash<const void *>()(v.second) + 0x9e3779b9 + (value<<6) + (value>>2);
|
||||
return value;
|
||||
}
|
||||
inline size_t
|
||||
operator()(const std::pair<const PyObject *, const char *> &v) const {
|
||||
size_t value = std::hash<const void *>()(v.first);
|
||||
value ^= std::hash<const void *>()(v.second) + 0x9e3779b9 + (value << 6) +
|
||||
(value >> 2);
|
||||
return value;
|
||||
}
|
||||
};
|
||||
|
||||
/// Internal data structure used to track registered instances and types.
|
||||
/// Whenever binary incompatible changes are made to this structure,
|
||||
/// `PYBIND11_INTERNALS_VERSION` must be incremented.
|
||||
struct internals {
|
||||
type_map<type_info *> registered_types_cpp; // std::type_index -> pybind11's type information
|
||||
std::unordered_map<PyTypeObject *, std::vector<type_info *>> registered_types_py; // PyTypeObject* -> base type_info(s)
|
||||
std::unordered_multimap<const void *, instance*> registered_instances; // void * -> instance*
|
||||
std::unordered_set<std::pair<const PyObject *, const char *>, overload_hash> inactive_overload_cache;
|
||||
type_map<std::vector<bool (*)(PyObject *, void *&)>> direct_conversions;
|
||||
std::unordered_map<const PyObject *, std::vector<PyObject *>> patients;
|
||||
std::forward_list<void (*) (std::exception_ptr)> registered_exception_translators;
|
||||
std::unordered_map<std::string, void *> shared_data; // Custom data to be shared across extensions
|
||||
std::vector<PyObject *> loader_patient_stack; // Used by `loader_life_support`
|
||||
std::forward_list<std::string> static_strings; // Stores the std::strings backing detail::c_str()
|
||||
PyTypeObject *static_property_type;
|
||||
PyTypeObject *default_metaclass;
|
||||
PyObject *instance_base;
|
||||
type_map<type_info *>
|
||||
registered_types_cpp; // std::type_index -> pybind11's type information
|
||||
std::unordered_map<PyTypeObject *, std::vector<type_info *>>
|
||||
registered_types_py; // PyTypeObject* -> base type_info(s)
|
||||
std::unordered_multimap<const void *, instance *>
|
||||
registered_instances; // void * -> instance*
|
||||
std::unordered_set<std::pair<const PyObject *, const char *>, overload_hash>
|
||||
inactive_overload_cache;
|
||||
type_map<std::vector<bool (*)(PyObject *, void *&)>> direct_conversions;
|
||||
std::unordered_map<const PyObject *, std::vector<PyObject *>> patients;
|
||||
std::forward_list<void (*)(std::exception_ptr)>
|
||||
registered_exception_translators;
|
||||
std::unordered_map<std::string, void *>
|
||||
shared_data; // Custom data to be shared across extensions
|
||||
std::vector<PyObject *> loader_patient_stack; // Used by `loader_life_support`
|
||||
std::forward_list<std::string>
|
||||
static_strings; // Stores the std::strings backing detail::c_str()
|
||||
PyTypeObject *static_property_type;
|
||||
PyTypeObject *default_metaclass;
|
||||
PyObject *instance_base;
|
||||
#if defined(WITH_THREAD)
|
||||
PYBIND11_TLS_KEY_INIT(tstate);
|
||||
PyInterpreterState *istate = nullptr;
|
||||
PYBIND11_TLS_KEY_INIT(tstate);
|
||||
PyInterpreterState *istate = nullptr;
|
||||
#endif
|
||||
};
|
||||
|
||||
/// Additional type information which does not fit into the PyTypeObject.
|
||||
/// Changes to this struct also require bumping `PYBIND11_INTERNALS_VERSION`.
|
||||
struct type_info {
|
||||
PyTypeObject *type;
|
||||
const std::type_info *cpptype;
|
||||
size_t type_size, type_align, holder_size_in_ptrs;
|
||||
void *(*operator_new)(size_t);
|
||||
void (*init_instance)(instance *, const void *);
|
||||
void (*dealloc)(value_and_holder &v_h);
|
||||
std::vector<PyObject *(*)(PyObject *, PyTypeObject *)> implicit_conversions;
|
||||
std::vector<std::pair<const std::type_info *, void *(*)(void *)>> implicit_casts;
|
||||
std::vector<bool (*)(PyObject *, void *&)> *direct_conversions;
|
||||
buffer_info *(*get_buffer)(PyObject *, void *) = nullptr;
|
||||
void *get_buffer_data = nullptr;
|
||||
void *(*module_local_load)(PyObject *, const type_info *) = nullptr;
|
||||
/* A simple type never occurs as a (direct or indirect) parent
|
||||
* of a class that makes use of multiple inheritance */
|
||||
bool simple_type : 1;
|
||||
/* True if there is no multiple inheritance in this type's inheritance tree */
|
||||
bool simple_ancestors : 1;
|
||||
/* for base vs derived holder_type checks */
|
||||
bool default_holder : 1;
|
||||
/* true if this is a type registered with py::module_local */
|
||||
bool module_local : 1;
|
||||
PyTypeObject *type;
|
||||
const std::type_info *cpptype;
|
||||
size_t type_size, type_align, holder_size_in_ptrs;
|
||||
void *(*operator_new)(size_t);
|
||||
void (*init_instance)(instance *, const void *);
|
||||
void (*dealloc)(value_and_holder &v_h);
|
||||
std::vector<PyObject *(*)(PyObject *, PyTypeObject *)> implicit_conversions;
|
||||
std::vector<std::pair<const std::type_info *, void *(*)(void *)>>
|
||||
implicit_casts;
|
||||
std::vector<bool (*)(PyObject *, void *&)> *direct_conversions;
|
||||
buffer_info *(*get_buffer)(PyObject *, void *) = nullptr;
|
||||
void *get_buffer_data = nullptr;
|
||||
void *(*module_local_load)(PyObject *, const type_info *) = nullptr;
|
||||
/* A simple type never occurs as a (direct or indirect) parent
|
||||
* of a class that makes use of multiple inheritance */
|
||||
bool simple_type : 1;
|
||||
/* True if there is no multiple inheritance in this type's inheritance tree */
|
||||
bool simple_ancestors : 1;
|
||||
/* for base vs derived holder_type checks */
|
||||
bool default_holder : 1;
|
||||
/* true if this is a type registered with py::module_local */
|
||||
bool module_local : 1;
|
||||
};
|
||||
|
||||
/// Tracks the `internals` and `type_info` ABI version independent of the main library version
|
||||
/// Tracks the `internals` and `type_info` ABI version independent of the main
|
||||
/// library version
|
||||
#define PYBIND11_INTERNALS_VERSION 3
|
||||
|
||||
#if defined(_DEBUG)
|
||||
# define PYBIND11_BUILD_TYPE "_debug"
|
||||
#define PYBIND11_BUILD_TYPE "_debug"
|
||||
#else
|
||||
# define PYBIND11_BUILD_TYPE ""
|
||||
#define PYBIND11_BUILD_TYPE ""
|
||||
#endif
|
||||
|
||||
#if defined(WITH_THREAD)
|
||||
# define PYBIND11_INTERNALS_KIND ""
|
||||
#define PYBIND11_INTERNALS_KIND ""
|
||||
#else
|
||||
# define PYBIND11_INTERNALS_KIND "_without_thread"
|
||||
#define PYBIND11_INTERNALS_KIND "_without_thread"
|
||||
#endif
|
||||
|
||||
#define PYBIND11_INTERNALS_ID "__pybind11_internals_v" \
|
||||
PYBIND11_TOSTRING(PYBIND11_INTERNALS_VERSION) PYBIND11_INTERNALS_KIND PYBIND11_BUILD_TYPE "__"
|
||||
#define PYBIND11_INTERNALS_ID \
|
||||
"__pybind11_internals_v" PYBIND11_TOSTRING(PYBIND11_INTERNALS_VERSION) \
|
||||
PYBIND11_INTERNALS_KIND PYBIND11_BUILD_TYPE "__"
|
||||
|
||||
#define PYBIND11_MODULE_LOCAL_ID "__pybind11_module_local_v" \
|
||||
PYBIND11_TOSTRING(PYBIND11_INTERNALS_VERSION) PYBIND11_INTERNALS_KIND PYBIND11_BUILD_TYPE "__"
|
||||
#define PYBIND11_MODULE_LOCAL_ID \
|
||||
"__pybind11_module_local_v" PYBIND11_TOSTRING(PYBIND11_INTERNALS_VERSION) \
|
||||
PYBIND11_INTERNALS_KIND PYBIND11_BUILD_TYPE "__"
|
||||
|
||||
/// Each module locally stores a pointer to the `internals` data. The data
|
||||
/// itself is shared among modules with the same `PYBIND11_INTERNALS_ID`.
|
||||
inline internals **&get_internals_pp() {
|
||||
static internals **internals_pp = nullptr;
|
||||
return internals_pp;
|
||||
static internals **internals_pp = nullptr;
|
||||
return internals_pp;
|
||||
}
|
||||
|
||||
/// Return a reference to the current `internals` data
|
||||
PYBIND11_NOINLINE inline internals &get_internals() {
|
||||
auto **&internals_pp = get_internals_pp();
|
||||
if (internals_pp && *internals_pp)
|
||||
return **internals_pp;
|
||||
|
||||
constexpr auto *id = PYBIND11_INTERNALS_ID;
|
||||
auto builtins = handle(PyEval_GetBuiltins());
|
||||
if (builtins.contains(id) && isinstance<capsule>(builtins[id])) {
|
||||
internals_pp = static_cast<internals **>(capsule(builtins[id]));
|
||||
|
||||
// We loaded builtins through python's builtins, which means that our `error_already_set`
|
||||
// and `builtin_exception` may be different local classes than the ones set up in the
|
||||
// initial exception translator, below, so add another for our local exception classes.
|
||||
//
|
||||
// libstdc++ doesn't require this (types there are identified only by name)
|
||||
#if !defined(__GLIBCXX__)
|
||||
(*internals_pp)->registered_exception_translators.push_front(
|
||||
[](std::exception_ptr p) -> void {
|
||||
try {
|
||||
if (p) std::rethrow_exception(p);
|
||||
} catch (error_already_set &e) { e.restore(); return;
|
||||
} catch (const builtin_exception &e) { e.set_error(); return;
|
||||
}
|
||||
}
|
||||
);
|
||||
#endif
|
||||
} else {
|
||||
if (!internals_pp) internals_pp = new internals*();
|
||||
auto *&internals_ptr = *internals_pp;
|
||||
internals_ptr = new internals();
|
||||
#if defined(WITH_THREAD)
|
||||
#if PY_VERSION_HEX < 0x03090000
|
||||
PyEval_InitThreads();
|
||||
#endif
|
||||
PyThreadState *tstate = PyThreadState_Get();
|
||||
#if PY_VERSION_HEX >= 0x03070000
|
||||
internals_ptr->tstate = PyThread_tss_alloc();
|
||||
if (!internals_ptr->tstate || PyThread_tss_create(internals_ptr->tstate))
|
||||
pybind11_fail("get_internals: could not successfully initialize the TSS key!");
|
||||
PyThread_tss_set(internals_ptr->tstate, tstate);
|
||||
#else
|
||||
internals_ptr->tstate = PyThread_create_key();
|
||||
if (internals_ptr->tstate == -1)
|
||||
pybind11_fail("get_internals: could not successfully initialize the TLS key!");
|
||||
PyThread_set_key_value(internals_ptr->tstate, tstate);
|
||||
#endif
|
||||
internals_ptr->istate = tstate->interp;
|
||||
#endif
|
||||
builtins[id] = capsule(internals_pp);
|
||||
internals_ptr->registered_exception_translators.push_front(
|
||||
[](std::exception_ptr p) -> void {
|
||||
try {
|
||||
if (p) std::rethrow_exception(p);
|
||||
} catch (error_already_set &e) { e.restore(); return;
|
||||
} catch (const builtin_exception &e) { e.set_error(); return;
|
||||
} catch (const std::bad_alloc &e) { PyErr_SetString(PyExc_MemoryError, e.what()); return;
|
||||
} catch (const std::domain_error &e) { PyErr_SetString(PyExc_ValueError, e.what()); return;
|
||||
} catch (const std::invalid_argument &e) { PyErr_SetString(PyExc_ValueError, e.what()); return;
|
||||
} catch (const std::length_error &e) { PyErr_SetString(PyExc_ValueError, e.what()); return;
|
||||
} catch (const std::out_of_range &e) { PyErr_SetString(PyExc_IndexError, e.what()); return;
|
||||
} catch (const std::range_error &e) { PyErr_SetString(PyExc_ValueError, e.what()); return;
|
||||
} catch (const std::exception &e) { PyErr_SetString(PyExc_RuntimeError, e.what()); return;
|
||||
} catch (...) {
|
||||
PyErr_SetString(PyExc_RuntimeError, "Caught an unknown exception!");
|
||||
return;
|
||||
}
|
||||
}
|
||||
);
|
||||
internals_ptr->static_property_type = make_static_property_type();
|
||||
internals_ptr->default_metaclass = make_default_metaclass();
|
||||
internals_ptr->instance_base = make_object_base_type(internals_ptr->default_metaclass);
|
||||
}
|
||||
auto **&internals_pp = get_internals_pp();
|
||||
if (internals_pp && *internals_pp)
|
||||
return **internals_pp;
|
||||
|
||||
constexpr auto *id = PYBIND11_INTERNALS_ID;
|
||||
auto builtins = handle(PyEval_GetBuiltins());
|
||||
if (builtins.contains(id) && isinstance<capsule>(builtins[id])) {
|
||||
internals_pp = static_cast<internals **>(capsule(builtins[id]));
|
||||
|
||||
// We loaded builtins through python's builtins, which means that our
|
||||
// `error_already_set` and `builtin_exception` may be different local
|
||||
// classes than the ones set up in the initial exception translator, below,
|
||||
// so add another for our local exception classes.
|
||||
//
|
||||
// libstdc++ doesn't require this (types there are identified only by name)
|
||||
#if !defined(__GLIBCXX__)
|
||||
(*internals_pp)
|
||||
->registered_exception_translators.push_front(
|
||||
[](std::exception_ptr p) -> void {
|
||||
try {
|
||||
if (p)
|
||||
std::rethrow_exception(p);
|
||||
} catch (error_already_set &e) {
|
||||
e.restore();
|
||||
return;
|
||||
} catch (const builtin_exception &e) {
|
||||
e.set_error();
|
||||
return;
|
||||
}
|
||||
});
|
||||
#endif
|
||||
} else {
|
||||
if (!internals_pp)
|
||||
internals_pp = new internals *();
|
||||
auto *&internals_ptr = *internals_pp;
|
||||
internals_ptr = new internals();
|
||||
#if defined(WITH_THREAD)
|
||||
#if PY_VERSION_HEX < 0x03090000
|
||||
PyEval_InitThreads();
|
||||
#endif
|
||||
PyThreadState *tstate = PyThreadState_Get();
|
||||
#if PY_VERSION_HEX >= 0x03070000
|
||||
internals_ptr->tstate = PyThread_tss_alloc();
|
||||
if (!internals_ptr->tstate || PyThread_tss_create(internals_ptr->tstate))
|
||||
pybind11_fail(
|
||||
"get_internals: could not successfully initialize the TSS key!");
|
||||
PyThread_tss_set(internals_ptr->tstate, tstate);
|
||||
#else
|
||||
internals_ptr->tstate = PyThread_create_key();
|
||||
if (internals_ptr->tstate == -1)
|
||||
pybind11_fail(
|
||||
"get_internals: could not successfully initialize the TLS key!");
|
||||
PyThread_set_key_value(internals_ptr->tstate, tstate);
|
||||
#endif
|
||||
internals_ptr->istate = tstate->interp;
|
||||
#endif
|
||||
builtins[id] = capsule(internals_pp);
|
||||
internals_ptr->registered_exception_translators.push_front(
|
||||
[](std::exception_ptr p) -> void {
|
||||
try {
|
||||
if (p)
|
||||
std::rethrow_exception(p);
|
||||
} catch (error_already_set &e) {
|
||||
e.restore();
|
||||
return;
|
||||
} catch (const builtin_exception &e) {
|
||||
e.set_error();
|
||||
return;
|
||||
} catch (const std::bad_alloc &e) {
|
||||
PyErr_SetString(PyExc_MemoryError, e.what());
|
||||
return;
|
||||
} catch (const std::domain_error &e) {
|
||||
PyErr_SetString(PyExc_ValueError, e.what());
|
||||
return;
|
||||
} catch (const std::invalid_argument &e) {
|
||||
PyErr_SetString(PyExc_ValueError, e.what());
|
||||
return;
|
||||
} catch (const std::length_error &e) {
|
||||
PyErr_SetString(PyExc_ValueError, e.what());
|
||||
return;
|
||||
} catch (const std::out_of_range &e) {
|
||||
PyErr_SetString(PyExc_IndexError, e.what());
|
||||
return;
|
||||
} catch (const std::range_error &e) {
|
||||
PyErr_SetString(PyExc_ValueError, e.what());
|
||||
return;
|
||||
} catch (const std::exception &e) {
|
||||
PyErr_SetString(PyExc_RuntimeError, e.what());
|
||||
return;
|
||||
} catch (...) {
|
||||
PyErr_SetString(PyExc_RuntimeError, "Caught an unknown exception!");
|
||||
return;
|
||||
}
|
||||
});
|
||||
internals_ptr->static_property_type = make_static_property_type();
|
||||
internals_ptr->default_metaclass = make_default_metaclass();
|
||||
internals_ptr->instance_base =
|
||||
make_object_base_type(internals_ptr->default_metaclass);
|
||||
}
|
||||
return **internals_pp;
|
||||
}
|
||||
|
||||
/// Works like `internals.registered_types_cpp`, but for module-local registered types:
|
||||
/// Works like `internals.registered_types_cpp`, but for module-local registered
|
||||
/// types:
|
||||
inline type_map<type_info *> ®istered_local_types_cpp() {
|
||||
static type_map<type_info *> locals{};
|
||||
return locals;
|
||||
static type_map<type_info *> locals{};
|
||||
return locals;
|
||||
}
|
||||
|
||||
/// Constructs a std::string with the given arguments, stores it in `internals`, and returns its
|
||||
/// `c_str()`. Such strings objects have a long storage duration -- the internal strings are only
|
||||
/// cleared when the program exits or after interpreter shutdown (when embedding), and so are
|
||||
/// suitable for c-style strings needed by Python internals (such as PyTypeObject's tp_name).
|
||||
template <typename... Args>
|
||||
const char *c_str(Args &&...args) {
|
||||
auto &strings = get_internals().static_strings;
|
||||
strings.emplace_front(std::forward<Args>(args)...);
|
||||
return strings.front().c_str();
|
||||
/// Constructs a std::string with the given arguments, stores it in `internals`,
|
||||
/// and returns its `c_str()`. Such strings objects have a long storage
|
||||
/// duration -- the internal strings are only cleared when the program exits or
|
||||
/// after interpreter shutdown (when embedding), and so are suitable for c-style
|
||||
/// strings needed by Python internals (such as PyTypeObject's tp_name).
|
||||
template <typename... Args> const char *c_str(Args &&... args) {
|
||||
auto &strings = get_internals().static_strings;
|
||||
strings.emplace_front(std::forward<Args>(args)...);
|
||||
return strings.front().c_str();
|
||||
}
|
||||
|
||||
NAMESPACE_END(detail)
|
||||
|
||||
/// Returns a named pointer that is shared among all extension modules (using the same
|
||||
/// pybind11 version) running in the current interpreter. Names starting with underscores
|
||||
/// are reserved for internal usage. Returns `nullptr` if no matching entry was found.
|
||||
/// Returns a named pointer that is shared among all extension modules (using
|
||||
/// the same pybind11 version) running in the current interpreter. Names
|
||||
/// starting with underscores are reserved for internal usage. Returns `nullptr`
|
||||
/// if no matching entry was found.
|
||||
inline PYBIND11_NOINLINE void *get_shared_data(const std::string &name) {
|
||||
auto &internals = detail::get_internals();
|
||||
auto it = internals.shared_data.find(name);
|
||||
return it != internals.shared_data.end() ? it->second : nullptr;
|
||||
auto &internals = detail::get_internals();
|
||||
auto it = internals.shared_data.find(name);
|
||||
return it != internals.shared_data.end() ? it->second : nullptr;
|
||||
}
|
||||
|
||||
/// Set the shared data that can be later recovered by `get_shared_data()`.
|
||||
inline PYBIND11_NOINLINE void *set_shared_data(const std::string &name, void *data) {
|
||||
detail::get_internals().shared_data[name] = data;
|
||||
return data;
|
||||
inline PYBIND11_NOINLINE void *set_shared_data(const std::string &name,
|
||||
void *data) {
|
||||
detail::get_internals().shared_data[name] = data;
|
||||
return data;
|
||||
}
|
||||
|
||||
/// Returns a typed reference to a shared data entry (by using `get_shared_data()`) if
|
||||
/// such entry exists. Otherwise, a new object of default-constructible type `T` is
|
||||
/// added to the shared data under the given name and a reference to it is returned.
|
||||
template<typename T>
|
||||
T &get_or_create_shared_data(const std::string &name) {
|
||||
auto &internals = detail::get_internals();
|
||||
auto it = internals.shared_data.find(name);
|
||||
T *ptr = (T *) (it != internals.shared_data.end() ? it->second : nullptr);
|
||||
if (!ptr) {
|
||||
ptr = new T();
|
||||
internals.shared_data[name] = ptr;
|
||||
}
|
||||
return *ptr;
|
||||
/// Returns a typed reference to a shared data entry (by using
|
||||
/// `get_shared_data()`) if such entry exists. Otherwise, a new object of
|
||||
/// default-constructible type `T` is added to the shared data under the given
|
||||
/// name and a reference to it is returned.
|
||||
template <typename T> T &get_or_create_shared_data(const std::string &name) {
|
||||
auto &internals = detail::get_internals();
|
||||
auto it = internals.shared_data.find(name);
|
||||
T *ptr = (T *)(it != internals.shared_data.end() ? it->second : nullptr);
|
||||
if (!ptr) {
|
||||
ptr = new T();
|
||||
internals.shared_data[name] = ptr;
|
||||
}
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
NAMESPACE_END(PYBIND11_NAMESPACE)
|
||||
|
@@ -22,34 +22,35 @@ NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
||||
NAMESPACE_BEGIN(detail)
|
||||
/// Erase all occurrences of a substring
|
||||
inline void erase_all(std::string &string, const std::string &search) {
|
||||
for (size_t pos = 0;;) {
|
||||
pos = string.find(search, pos);
|
||||
if (pos == std::string::npos) break;
|
||||
string.erase(pos, search.length());
|
||||
}
|
||||
for (size_t pos = 0;;) {
|
||||
pos = string.find(search, pos);
|
||||
if (pos == std::string::npos)
|
||||
break;
|
||||
string.erase(pos, search.length());
|
||||
}
|
||||
}
|
||||
|
||||
PYBIND11_NOINLINE inline void clean_type_id(std::string &name) {
|
||||
#if defined(__GNUG__)
|
||||
int status = 0;
|
||||
std::unique_ptr<char, void (*)(void *)> res {
|
||||
abi::__cxa_demangle(name.c_str(), nullptr, nullptr, &status), std::free };
|
||||
if (status == 0)
|
||||
name = res.get();
|
||||
int status = 0;
|
||||
std::unique_ptr<char, void (*)(void *)> res{
|
||||
abi::__cxa_demangle(name.c_str(), nullptr, nullptr, &status), std::free};
|
||||
if (status == 0)
|
||||
name = res.get();
|
||||
#else
|
||||
detail::erase_all(name, "class ");
|
||||
detail::erase_all(name, "struct ");
|
||||
detail::erase_all(name, "enum ");
|
||||
detail::erase_all(name, "class ");
|
||||
detail::erase_all(name, "struct ");
|
||||
detail::erase_all(name, "enum ");
|
||||
#endif
|
||||
detail::erase_all(name, "pybind11::");
|
||||
detail::erase_all(name, "pybind11::");
|
||||
}
|
||||
NAMESPACE_END(detail)
|
||||
|
||||
/// Return a string representation of a C++ type
|
||||
template <typename T> static std::string type_id() {
|
||||
std::string name(typeid(T).name());
|
||||
detail::clean_type_id(name);
|
||||
return name;
|
||||
std::string name(typeid(T).name());
|
||||
detail::clean_type_id(name);
|
||||
return name;
|
||||
}
|
||||
|
||||
NAMESPACE_END(PYBIND11_NAMESPACE)
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -9,23 +9,23 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "pybind11.h"
|
||||
#include "eval.h"
|
||||
#include "pybind11.h"
|
||||
|
||||
#if defined(PYPY_VERSION)
|
||||
# error Embedding the interpreter is not supported with PyPy
|
||||
#error Embedding the interpreter is not supported with PyPy
|
||||
#endif
|
||||
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
# define PYBIND11_EMBEDDED_MODULE_IMPL(name) \
|
||||
extern "C" PyObject *pybind11_init_impl_##name() { \
|
||||
return pybind11_init_wrapper_##name(); \
|
||||
}
|
||||
#define PYBIND11_EMBEDDED_MODULE_IMPL(name) \
|
||||
extern "C" PyObject *pybind11_init_impl_##name() { \
|
||||
return pybind11_init_wrapper_##name(); \
|
||||
}
|
||||
#else
|
||||
# define PYBIND11_EMBEDDED_MODULE_IMPL(name) \
|
||||
extern "C" void pybind11_init_impl_##name() { \
|
||||
pybind11_init_wrapper_##name(); \
|
||||
}
|
||||
#define PYBIND11_EMBEDDED_MODULE_IMPL(name) \
|
||||
extern "C" void pybind11_init_impl_##name() { \
|
||||
pybind11_init_wrapper_##name(); \
|
||||
}
|
||||
#endif
|
||||
|
||||
/** \rst
|
||||
@@ -43,75 +43,78 @@
|
||||
});
|
||||
}
|
||||
\endrst */
|
||||
#define PYBIND11_EMBEDDED_MODULE(name, variable) \
|
||||
static void PYBIND11_CONCAT(pybind11_init_, name)(pybind11::module &); \
|
||||
static PyObject PYBIND11_CONCAT(*pybind11_init_wrapper_, name)() { \
|
||||
auto m = pybind11::module(PYBIND11_TOSTRING(name)); \
|
||||
try { \
|
||||
PYBIND11_CONCAT(pybind11_init_, name)(m); \
|
||||
return m.ptr(); \
|
||||
} catch (pybind11::error_already_set &e) { \
|
||||
PyErr_SetString(PyExc_ImportError, e.what()); \
|
||||
return nullptr; \
|
||||
} catch (const std::exception &e) { \
|
||||
PyErr_SetString(PyExc_ImportError, e.what()); \
|
||||
return nullptr; \
|
||||
} \
|
||||
} \
|
||||
PYBIND11_EMBEDDED_MODULE_IMPL(name) \
|
||||
pybind11::detail::embedded_module name(PYBIND11_TOSTRING(name), \
|
||||
PYBIND11_CONCAT(pybind11_init_impl_, name)); \
|
||||
void PYBIND11_CONCAT(pybind11_init_, name)(pybind11::module &variable)
|
||||
|
||||
#define PYBIND11_EMBEDDED_MODULE(name, variable) \
|
||||
static void PYBIND11_CONCAT(pybind11_init_, name)(pybind11::module &); \
|
||||
static PyObject PYBIND11_CONCAT(*pybind11_init_wrapper_, name)() { \
|
||||
auto m = pybind11::module(PYBIND11_TOSTRING(name)); \
|
||||
try { \
|
||||
PYBIND11_CONCAT(pybind11_init_, name)(m); \
|
||||
return m.ptr(); \
|
||||
} catch (pybind11::error_already_set & e) { \
|
||||
PyErr_SetString(PyExc_ImportError, e.what()); \
|
||||
return nullptr; \
|
||||
} catch (const std::exception &e) { \
|
||||
PyErr_SetString(PyExc_ImportError, e.what()); \
|
||||
return nullptr; \
|
||||
} \
|
||||
} \
|
||||
PYBIND11_EMBEDDED_MODULE_IMPL(name) \
|
||||
pybind11::detail::embedded_module name( \
|
||||
PYBIND11_TOSTRING(name), PYBIND11_CONCAT(pybind11_init_impl_, name)); \
|
||||
void PYBIND11_CONCAT(pybind11_init_, name)(pybind11::module & variable)
|
||||
|
||||
NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
||||
NAMESPACE_BEGIN(detail)
|
||||
|
||||
/// Python 2.7/3.x compatible version of `PyImport_AppendInittab` and error checks.
|
||||
/// Python 2.7/3.x compatible version of `PyImport_AppendInittab` and error
|
||||
/// checks.
|
||||
struct embedded_module {
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
using init_t = PyObject *(*)();
|
||||
using init_t = PyObject *(*)();
|
||||
#else
|
||||
using init_t = void (*)();
|
||||
using init_t = void (*)();
|
||||
#endif
|
||||
embedded_module(const char *name, init_t init) {
|
||||
if (Py_IsInitialized())
|
||||
pybind11_fail("Can't add new modules after the interpreter has been initialized");
|
||||
embedded_module(const char *name, init_t init) {
|
||||
if (Py_IsInitialized())
|
||||
pybind11_fail(
|
||||
"Can't add new modules after the interpreter has been initialized");
|
||||
|
||||
auto result = PyImport_AppendInittab(name, init);
|
||||
if (result == -1)
|
||||
pybind11_fail("Insufficient memory to add a new module");
|
||||
}
|
||||
auto result = PyImport_AppendInittab(name, init);
|
||||
if (result == -1)
|
||||
pybind11_fail("Insufficient memory to add a new module");
|
||||
}
|
||||
};
|
||||
|
||||
NAMESPACE_END(detail)
|
||||
|
||||
/** \rst
|
||||
Initialize the Python interpreter. No other pybind11 or CPython API functions can be
|
||||
called before this is done; with the exception of `PYBIND11_EMBEDDED_MODULE`. The
|
||||
optional parameter can be used to skip the registration of signal handlers (see the
|
||||
`Python documentation`_ for details). Calling this function again after the interpreter
|
||||
has already been initialized is a fatal error.
|
||||
Initialize the Python interpreter. No other pybind11 or CPython API
|
||||
functions can be called before this is done; with the exception of
|
||||
`PYBIND11_EMBEDDED_MODULE`. The optional parameter can be used to skip the
|
||||
registration of signal handlers (see the `Python documentation`_ for details).
|
||||
Calling this function again after the interpreter has already been initialized
|
||||
is a fatal error.
|
||||
|
||||
If initializing the Python interpreter fails, then the program is terminated. (This
|
||||
is controlled by the CPython runtime and is an exception to pybind11's normal behavior
|
||||
of throwing exceptions on errors.)
|
||||
If initializing the Python interpreter fails, then the program is
|
||||
terminated. (This is controlled by the CPython runtime and is an exception to
|
||||
pybind11's normal behavior of throwing exceptions on errors.)
|
||||
|
||||
.. _Python documentation: https://docs.python.org/3/c-api/init.html#c.Py_InitializeEx
|
||||
\endrst */
|
||||
.. _Python documentation:
|
||||
https://docs.python.org/3/c-api/init.html#c.Py_InitializeEx \endrst */
|
||||
inline void initialize_interpreter(bool init_signal_handlers = true) {
|
||||
if (Py_IsInitialized())
|
||||
pybind11_fail("The interpreter is already running");
|
||||
if (Py_IsInitialized())
|
||||
pybind11_fail("The interpreter is already running");
|
||||
|
||||
Py_InitializeEx(init_signal_handlers ? 1 : 0);
|
||||
Py_InitializeEx(init_signal_handlers ? 1 : 0);
|
||||
|
||||
// Make .py files in the working directory available by default
|
||||
module::import("sys").attr("path").cast<list>().append(".");
|
||||
// Make .py files in the working directory available by default
|
||||
module::import("sys").attr("path").cast<list>().append(".");
|
||||
}
|
||||
|
||||
/** \rst
|
||||
Shut down the Python interpreter. No pybind11 or CPython API functions can be called
|
||||
after this. In addition, pybind11 objects must not outlive the interpreter:
|
||||
Shut down the Python interpreter. No pybind11 or CPython API functions can
|
||||
be called after this. In addition, pybind11 objects must not outlive the
|
||||
interpreter:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
@@ -136,32 +139,33 @@ inline void initialize_interpreter(bool init_signal_handlers = true) {
|
||||
|
||||
.. warning::
|
||||
|
||||
The interpreter can be restarted by calling `initialize_interpreter` again.
|
||||
Modules created using pybind11 can be safely re-initialized. However, Python
|
||||
itself cannot completely unload binary extension modules and there are several
|
||||
caveats with regard to interpreter restarting. All the details can be found
|
||||
in the CPython documentation. In short, not all interpreter memory may be
|
||||
The interpreter can be restarted by calling `initialize_interpreter`
|
||||
again. Modules created using pybind11 can be safely re-initialized. However,
|
||||
Python itself cannot completely unload binary extension modules and there are
|
||||
several caveats with regard to interpreter restarting. All the details can be
|
||||
found in the CPython documentation. In short, not all interpreter memory may be
|
||||
freed, either due to reference cycles or user-created global data.
|
||||
|
||||
\endrst */
|
||||
inline void finalize_interpreter() {
|
||||
handle builtins(PyEval_GetBuiltins());
|
||||
const char *id = PYBIND11_INTERNALS_ID;
|
||||
handle builtins(PyEval_GetBuiltins());
|
||||
const char *id = PYBIND11_INTERNALS_ID;
|
||||
|
||||
// Get the internals pointer (without creating it if it doesn't exist). It's possible for the
|
||||
// internals to be created during Py_Finalize() (e.g. if a py::capsule calls `get_internals()`
|
||||
// during destruction), so we get the pointer-pointer here and check it after Py_Finalize().
|
||||
detail::internals **internals_ptr_ptr = detail::get_internals_pp();
|
||||
// It could also be stashed in builtins, so look there too:
|
||||
if (builtins.contains(id) && isinstance<capsule>(builtins[id]))
|
||||
internals_ptr_ptr = capsule(builtins[id]);
|
||||
// Get the internals pointer (without creating it if it doesn't exist). It's
|
||||
// possible for the internals to be created during Py_Finalize() (e.g. if a
|
||||
// py::capsule calls `get_internals()` during destruction), so we get the
|
||||
// pointer-pointer here and check it after Py_Finalize().
|
||||
detail::internals **internals_ptr_ptr = detail::get_internals_pp();
|
||||
// It could also be stashed in builtins, so look there too:
|
||||
if (builtins.contains(id) && isinstance<capsule>(builtins[id]))
|
||||
internals_ptr_ptr = capsule(builtins[id]);
|
||||
|
||||
Py_Finalize();
|
||||
Py_Finalize();
|
||||
|
||||
if (internals_ptr_ptr) {
|
||||
delete *internals_ptr_ptr;
|
||||
*internals_ptr_ptr = nullptr;
|
||||
}
|
||||
if (internals_ptr_ptr) {
|
||||
delete *internals_ptr_ptr;
|
||||
*internals_ptr_ptr = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
/** \rst
|
||||
@@ -179,22 +183,24 @@ inline void finalize_interpreter() {
|
||||
\endrst */
|
||||
class scoped_interpreter {
|
||||
public:
|
||||
scoped_interpreter(bool init_signal_handlers = true) {
|
||||
initialize_interpreter(init_signal_handlers);
|
||||
}
|
||||
scoped_interpreter(bool init_signal_handlers = true) {
|
||||
initialize_interpreter(init_signal_handlers);
|
||||
}
|
||||
|
||||
scoped_interpreter(const scoped_interpreter &) = delete;
|
||||
scoped_interpreter(scoped_interpreter &&other) noexcept { other.is_valid = false; }
|
||||
scoped_interpreter &operator=(const scoped_interpreter &) = delete;
|
||||
scoped_interpreter &operator=(scoped_interpreter &&) = delete;
|
||||
scoped_interpreter(const scoped_interpreter &) = delete;
|
||||
scoped_interpreter(scoped_interpreter &&other) noexcept {
|
||||
other.is_valid = false;
|
||||
}
|
||||
scoped_interpreter &operator=(const scoped_interpreter &) = delete;
|
||||
scoped_interpreter &operator=(scoped_interpreter &&) = delete;
|
||||
|
||||
~scoped_interpreter() {
|
||||
if (is_valid)
|
||||
finalize_interpreter();
|
||||
}
|
||||
~scoped_interpreter() {
|
||||
if (is_valid)
|
||||
finalize_interpreter();
|
||||
}
|
||||
|
||||
private:
|
||||
bool is_valid = true;
|
||||
bool is_valid = true;
|
||||
};
|
||||
|
||||
NAMESPACE_END(PYBIND11_NAMESPACE)
|
||||
|
@@ -2,8 +2,8 @@
|
||||
pybind11/exec.h: Support for evaluating Python expressions and statements
|
||||
from strings and files
|
||||
|
||||
Copyright (c) 2016 Klemens Morgenstern <klemens.morgenstern@ed-chemnitz.de> and
|
||||
Wenzel Jakob <wenzel.jakob@epfl.ch>
|
||||
Copyright (c) 2016 Klemens Morgenstern <klemens.morgenstern@ed-chemnitz.de>
|
||||
and Wenzel Jakob <wenzel.jakob@epfl.ch>
|
||||
|
||||
All rights reserved. Use of this source code is governed by a
|
||||
BSD-style license that can be found in the LICENSE file.
|
||||
@@ -16,102 +16,119 @@
|
||||
NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
||||
|
||||
enum eval_mode {
|
||||
/// Evaluate a string containing an isolated expression
|
||||
eval_expr,
|
||||
/// Evaluate a string containing an isolated expression
|
||||
eval_expr,
|
||||
|
||||
/// Evaluate a string containing a single statement. Returns \c none
|
||||
eval_single_statement,
|
||||
/// Evaluate a string containing a single statement. Returns \c none
|
||||
eval_single_statement,
|
||||
|
||||
/// Evaluate a string containing a sequence of statement. Returns \c none
|
||||
eval_statements
|
||||
/// Evaluate a string containing a sequence of statement. Returns \c none
|
||||
eval_statements
|
||||
};
|
||||
|
||||
template <eval_mode mode = eval_expr>
|
||||
object eval(str expr, object global = globals(), object local = object()) {
|
||||
if (!local)
|
||||
local = global;
|
||||
if (!local)
|
||||
local = global;
|
||||
|
||||
/* PyRun_String does not accept a PyObject / encoding specifier,
|
||||
this seems to be the only alternative */
|
||||
std::string buffer = "# -*- coding: utf-8 -*-\n" + (std::string) expr;
|
||||
/* PyRun_String does not accept a PyObject / encoding specifier,
|
||||
this seems to be the only alternative */
|
||||
std::string buffer = "# -*- coding: utf-8 -*-\n" + (std::string)expr;
|
||||
|
||||
int start;
|
||||
switch (mode) {
|
||||
case eval_expr: start = Py_eval_input; break;
|
||||
case eval_single_statement: start = Py_single_input; break;
|
||||
case eval_statements: start = Py_file_input; break;
|
||||
default: pybind11_fail("invalid evaluation mode");
|
||||
}
|
||||
int start;
|
||||
switch (mode) {
|
||||
case eval_expr:
|
||||
start = Py_eval_input;
|
||||
break;
|
||||
case eval_single_statement:
|
||||
start = Py_single_input;
|
||||
break;
|
||||
case eval_statements:
|
||||
start = Py_file_input;
|
||||
break;
|
||||
default:
|
||||
pybind11_fail("invalid evaluation mode");
|
||||
}
|
||||
|
||||
PyObject *result = PyRun_String(buffer.c_str(), start, global.ptr(), local.ptr());
|
||||
if (!result)
|
||||
throw error_already_set();
|
||||
return reinterpret_steal<object>(result);
|
||||
PyObject *result =
|
||||
PyRun_String(buffer.c_str(), start, global.ptr(), local.ptr());
|
||||
if (!result)
|
||||
throw error_already_set();
|
||||
return reinterpret_steal<object>(result);
|
||||
}
|
||||
|
||||
template <eval_mode mode = eval_expr, size_t N>
|
||||
object eval(const char (&s)[N], object global = globals(), object local = object()) {
|
||||
/* Support raw string literals by removing common leading whitespace */
|
||||
auto expr = (s[0] == '\n') ? str(module::import("textwrap").attr("dedent")(s))
|
||||
: str(s);
|
||||
return eval<mode>(expr, global, local);
|
||||
object eval(const char (&s)[N], object global = globals(),
|
||||
object local = object()) {
|
||||
/* Support raw string literals by removing common leading whitespace */
|
||||
auto expr = (s[0] == '\n') ? str(module::import("textwrap").attr("dedent")(s))
|
||||
: str(s);
|
||||
return eval<mode>(expr, global, local);
|
||||
}
|
||||
|
||||
inline void exec(str expr, object global = globals(), object local = object()) {
|
||||
eval<eval_statements>(expr, global, local);
|
||||
eval<eval_statements>(expr, global, local);
|
||||
}
|
||||
|
||||
template <size_t N>
|
||||
void exec(const char (&s)[N], object global = globals(), object local = object()) {
|
||||
eval<eval_statements>(s, global, local);
|
||||
void exec(const char (&s)[N], object global = globals(),
|
||||
object local = object()) {
|
||||
eval<eval_statements>(s, global, local);
|
||||
}
|
||||
|
||||
template <eval_mode mode = eval_statements>
|
||||
object eval_file(str fname, object global = globals(), object local = object()) {
|
||||
if (!local)
|
||||
local = global;
|
||||
object eval_file(str fname, object global = globals(),
|
||||
object local = object()) {
|
||||
if (!local)
|
||||
local = global;
|
||||
|
||||
int start;
|
||||
switch (mode) {
|
||||
case eval_expr: start = Py_eval_input; break;
|
||||
case eval_single_statement: start = Py_single_input; break;
|
||||
case eval_statements: start = Py_file_input; break;
|
||||
default: pybind11_fail("invalid evaluation mode");
|
||||
}
|
||||
int start;
|
||||
switch (mode) {
|
||||
case eval_expr:
|
||||
start = Py_eval_input;
|
||||
break;
|
||||
case eval_single_statement:
|
||||
start = Py_single_input;
|
||||
break;
|
||||
case eval_statements:
|
||||
start = Py_file_input;
|
||||
break;
|
||||
default:
|
||||
pybind11_fail("invalid evaluation mode");
|
||||
}
|
||||
|
||||
int closeFile = 1;
|
||||
std::string fname_str = (std::string) fname;
|
||||
int closeFile = 1;
|
||||
std::string fname_str = (std::string)fname;
|
||||
#if PY_VERSION_HEX >= 0x03040000
|
||||
FILE *f = _Py_fopen_obj(fname.ptr(), "r");
|
||||
FILE *f = _Py_fopen_obj(fname.ptr(), "r");
|
||||
#elif PY_VERSION_HEX >= 0x03000000
|
||||
FILE *f = _Py_fopen(fname.ptr(), "r");
|
||||
FILE *f = _Py_fopen(fname.ptr(), "r");
|
||||
#else
|
||||
/* No unicode support in open() :( */
|
||||
auto fobj = reinterpret_steal<object>(PyFile_FromString(
|
||||
const_cast<char *>(fname_str.c_str()),
|
||||
const_cast<char*>("r")));
|
||||
FILE *f = nullptr;
|
||||
if (fobj)
|
||||
f = PyFile_AsFile(fobj.ptr());
|
||||
closeFile = 0;
|
||||
/* No unicode support in open() :( */
|
||||
auto fobj = reinterpret_steal<object>(PyFile_FromString(
|
||||
const_cast<char *>(fname_str.c_str()), const_cast<char *>("r")));
|
||||
FILE *f = nullptr;
|
||||
if (fobj)
|
||||
f = PyFile_AsFile(fobj.ptr());
|
||||
closeFile = 0;
|
||||
#endif
|
||||
if (!f) {
|
||||
PyErr_Clear();
|
||||
pybind11_fail("File \"" + fname_str + "\" could not be opened!");
|
||||
}
|
||||
if (!f) {
|
||||
PyErr_Clear();
|
||||
pybind11_fail("File \"" + fname_str + "\" could not be opened!");
|
||||
}
|
||||
|
||||
#if PY_VERSION_HEX < 0x03000000 && defined(PYPY_VERSION)
|
||||
PyObject *result = PyRun_File(f, fname_str.c_str(), start, global.ptr(),
|
||||
local.ptr());
|
||||
(void) closeFile;
|
||||
PyObject *result =
|
||||
PyRun_File(f, fname_str.c_str(), start, global.ptr(), local.ptr());
|
||||
(void)closeFile;
|
||||
#else
|
||||
PyObject *result = PyRun_FileEx(f, fname_str.c_str(), start, global.ptr(),
|
||||
local.ptr(), closeFile);
|
||||
PyObject *result = PyRun_FileEx(f, fname_str.c_str(), start, global.ptr(),
|
||||
local.ptr(), closeFile);
|
||||
#endif
|
||||
|
||||
if (!result)
|
||||
throw error_already_set();
|
||||
return reinterpret_steal<object>(result);
|
||||
if (!result)
|
||||
throw error_already_set();
|
||||
return reinterpret_steal<object>(result);
|
||||
}
|
||||
|
||||
NAMESPACE_END(PYBIND11_NAMESPACE)
|
||||
|
@@ -17,91 +17,99 @@ NAMESPACE_BEGIN(detail)
|
||||
|
||||
template <typename Return, typename... Args>
|
||||
struct type_caster<std::function<Return(Args...)>> {
|
||||
using type = std::function<Return(Args...)>;
|
||||
using retval_type = conditional_t<std::is_same<Return, void>::value, void_type, Return>;
|
||||
using function_type = Return (*) (Args...);
|
||||
using type = std::function<Return(Args...)>;
|
||||
using retval_type =
|
||||
conditional_t<std::is_same<Return, void>::value, void_type, Return>;
|
||||
using function_type = Return (*)(Args...);
|
||||
|
||||
public:
|
||||
bool load(handle src, bool convert) {
|
||||
if (src.is_none()) {
|
||||
// Defer accepting None to other overloads (if we aren't in convert mode):
|
||||
if (!convert) return false;
|
||||
return true;
|
||||
}
|
||||
bool load(handle src, bool convert) {
|
||||
if (src.is_none()) {
|
||||
// Defer accepting None to other overloads (if we aren't in convert mode):
|
||||
if (!convert)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!isinstance<function>(src))
|
||||
return false;
|
||||
if (!isinstance<function>(src))
|
||||
return false;
|
||||
|
||||
auto func = reinterpret_borrow<function>(src);
|
||||
auto func = reinterpret_borrow<function>(src);
|
||||
|
||||
/*
|
||||
When passing a C++ function as an argument to another C++
|
||||
function via Python, every function call would normally involve
|
||||
a full C++ -> Python -> C++ roundtrip, which can be prohibitive.
|
||||
Here, we try to at least detect the case where the function is
|
||||
stateless (i.e. function pointer or lambda function without
|
||||
captured variables), in which case the roundtrip can be avoided.
|
||||
*/
|
||||
if (auto cfunc = func.cpp_function()) {
|
||||
auto c = reinterpret_borrow<capsule>(PyCFunction_GET_SELF(cfunc.ptr()));
|
||||
auto rec = (function_record *) c;
|
||||
/*
|
||||
When passing a C++ function as an argument to another C++
|
||||
function via Python, every function call would normally involve
|
||||
a full C++ -> Python -> C++ roundtrip, which can be prohibitive.
|
||||
Here, we try to at least detect the case where the function is
|
||||
stateless (i.e. function pointer or lambda function without
|
||||
captured variables), in which case the roundtrip can be avoided.
|
||||
*/
|
||||
if (auto cfunc = func.cpp_function()) {
|
||||
auto c = reinterpret_borrow<capsule>(PyCFunction_GET_SELF(cfunc.ptr()));
|
||||
auto rec = (function_record *)c;
|
||||
|
||||
if (rec && rec->is_stateless &&
|
||||
same_type(typeid(function_type), *reinterpret_cast<const std::type_info *>(rec->data[1]))) {
|
||||
struct capture { function_type f; };
|
||||
value = ((capture *) &rec->data)->f;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// ensure GIL is held during functor destruction
|
||||
struct func_handle {
|
||||
function f;
|
||||
func_handle(function&& f_) : f(std::move(f_)) {}
|
||||
func_handle(const func_handle&) = default;
|
||||
~func_handle() {
|
||||
gil_scoped_acquire acq;
|
||||
function kill_f(std::move(f));
|
||||
}
|
||||
if (rec && rec->is_stateless &&
|
||||
same_type(typeid(function_type),
|
||||
*reinterpret_cast<const std::type_info *>(rec->data[1]))) {
|
||||
struct capture {
|
||||
function_type f;
|
||||
};
|
||||
|
||||
// value = [hfunc = func_handle(std::move(func))](Args... args) -> Return {
|
||||
// gil_scoped_acquire acq;
|
||||
// object retval(hfunc.f(std::forward<Args>(args)...));
|
||||
// /* Visual studio 2015 parser issue: need parentheses around this expression */
|
||||
// return (retval.template cast<Return>());
|
||||
// };
|
||||
|
||||
struct func_wrapper {
|
||||
func_handle hfunc;
|
||||
func_wrapper(func_handle&& hf): hfunc(std::move(hf)) {}
|
||||
Return operator()(Args... args) const {
|
||||
gil_scoped_acquire acq;
|
||||
object retval(hfunc.f(std::forward<Args>(args)...));
|
||||
/* Visual studio 2015 parser issue: need parentheses around this expression */
|
||||
return (retval.template cast<Return>());
|
||||
}
|
||||
};
|
||||
|
||||
value = func_wrapper(func_handle(std::move(func)));
|
||||
|
||||
value = ((capture *)&rec->data)->f;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Func>
|
||||
static handle cast(Func &&f_, return_value_policy policy, handle /* parent */) {
|
||||
if (!f_)
|
||||
return none().inc_ref();
|
||||
// ensure GIL is held during functor destruction
|
||||
struct func_handle {
|
||||
function f;
|
||||
func_handle(function &&f_) : f(std::move(f_)) {}
|
||||
func_handle(const func_handle &) = default;
|
||||
~func_handle() {
|
||||
gil_scoped_acquire acq;
|
||||
function kill_f(std::move(f));
|
||||
}
|
||||
};
|
||||
|
||||
auto result = f_.template target<function_type>();
|
||||
if (result)
|
||||
return cpp_function(*result, policy).release();
|
||||
else
|
||||
return cpp_function(std::forward<Func>(f_), policy).release();
|
||||
}
|
||||
// value = [hfunc = func_handle(std::move(func))](Args... args) -> Return {
|
||||
// gil_scoped_acquire acq;
|
||||
// object retval(hfunc.f(std::forward<Args>(args)...));
|
||||
// /* Visual studio 2015 parser issue: need parentheses around this
|
||||
// expression */ return (retval.template cast<Return>());
|
||||
// };
|
||||
|
||||
PYBIND11_TYPE_CASTER(type, _("Callable[[") + concat(make_caster<Args>::name...) + _("], ")
|
||||
+ make_caster<retval_type>::name + _("]"));
|
||||
struct func_wrapper {
|
||||
func_handle hfunc;
|
||||
func_wrapper(func_handle &&hf) : hfunc(std::move(hf)) {}
|
||||
Return operator()(Args... args) const {
|
||||
gil_scoped_acquire acq;
|
||||
object retval(hfunc.f(std::forward<Args>(args)...));
|
||||
/* Visual studio 2015 parser issue: need parentheses around this
|
||||
* expression */
|
||||
return (retval.template cast<Return>());
|
||||
}
|
||||
};
|
||||
|
||||
value = func_wrapper(func_handle(std::move(func)));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Func>
|
||||
static handle cast(Func &&f_, return_value_policy policy,
|
||||
handle /* parent */) {
|
||||
if (!f_)
|
||||
return none().inc_ref();
|
||||
|
||||
auto result = f_.template target<function_type>();
|
||||
if (result)
|
||||
return cpp_function(*result, policy).release();
|
||||
else
|
||||
return cpp_function(std::forward<Func>(f_), policy).release();
|
||||
}
|
||||
|
||||
PYBIND11_TYPE_CASTER(type, _("Callable[[") +
|
||||
concat(make_caster<Args>::name...) + _("], ") +
|
||||
make_caster<retval_type>::name + _("]"));
|
||||
};
|
||||
|
||||
NAMESPACE_END(detail)
|
||||
|
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
pybind11/iostream.h -- Tools to assist with redirecting cout and cerr to Python
|
||||
pybind11/iostream.h -- Tools to assist with redirecting cout and cerr to
|
||||
Python
|
||||
|
||||
Copyright (c) 2017 Henry F. Schreiner
|
||||
|
||||
@@ -11,11 +12,11 @@
|
||||
|
||||
#include "pybind11.h"
|
||||
|
||||
#include <streambuf>
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <ostream>
|
||||
#include <streambuf>
|
||||
#include <string>
|
||||
|
||||
NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
||||
NAMESPACE_BEGIN(detail)
|
||||
@@ -23,56 +24,50 @@ NAMESPACE_BEGIN(detail)
|
||||
// Buffer that writes to Python instead of C++
|
||||
class pythonbuf : public std::streambuf {
|
||||
private:
|
||||
using traits_type = std::streambuf::traits_type;
|
||||
using traits_type = std::streambuf::traits_type;
|
||||
|
||||
const size_t buf_size;
|
||||
std::unique_ptr<char[]> d_buffer;
|
||||
object pywrite;
|
||||
object pyflush;
|
||||
const size_t buf_size;
|
||||
std::unique_ptr<char[]> d_buffer;
|
||||
object pywrite;
|
||||
object pyflush;
|
||||
|
||||
int overflow(int c) {
|
||||
if (!traits_type::eq_int_type(c, traits_type::eof())) {
|
||||
*pptr() = traits_type::to_char_type(c);
|
||||
pbump(1);
|
||||
}
|
||||
return sync() == 0 ? traits_type::not_eof(c) : traits_type::eof();
|
||||
int overflow(int c) {
|
||||
if (!traits_type::eq_int_type(c, traits_type::eof())) {
|
||||
*pptr() = traits_type::to_char_type(c);
|
||||
pbump(1);
|
||||
}
|
||||
return sync() == 0 ? traits_type::not_eof(c) : traits_type::eof();
|
||||
}
|
||||
|
||||
int sync() {
|
||||
if (pbase() != pptr()) {
|
||||
// This subtraction cannot be negative, so dropping the sign
|
||||
str line(pbase(), static_cast<size_t>(pptr() - pbase()));
|
||||
int sync() {
|
||||
if (pbase() != pptr()) {
|
||||
// This subtraction cannot be negative, so dropping the sign
|
||||
str line(pbase(), static_cast<size_t>(pptr() - pbase()));
|
||||
|
||||
{
|
||||
gil_scoped_acquire tmp;
|
||||
pywrite(line);
|
||||
pyflush();
|
||||
}
|
||||
{
|
||||
gil_scoped_acquire tmp;
|
||||
pywrite(line);
|
||||
pyflush();
|
||||
}
|
||||
|
||||
setp(pbase(), epptr());
|
||||
}
|
||||
return 0;
|
||||
setp(pbase(), epptr());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public:
|
||||
pythonbuf(object pyostream, size_t buffer_size = 1024)
|
||||
: buf_size(buffer_size), d_buffer(new char[buf_size]),
|
||||
pywrite(pyostream.attr("write")), pyflush(pyostream.attr("flush")) {
|
||||
setp(d_buffer.get(), d_buffer.get() + buf_size - 1);
|
||||
}
|
||||
|
||||
pythonbuf(object pyostream, size_t buffer_size = 1024)
|
||||
: buf_size(buffer_size),
|
||||
d_buffer(new char[buf_size]),
|
||||
pywrite(pyostream.attr("write")),
|
||||
pyflush(pyostream.attr("flush")) {
|
||||
setp(d_buffer.get(), d_buffer.get() + buf_size - 1);
|
||||
}
|
||||
|
||||
/// Sync before destroy
|
||||
~pythonbuf() {
|
||||
sync();
|
||||
}
|
||||
/// Sync before destroy
|
||||
~pythonbuf() { sync(); }
|
||||
};
|
||||
|
||||
NAMESPACE_END(detail)
|
||||
|
||||
|
||||
/** \rst
|
||||
This a move-only guard that redirects output.
|
||||
|
||||
@@ -93,35 +88,32 @@ NAMESPACE_END(detail)
|
||||
.. code-block:: cpp
|
||||
|
||||
{
|
||||
py::scoped_ostream_redirect output{std::cerr, py::module::import("sys").attr("stderr")};
|
||||
std::cerr << "Hello, World!";
|
||||
py::scoped_ostream_redirect output{std::cerr,
|
||||
py::module::import("sys").attr("stderr")}; std::cerr << "Hello, World!";
|
||||
}
|
||||
\endrst */
|
||||
class scoped_ostream_redirect {
|
||||
protected:
|
||||
std::streambuf *old;
|
||||
std::ostream &costream;
|
||||
detail::pythonbuf buffer;
|
||||
std::streambuf *old;
|
||||
std::ostream &costream;
|
||||
detail::pythonbuf buffer;
|
||||
|
||||
public:
|
||||
scoped_ostream_redirect(
|
||||
std::ostream &costream = std::cout,
|
||||
object pyostream = module::import("sys").attr("stdout"))
|
||||
: costream(costream), buffer(pyostream) {
|
||||
old = costream.rdbuf(&buffer);
|
||||
}
|
||||
scoped_ostream_redirect(
|
||||
std::ostream &costream = std::cout,
|
||||
object pyostream = module::import("sys").attr("stdout"))
|
||||
: costream(costream), buffer(pyostream) {
|
||||
old = costream.rdbuf(&buffer);
|
||||
}
|
||||
|
||||
~scoped_ostream_redirect() {
|
||||
costream.rdbuf(old);
|
||||
}
|
||||
~scoped_ostream_redirect() { costream.rdbuf(old); }
|
||||
|
||||
scoped_ostream_redirect(const scoped_ostream_redirect &) = delete;
|
||||
scoped_ostream_redirect(scoped_ostream_redirect &&other) = default;
|
||||
scoped_ostream_redirect &operator=(const scoped_ostream_redirect &) = delete;
|
||||
scoped_ostream_redirect &operator=(scoped_ostream_redirect &&) = delete;
|
||||
scoped_ostream_redirect(const scoped_ostream_redirect &) = delete;
|
||||
scoped_ostream_redirect(scoped_ostream_redirect &&other) = default;
|
||||
scoped_ostream_redirect &operator=(const scoped_ostream_redirect &) = delete;
|
||||
scoped_ostream_redirect &operator=(scoped_ostream_redirect &&) = delete;
|
||||
};
|
||||
|
||||
|
||||
/** \rst
|
||||
Like `scoped_ostream_redirect`, but redirects cerr by default. This class
|
||||
is provided primary to make ``py::call_guard`` easier to make.
|
||||
@@ -135,44 +127,44 @@ public:
|
||||
\endrst */
|
||||
class scoped_estream_redirect : public scoped_ostream_redirect {
|
||||
public:
|
||||
scoped_estream_redirect(
|
||||
std::ostream &costream = std::cerr,
|
||||
object pyostream = module::import("sys").attr("stderr"))
|
||||
: scoped_ostream_redirect(costream,pyostream) {}
|
||||
scoped_estream_redirect(
|
||||
std::ostream &costream = std::cerr,
|
||||
object pyostream = module::import("sys").attr("stderr"))
|
||||
: scoped_ostream_redirect(costream, pyostream) {}
|
||||
};
|
||||
|
||||
|
||||
NAMESPACE_BEGIN(detail)
|
||||
|
||||
// Class to redirect output as a context manager. C++ backend.
|
||||
class OstreamRedirect {
|
||||
bool do_stdout_;
|
||||
bool do_stderr_;
|
||||
std::unique_ptr<scoped_ostream_redirect> redirect_stdout;
|
||||
std::unique_ptr<scoped_estream_redirect> redirect_stderr;
|
||||
bool do_stdout_;
|
||||
bool do_stderr_;
|
||||
std::unique_ptr<scoped_ostream_redirect> redirect_stdout;
|
||||
std::unique_ptr<scoped_estream_redirect> redirect_stderr;
|
||||
|
||||
public:
|
||||
OstreamRedirect(bool do_stdout = true, bool do_stderr = true)
|
||||
: do_stdout_(do_stdout), do_stderr_(do_stderr) {}
|
||||
OstreamRedirect(bool do_stdout = true, bool do_stderr = true)
|
||||
: do_stdout_(do_stdout), do_stderr_(do_stderr) {}
|
||||
|
||||
void enter() {
|
||||
if (do_stdout_)
|
||||
redirect_stdout.reset(new scoped_ostream_redirect());
|
||||
if (do_stderr_)
|
||||
redirect_stderr.reset(new scoped_estream_redirect());
|
||||
}
|
||||
void enter() {
|
||||
if (do_stdout_)
|
||||
redirect_stdout.reset(new scoped_ostream_redirect());
|
||||
if (do_stderr_)
|
||||
redirect_stderr.reset(new scoped_estream_redirect());
|
||||
}
|
||||
|
||||
void exit() {
|
||||
redirect_stdout.reset();
|
||||
redirect_stderr.reset();
|
||||
}
|
||||
void exit() {
|
||||
redirect_stdout.reset();
|
||||
redirect_stderr.reset();
|
||||
}
|
||||
};
|
||||
|
||||
NAMESPACE_END(detail)
|
||||
|
||||
/** \rst
|
||||
This is a helper function to add a C++ redirect context manager to Python
|
||||
instead of using a C++ guard. To use it, add the following to your binding code:
|
||||
instead of using a C++ guard. To use it, add the following to your binding
|
||||
code:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
@@ -197,11 +189,13 @@ NAMESPACE_END(detail)
|
||||
m.noisy_function_with_error_printing()
|
||||
|
||||
\endrst */
|
||||
inline class_<detail::OstreamRedirect> add_ostream_redirect(module m, std::string name = "ostream_redirect") {
|
||||
return class_<detail::OstreamRedirect>(m, name.c_str(), module_local())
|
||||
.def(init<bool,bool>(), arg("stdout")=true, arg("stderr")=true)
|
||||
.def("__enter__", &detail::OstreamRedirect::enter)
|
||||
.def("__exit__", [](detail::OstreamRedirect &self_, args) { self_.exit(); });
|
||||
inline class_<detail::OstreamRedirect>
|
||||
add_ostream_redirect(module m, std::string name = "ostream_redirect") {
|
||||
return class_<detail::OstreamRedirect>(m, name.c_str(), module_local())
|
||||
.def(init<bool, bool>(), arg("stdout") = true, arg("stderr") = true)
|
||||
.def("__enter__", &detail::OstreamRedirect::enter)
|
||||
.def("__exit__",
|
||||
[](detail::OstreamRedirect &self_, args) { self_.exit(); });
|
||||
}
|
||||
|
||||
NAMESPACE_END(PYBIND11_NAMESPACE)
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -12,10 +12,13 @@
|
||||
#include "pybind11.h"
|
||||
|
||||
#if defined(__clang__) && !defined(__INTEL_COMPILER)
|
||||
# pragma clang diagnostic ignored "-Wunsequenced" // multiple unsequenced modifications to 'self' (when using def(py::self OP Type()))
|
||||
#pragma clang diagnostic ignored \
|
||||
"-Wunsequenced" // multiple unsequenced modifications to 'self' (when using
|
||||
// def(py::self OP Type()))
|
||||
#elif defined(_MSC_VER)
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable: 4127) // warning C4127: Conditional expression is constant
|
||||
#pragma warning(push)
|
||||
#pragma warning( \
|
||||
disable : 4127) // warning C4127: Conditional expression is constant
|
||||
#endif
|
||||
|
||||
NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
||||
@@ -23,136 +26,191 @@ NAMESPACE_BEGIN(detail)
|
||||
|
||||
/// Enumeration with all supported operator types
|
||||
enum op_id : int {
|
||||
op_add, op_sub, op_mul, op_div, op_mod, op_divmod, op_pow, op_lshift,
|
||||
op_rshift, op_and, op_xor, op_or, op_neg, op_pos, op_abs, op_invert,
|
||||
op_int, op_long, op_float, op_str, op_cmp, op_gt, op_ge, op_lt, op_le,
|
||||
op_eq, op_ne, op_iadd, op_isub, op_imul, op_idiv, op_imod, op_ilshift,
|
||||
op_irshift, op_iand, op_ixor, op_ior, op_complex, op_bool, op_nonzero,
|
||||
op_repr, op_truediv, op_itruediv, op_hash
|
||||
op_add,
|
||||
op_sub,
|
||||
op_mul,
|
||||
op_div,
|
||||
op_mod,
|
||||
op_divmod,
|
||||
op_pow,
|
||||
op_lshift,
|
||||
op_rshift,
|
||||
op_and,
|
||||
op_xor,
|
||||
op_or,
|
||||
op_neg,
|
||||
op_pos,
|
||||
op_abs,
|
||||
op_invert,
|
||||
op_int,
|
||||
op_long,
|
||||
op_float,
|
||||
op_str,
|
||||
op_cmp,
|
||||
op_gt,
|
||||
op_ge,
|
||||
op_lt,
|
||||
op_le,
|
||||
op_eq,
|
||||
op_ne,
|
||||
op_iadd,
|
||||
op_isub,
|
||||
op_imul,
|
||||
op_idiv,
|
||||
op_imod,
|
||||
op_ilshift,
|
||||
op_irshift,
|
||||
op_iand,
|
||||
op_ixor,
|
||||
op_ior,
|
||||
op_complex,
|
||||
op_bool,
|
||||
op_nonzero,
|
||||
op_repr,
|
||||
op_truediv,
|
||||
op_itruediv,
|
||||
op_hash
|
||||
};
|
||||
|
||||
enum op_type : int {
|
||||
op_l, /* base type on left */
|
||||
op_r, /* base type on right */
|
||||
op_u /* unary operator */
|
||||
op_l, /* base type on left */
|
||||
op_r, /* base type on right */
|
||||
op_u /* unary operator */
|
||||
};
|
||||
|
||||
struct self_t { };
|
||||
struct self_t {};
|
||||
static const self_t self = self_t();
|
||||
|
||||
/// Type for an unused type slot
|
||||
struct undefined_t { };
|
||||
struct undefined_t {};
|
||||
|
||||
/// Don't warn about an unused variable
|
||||
inline self_t __self() { return self; }
|
||||
|
||||
/// base template of operator implementations
|
||||
template <op_id, op_type, typename B, typename L, typename R> struct op_impl { };
|
||||
template <op_id, op_type, typename B, typename L, typename R> struct op_impl {};
|
||||
|
||||
/// Operator implementation generator
|
||||
template <op_id id, op_type ot, typename L, typename R> struct op_ {
|
||||
template <typename Class, typename... Extra> void execute(Class &cl, const Extra&... extra) const {
|
||||
using Base = typename Class::type;
|
||||
using L_type = conditional_t<std::is_same<L, self_t>::value, Base, L>;
|
||||
using R_type = conditional_t<std::is_same<R, self_t>::value, Base, R>;
|
||||
using op = op_impl<id, ot, Base, L_type, R_type>;
|
||||
cl.def(op::name(), &op::execute, is_operator(), extra...);
|
||||
#if PY_MAJOR_VERSION < 3
|
||||
if (id == op_truediv || id == op_itruediv)
|
||||
cl.def(id == op_itruediv ? "__idiv__" : ot == op_l ? "__div__" : "__rdiv__",
|
||||
&op::execute, is_operator(), extra...);
|
||||
#endif
|
||||
}
|
||||
template <typename Class, typename... Extra> void execute_cast(Class &cl, const Extra&... extra) const {
|
||||
using Base = typename Class::type;
|
||||
using L_type = conditional_t<std::is_same<L, self_t>::value, Base, L>;
|
||||
using R_type = conditional_t<std::is_same<R, self_t>::value, Base, R>;
|
||||
using op = op_impl<id, ot, Base, L_type, R_type>;
|
||||
cl.def(op::name(), &op::execute_cast, is_operator(), extra...);
|
||||
#if PY_MAJOR_VERSION < 3
|
||||
if (id == op_truediv || id == op_itruediv)
|
||||
cl.def(id == op_itruediv ? "__idiv__" : ot == op_l ? "__div__" : "__rdiv__",
|
||||
&op::execute, is_operator(), extra...);
|
||||
#endif
|
||||
}
|
||||
template <typename Class, typename... Extra>
|
||||
void execute(Class &cl, const Extra &... extra) const {
|
||||
using Base = typename Class::type;
|
||||
using L_type = conditional_t<std::is_same<L, self_t>::value, Base, L>;
|
||||
using R_type = conditional_t<std::is_same<R, self_t>::value, Base, R>;
|
||||
using op = op_impl<id, ot, Base, L_type, R_type>;
|
||||
cl.def(op::name(), &op::execute, is_operator(), extra...);
|
||||
#if PY_MAJOR_VERSION < 3
|
||||
if (id == op_truediv || id == op_itruediv)
|
||||
cl.def(id == op_itruediv ? "__idiv__"
|
||||
: ot == op_l ? "__div__" : "__rdiv__",
|
||||
&op::execute, is_operator(), extra...);
|
||||
#endif
|
||||
}
|
||||
template <typename Class, typename... Extra>
|
||||
void execute_cast(Class &cl, const Extra &... extra) const {
|
||||
using Base = typename Class::type;
|
||||
using L_type = conditional_t<std::is_same<L, self_t>::value, Base, L>;
|
||||
using R_type = conditional_t<std::is_same<R, self_t>::value, Base, R>;
|
||||
using op = op_impl<id, ot, Base, L_type, R_type>;
|
||||
cl.def(op::name(), &op::execute_cast, is_operator(), extra...);
|
||||
#if PY_MAJOR_VERSION < 3
|
||||
if (id == op_truediv || id == op_itruediv)
|
||||
cl.def(id == op_itruediv ? "__idiv__"
|
||||
: ot == op_l ? "__div__" : "__rdiv__",
|
||||
&op::execute, is_operator(), extra...);
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
#define PYBIND11_BINARY_OPERATOR(id, rid, op, expr) \
|
||||
template <typename B, typename L, typename R> struct op_impl<op_##id, op_l, B, L, R> { \
|
||||
static char const* name() { return "__" #id "__"; } \
|
||||
static auto execute(const L &l, const R &r) -> decltype(expr) { return (expr); } \
|
||||
static B execute_cast(const L &l, const R &r) { return B(expr); } \
|
||||
}; \
|
||||
template <typename B, typename L, typename R> struct op_impl<op_##id, op_r, B, L, R> { \
|
||||
static char const* name() { return "__" #rid "__"; } \
|
||||
static auto execute(const R &r, const L &l) -> decltype(expr) { return (expr); } \
|
||||
static B execute_cast(const R &r, const L &l) { return B(expr); } \
|
||||
}; \
|
||||
inline op_<op_##id, op_l, self_t, self_t> op(const self_t &, const self_t &) { \
|
||||
return op_<op_##id, op_l, self_t, self_t>(); \
|
||||
} \
|
||||
template <typename T> op_<op_##id, op_l, self_t, T> op(const self_t &, const T &) { \
|
||||
return op_<op_##id, op_l, self_t, T>(); \
|
||||
} \
|
||||
template <typename T> op_<op_##id, op_r, T, self_t> op(const T &, const self_t &) { \
|
||||
return op_<op_##id, op_r, T, self_t>(); \
|
||||
}
|
||||
#define PYBIND11_BINARY_OPERATOR(id, rid, op, expr) \
|
||||
template <typename B, typename L, typename R> \
|
||||
struct op_impl<op_##id, op_l, B, L, R> { \
|
||||
static char const *name() { return "__" #id "__"; } \
|
||||
static auto execute(const L &l, const R &r) -> decltype(expr) { \
|
||||
return (expr); \
|
||||
} \
|
||||
static B execute_cast(const L &l, const R &r) { return B(expr); } \
|
||||
}; \
|
||||
template <typename B, typename L, typename R> \
|
||||
struct op_impl<op_##id, op_r, B, L, R> { \
|
||||
static char const *name() { return "__" #rid "__"; } \
|
||||
static auto execute(const R &r, const L &l) -> decltype(expr) { \
|
||||
return (expr); \
|
||||
} \
|
||||
static B execute_cast(const R &r, const L &l) { return B(expr); } \
|
||||
}; \
|
||||
inline op_<op_##id, op_l, self_t, self_t> op(const self_t &, \
|
||||
const self_t &) { \
|
||||
return op_<op_##id, op_l, self_t, self_t>(); \
|
||||
} \
|
||||
template <typename T> \
|
||||
op_<op_##id, op_l, self_t, T> op(const self_t &, const T &) { \
|
||||
return op_<op_##id, op_l, self_t, T>(); \
|
||||
} \
|
||||
template <typename T> \
|
||||
op_<op_##id, op_r, T, self_t> op(const T &, const self_t &) { \
|
||||
return op_<op_##id, op_r, T, self_t>(); \
|
||||
}
|
||||
|
||||
#define PYBIND11_INPLACE_OPERATOR(id, op, expr) \
|
||||
template <typename B, typename L, typename R> struct op_impl<op_##id, op_l, B, L, R> { \
|
||||
static char const* name() { return "__" #id "__"; } \
|
||||
static auto execute(L &l, const R &r) -> decltype(expr) { return expr; } \
|
||||
static B execute_cast(L &l, const R &r) { return B(expr); } \
|
||||
}; \
|
||||
template <typename T> op_<op_##id, op_l, self_t, T> op(const self_t &, const T &) { \
|
||||
return op_<op_##id, op_l, self_t, T>(); \
|
||||
}
|
||||
#define PYBIND11_INPLACE_OPERATOR(id, op, expr) \
|
||||
template <typename B, typename L, typename R> \
|
||||
struct op_impl<op_##id, op_l, B, L, R> { \
|
||||
static char const *name() { return "__" #id "__"; } \
|
||||
static auto execute(L &l, const R &r) -> decltype(expr) { return expr; } \
|
||||
static B execute_cast(L &l, const R &r) { return B(expr); } \
|
||||
}; \
|
||||
template <typename T> \
|
||||
op_<op_##id, op_l, self_t, T> op(const self_t &, const T &) { \
|
||||
return op_<op_##id, op_l, self_t, T>(); \
|
||||
}
|
||||
|
||||
#define PYBIND11_UNARY_OPERATOR(id, op, expr) \
|
||||
template <typename B, typename L> struct op_impl<op_##id, op_u, B, L, undefined_t> { \
|
||||
static char const* name() { return "__" #id "__"; } \
|
||||
static auto execute(const L &l) -> decltype(expr) { return expr; } \
|
||||
static B execute_cast(const L &l) { return B(expr); } \
|
||||
}; \
|
||||
inline op_<op_##id, op_u, self_t, undefined_t> op(const self_t &) { \
|
||||
return op_<op_##id, op_u, self_t, undefined_t>(); \
|
||||
}
|
||||
#define PYBIND11_UNARY_OPERATOR(id, op, expr) \
|
||||
template <typename B, typename L> \
|
||||
struct op_impl<op_##id, op_u, B, L, undefined_t> { \
|
||||
static char const *name() { return "__" #id "__"; } \
|
||||
static auto execute(const L &l) -> decltype(expr) { return expr; } \
|
||||
static B execute_cast(const L &l) { return B(expr); } \
|
||||
}; \
|
||||
inline op_<op_##id, op_u, self_t, undefined_t> op(const self_t &) { \
|
||||
return op_<op_##id, op_u, self_t, undefined_t>(); \
|
||||
}
|
||||
|
||||
PYBIND11_BINARY_OPERATOR(sub, rsub, operator-, l - r)
|
||||
PYBIND11_BINARY_OPERATOR(add, radd, operator+, l + r)
|
||||
PYBIND11_BINARY_OPERATOR(mul, rmul, operator*, l * r)
|
||||
PYBIND11_BINARY_OPERATOR(truediv, rtruediv, operator/, l / r)
|
||||
PYBIND11_BINARY_OPERATOR(mod, rmod, operator%, l % r)
|
||||
PYBIND11_BINARY_OPERATOR(lshift, rlshift, operator<<, l << r)
|
||||
PYBIND11_BINARY_OPERATOR(rshift, rrshift, operator>>, l >> r)
|
||||
PYBIND11_BINARY_OPERATOR(and, rand, operator&, l & r)
|
||||
PYBIND11_BINARY_OPERATOR(xor, rxor, operator^, l ^ r)
|
||||
PYBIND11_BINARY_OPERATOR(eq, eq, operator==, l == r)
|
||||
PYBIND11_BINARY_OPERATOR(ne, ne, operator!=, l != r)
|
||||
PYBIND11_BINARY_OPERATOR(or, ror, operator|, l | r)
|
||||
PYBIND11_BINARY_OPERATOR(gt, lt, operator>, l > r)
|
||||
PYBIND11_BINARY_OPERATOR(ge, le, operator>=, l >= r)
|
||||
PYBIND11_BINARY_OPERATOR(lt, gt, operator<, l < r)
|
||||
PYBIND11_BINARY_OPERATOR(le, ge, operator<=, l <= r)
|
||||
//PYBIND11_BINARY_OPERATOR(pow, rpow, pow, std::pow(l, r))
|
||||
PYBIND11_INPLACE_OPERATOR(iadd, operator+=, l += r)
|
||||
PYBIND11_INPLACE_OPERATOR(isub, operator-=, l -= r)
|
||||
PYBIND11_INPLACE_OPERATOR(imul, operator*=, l *= r)
|
||||
PYBIND11_INPLACE_OPERATOR(itruediv, operator/=, l /= r)
|
||||
PYBIND11_INPLACE_OPERATOR(imod, operator%=, l %= r)
|
||||
PYBIND11_INPLACE_OPERATOR(ilshift, operator<<=, l <<= r)
|
||||
PYBIND11_INPLACE_OPERATOR(irshift, operator>>=, l >>= r)
|
||||
PYBIND11_INPLACE_OPERATOR(iand, operator&=, l &= r)
|
||||
PYBIND11_INPLACE_OPERATOR(ixor, operator^=, l ^= r)
|
||||
PYBIND11_INPLACE_OPERATOR(ior, operator|=, l |= r)
|
||||
PYBIND11_UNARY_OPERATOR(neg, operator-, -l)
|
||||
PYBIND11_UNARY_OPERATOR(pos, operator+, +l)
|
||||
PYBIND11_UNARY_OPERATOR(abs, abs, std::abs(l))
|
||||
PYBIND11_UNARY_OPERATOR(hash, hash, std::hash<L>()(l))
|
||||
PYBIND11_UNARY_OPERATOR(invert, operator~, (~l))
|
||||
PYBIND11_UNARY_OPERATOR(bool, operator!, !!l)
|
||||
PYBIND11_UNARY_OPERATOR(int, int_, (int) l)
|
||||
PYBIND11_UNARY_OPERATOR(float, float_, (double) l)
|
||||
PYBIND11_BINARY_OPERATOR(sub, rsub, operator-, l - r)
|
||||
PYBIND11_BINARY_OPERATOR(add, radd, operator+, l + r)
|
||||
PYBIND11_BINARY_OPERATOR(mul, rmul, operator*, l * r)
|
||||
PYBIND11_BINARY_OPERATOR(truediv, rtruediv, operator/, l / r)
|
||||
PYBIND11_BINARY_OPERATOR(mod, rmod, operator%, l % r)
|
||||
PYBIND11_BINARY_OPERATOR(lshift, rlshift, operator<<, l << r)
|
||||
PYBIND11_BINARY_OPERATOR(rshift, rrshift, operator>>, l>> r)
|
||||
PYBIND11_BINARY_OPERATOR(and, rand, operator&, l & r)
|
||||
PYBIND11_BINARY_OPERATOR(xor, rxor, operator^, l ^ r)
|
||||
PYBIND11_BINARY_OPERATOR(eq, eq, operator==, l == r)
|
||||
PYBIND11_BINARY_OPERATOR(ne, ne, operator!=, l != r)
|
||||
PYBIND11_BINARY_OPERATOR(or, ror, operator|, l | r)
|
||||
PYBIND11_BINARY_OPERATOR(gt, lt, operator>, l> r)
|
||||
PYBIND11_BINARY_OPERATOR(ge, le, operator>=, l >= r)
|
||||
PYBIND11_BINARY_OPERATOR(lt, gt, operator<, l<r)
|
||||
PYBIND11_BINARY_OPERATOR(le, ge, operator<=, l <= r)
|
||||
// PYBIND11_BINARY_OPERATOR(pow, rpow, pow, std::pow(l,
|
||||
// r))
|
||||
PYBIND11_INPLACE_OPERATOR(iadd, operator+=, l += r)
|
||||
PYBIND11_INPLACE_OPERATOR(isub, operator-=, l -= r)
|
||||
PYBIND11_INPLACE_OPERATOR(imul, operator*=, l *= r)
|
||||
PYBIND11_INPLACE_OPERATOR(itruediv, operator/=, l /= r)
|
||||
PYBIND11_INPLACE_OPERATOR(imod, operator%=, l %= r)
|
||||
PYBIND11_INPLACE_OPERATOR(ilshift, operator<<=, l <<= r)
|
||||
PYBIND11_INPLACE_OPERATOR(irshift, operator>>=, l >>= r)
|
||||
PYBIND11_INPLACE_OPERATOR(iand, operator&=, l &= r)
|
||||
PYBIND11_INPLACE_OPERATOR(ixor, operator^=, l ^= r)
|
||||
PYBIND11_INPLACE_OPERATOR(ior, operator|=, l |= r)
|
||||
PYBIND11_UNARY_OPERATOR(neg, operator-, - l)
|
||||
PYBIND11_UNARY_OPERATOR(pos, operator+, + l)
|
||||
PYBIND11_UNARY_OPERATOR(abs, abs, std::abs(l))
|
||||
PYBIND11_UNARY_OPERATOR(hash, hash, std::hash<L>()(l))
|
||||
PYBIND11_UNARY_OPERATOR(invert, operator~,(~l))
|
||||
PYBIND11_UNARY_OPERATOR(bool, operator!, !!l)
|
||||
PYBIND11_UNARY_OPERATOR(int, int_, (int)l)
|
||||
PYBIND11_UNARY_OPERATOR(float, float_, (double)l)
|
||||
|
||||
#undef PYBIND11_BINARY_OPERATOR
|
||||
#undef PYBIND11_INPLACE_OPERATOR
|
||||
@@ -164,5 +222,5 @@ using detail::self;
|
||||
NAMESPACE_END(PYBIND11_NAMESPACE)
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
# pragma warning(pop)
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
@@ -15,51 +15,65 @@ NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
||||
|
||||
class options {
|
||||
public:
|
||||
// Default RAII constructor, which leaves settings as they currently are.
|
||||
options() : previous_state(global_state()) {}
|
||||
|
||||
// Default RAII constructor, which leaves settings as they currently are.
|
||||
options() : previous_state(global_state()) {}
|
||||
// Class is non-copyable.
|
||||
options(const options &) = delete;
|
||||
options &operator=(const options &) = delete;
|
||||
|
||||
// Class is non-copyable.
|
||||
options(const options&) = delete;
|
||||
options& operator=(const options&) = delete;
|
||||
// Destructor, which restores settings that were in effect before.
|
||||
~options() { global_state() = previous_state; }
|
||||
|
||||
// Destructor, which restores settings that were in effect before.
|
||||
~options() {
|
||||
global_state() = previous_state;
|
||||
}
|
||||
// Setter methods (affect the global state):
|
||||
|
||||
// Setter methods (affect the global state):
|
||||
options &disable_user_defined_docstrings() & {
|
||||
global_state().show_user_defined_docstrings = false;
|
||||
return *this;
|
||||
}
|
||||
|
||||
options& disable_user_defined_docstrings() & { global_state().show_user_defined_docstrings = false; return *this; }
|
||||
options &enable_user_defined_docstrings() & {
|
||||
global_state().show_user_defined_docstrings = true;
|
||||
return *this;
|
||||
}
|
||||
|
||||
options& enable_user_defined_docstrings() & { global_state().show_user_defined_docstrings = true; return *this; }
|
||||
options &disable_function_signatures() & {
|
||||
global_state().show_function_signatures = false;
|
||||
return *this;
|
||||
}
|
||||
|
||||
options& disable_function_signatures() & { global_state().show_function_signatures = false; return *this; }
|
||||
options &enable_function_signatures() & {
|
||||
global_state().show_function_signatures = true;
|
||||
return *this;
|
||||
}
|
||||
|
||||
options& enable_function_signatures() & { global_state().show_function_signatures = true; return *this; }
|
||||
// Getter methods (return the global state):
|
||||
|
||||
// Getter methods (return the global state):
|
||||
static bool show_user_defined_docstrings() {
|
||||
return global_state().show_user_defined_docstrings;
|
||||
}
|
||||
|
||||
static bool show_user_defined_docstrings() { return global_state().show_user_defined_docstrings; }
|
||||
static bool show_function_signatures() {
|
||||
return global_state().show_function_signatures;
|
||||
}
|
||||
|
||||
static bool show_function_signatures() { return global_state().show_function_signatures; }
|
||||
|
||||
// This type is not meant to be allocated on the heap.
|
||||
void* operator new(size_t) = delete;
|
||||
// This type is not meant to be allocated on the heap.
|
||||
void *operator new(size_t) = delete;
|
||||
|
||||
private:
|
||||
struct state {
|
||||
bool show_user_defined_docstrings =
|
||||
true; //< Include user-supplied texts in docstrings.
|
||||
bool show_function_signatures =
|
||||
true; //< Include auto-generated function signatures in docstrings.
|
||||
};
|
||||
|
||||
struct state {
|
||||
bool show_user_defined_docstrings = true; //< Include user-supplied texts in docstrings.
|
||||
bool show_function_signatures = true; //< Include auto-generated function signatures in docstrings.
|
||||
};
|
||||
static state &global_state() {
|
||||
static state instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
static state &global_state() {
|
||||
static state instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
state previous_state;
|
||||
state previous_state;
|
||||
};
|
||||
|
||||
NAMESPACE_END(PYBIND11_NAMESPACE)
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -10,373 +10,411 @@
|
||||
#pragma once
|
||||
|
||||
#include "pybind11.h"
|
||||
#include <set>
|
||||
#include <unordered_set>
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
#include <deque>
|
||||
#include <iostream>
|
||||
#include <list>
|
||||
#include <deque>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <valarray>
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4127) // warning C4127: Conditional expression is constant
|
||||
#pragma warning( \
|
||||
disable : 4127) // warning C4127: Conditional expression is constant
|
||||
#endif
|
||||
|
||||
#ifdef __has_include
|
||||
// std::optional (but including it in c++14 mode isn't allowed)
|
||||
# if defined(PYBIND11_CPP17) && __has_include(<optional>)
|
||||
# include <optional>
|
||||
# define PYBIND11_HAS_OPTIONAL 1
|
||||
# endif
|
||||
#if defined(PYBIND11_CPP17) && __has_include(<optional>)
|
||||
#include <optional>
|
||||
#define PYBIND11_HAS_OPTIONAL 1
|
||||
#endif
|
||||
// std::experimental::optional (but not allowed in c++11 mode)
|
||||
# if defined(PYBIND11_CPP14) && (__has_include(<experimental/optional>) && \
|
||||
#if defined(PYBIND11_CPP14) && (__has_include(<experimental/optional>) && \
|
||||
!__has_include(<optional>))
|
||||
# include <experimental/optional>
|
||||
# define PYBIND11_HAS_EXP_OPTIONAL 1
|
||||
# endif
|
||||
#include <experimental/optional>
|
||||
#define PYBIND11_HAS_EXP_OPTIONAL 1
|
||||
#endif
|
||||
// std::variant
|
||||
# if defined(PYBIND11_CPP17) && __has_include(<variant>)
|
||||
# include <variant>
|
||||
# define PYBIND11_HAS_VARIANT 1
|
||||
# endif
|
||||
#if defined(PYBIND11_CPP17) && __has_include(<variant>)
|
||||
#include <variant>
|
||||
#define PYBIND11_HAS_VARIANT 1
|
||||
#endif
|
||||
#elif defined(_MSC_VER) && defined(PYBIND11_CPP17)
|
||||
# include <optional>
|
||||
# include <variant>
|
||||
# define PYBIND11_HAS_OPTIONAL 1
|
||||
# define PYBIND11_HAS_VARIANT 1
|
||||
#include <optional>
|
||||
#include <variant>
|
||||
#define PYBIND11_HAS_OPTIONAL 1
|
||||
#define PYBIND11_HAS_VARIANT 1
|
||||
#endif
|
||||
|
||||
NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
||||
NAMESPACE_BEGIN(detail)
|
||||
|
||||
/// Extracts an const lvalue reference or rvalue reference for U based on the type of T (e.g. for
|
||||
/// forwarding a container element). Typically used indirect via forwarded_type(), below.
|
||||
/// Extracts an const lvalue reference or rvalue reference for U based on the
|
||||
/// type of T (e.g. for forwarding a container element). Typically used
|
||||
/// indirect via forwarded_type(), below.
|
||||
template <typename T, typename U>
|
||||
using forwarded_type = conditional_t<
|
||||
std::is_lvalue_reference<T>::value, remove_reference_t<U> &, remove_reference_t<U> &&>;
|
||||
using forwarded_type =
|
||||
conditional_t<std::is_lvalue_reference<T>::value, remove_reference_t<U> &,
|
||||
remove_reference_t<U> &&>;
|
||||
|
||||
/// Forwards a value U as rvalue or lvalue according to whether T is rvalue or lvalue; typically
|
||||
/// used for forwarding a container's elements.
|
||||
template <typename T, typename U>
|
||||
forwarded_type<T, U> forward_like(U &&u) {
|
||||
return std::forward<detail::forwarded_type<T, U>>(std::forward<U>(u));
|
||||
/// Forwards a value U as rvalue or lvalue according to whether T is rvalue or
|
||||
/// lvalue; typically used for forwarding a container's elements.
|
||||
template <typename T, typename U> forwarded_type<T, U> forward_like(U &&u) {
|
||||
return std::forward<detail::forwarded_type<T, U>>(std::forward<U>(u));
|
||||
}
|
||||
|
||||
template <typename Type, typename Key> struct set_caster {
|
||||
using type = Type;
|
||||
using key_conv = make_caster<Key>;
|
||||
using type = Type;
|
||||
using key_conv = make_caster<Key>;
|
||||
|
||||
bool load(handle src, bool convert) {
|
||||
if (!isinstance<pybind11::set>(src))
|
||||
return false;
|
||||
auto s = reinterpret_borrow<pybind11::set>(src);
|
||||
value.clear();
|
||||
for (auto entry : s) {
|
||||
key_conv conv;
|
||||
if (!conv.load(entry, convert))
|
||||
return false;
|
||||
value.insert(cast_op<Key &&>(std::move(conv)));
|
||||
}
|
||||
return true;
|
||||
bool load(handle src, bool convert) {
|
||||
if (!isinstance<pybind11::set>(src))
|
||||
return false;
|
||||
auto s = reinterpret_borrow<pybind11::set>(src);
|
||||
value.clear();
|
||||
for (auto entry : s) {
|
||||
key_conv conv;
|
||||
if (!conv.load(entry, convert))
|
||||
return false;
|
||||
value.insert(cast_op<Key &&>(std::move(conv)));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static handle cast(T &&src, return_value_policy policy, handle parent) {
|
||||
if (!std::is_lvalue_reference<T>::value)
|
||||
policy = return_value_policy_override<Key>::policy(policy);
|
||||
pybind11::set s;
|
||||
for (auto &&value : src) {
|
||||
auto value_ = reinterpret_steal<object>(key_conv::cast(forward_like<T>(value), policy, parent));
|
||||
if (!value_ || !s.add(value_))
|
||||
return handle();
|
||||
}
|
||||
return s.release();
|
||||
template <typename T>
|
||||
static handle cast(T &&src, return_value_policy policy, handle parent) {
|
||||
if (!std::is_lvalue_reference<T>::value)
|
||||
policy = return_value_policy_override<Key>::policy(policy);
|
||||
pybind11::set s;
|
||||
for (auto &&value : src) {
|
||||
auto value_ = reinterpret_steal<object>(
|
||||
key_conv::cast(forward_like<T>(value), policy, parent));
|
||||
if (!value_ || !s.add(value_))
|
||||
return handle();
|
||||
}
|
||||
return s.release();
|
||||
}
|
||||
|
||||
PYBIND11_TYPE_CASTER(type, _("Set[") + key_conv::name + _("]"));
|
||||
PYBIND11_TYPE_CASTER(type, _("Set[") + key_conv::name + _("]"));
|
||||
};
|
||||
|
||||
template <typename Type, typename Key, typename Value> struct map_caster {
|
||||
using key_conv = make_caster<Key>;
|
||||
using value_conv = make_caster<Value>;
|
||||
using key_conv = make_caster<Key>;
|
||||
using value_conv = make_caster<Value>;
|
||||
|
||||
bool load(handle src, bool convert) {
|
||||
if (!isinstance<dict>(src))
|
||||
return false;
|
||||
auto d = reinterpret_borrow<dict>(src);
|
||||
value.clear();
|
||||
for (auto it : d) {
|
||||
key_conv kconv;
|
||||
value_conv vconv;
|
||||
if (!kconv.load(it.first.ptr(), convert) ||
|
||||
!vconv.load(it.second.ptr(), convert))
|
||||
return false;
|
||||
value.emplace(cast_op<Key &&>(std::move(kconv)), cast_op<Value &&>(std::move(vconv)));
|
||||
}
|
||||
return true;
|
||||
bool load(handle src, bool convert) {
|
||||
if (!isinstance<dict>(src))
|
||||
return false;
|
||||
auto d = reinterpret_borrow<dict>(src);
|
||||
value.clear();
|
||||
for (auto it : d) {
|
||||
key_conv kconv;
|
||||
value_conv vconv;
|
||||
if (!kconv.load(it.first.ptr(), convert) ||
|
||||
!vconv.load(it.second.ptr(), convert))
|
||||
return false;
|
||||
value.emplace(cast_op<Key &&>(std::move(kconv)),
|
||||
cast_op<Value &&>(std::move(vconv)));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static handle cast(T &&src, return_value_policy policy, handle parent) {
|
||||
dict d;
|
||||
return_value_policy policy_key = policy;
|
||||
return_value_policy policy_value = policy;
|
||||
if (!std::is_lvalue_reference<T>::value) {
|
||||
policy_key = return_value_policy_override<Key>::policy(policy_key);
|
||||
policy_value = return_value_policy_override<Value>::policy(policy_value);
|
||||
}
|
||||
for (auto &&kv : src) {
|
||||
auto key = reinterpret_steal<object>(key_conv::cast(forward_like<T>(kv.first), policy_key, parent));
|
||||
auto value = reinterpret_steal<object>(value_conv::cast(forward_like<T>(kv.second), policy_value, parent));
|
||||
if (!key || !value)
|
||||
return handle();
|
||||
d[key] = value;
|
||||
}
|
||||
return d.release();
|
||||
template <typename T>
|
||||
static handle cast(T &&src, return_value_policy policy, handle parent) {
|
||||
dict d;
|
||||
return_value_policy policy_key = policy;
|
||||
return_value_policy policy_value = policy;
|
||||
if (!std::is_lvalue_reference<T>::value) {
|
||||
policy_key = return_value_policy_override<Key>::policy(policy_key);
|
||||
policy_value = return_value_policy_override<Value>::policy(policy_value);
|
||||
}
|
||||
for (auto &&kv : src) {
|
||||
auto key = reinterpret_steal<object>(
|
||||
key_conv::cast(forward_like<T>(kv.first), policy_key, parent));
|
||||
auto value = reinterpret_steal<object>(
|
||||
value_conv::cast(forward_like<T>(kv.second), policy_value, parent));
|
||||
if (!key || !value)
|
||||
return handle();
|
||||
d[key] = value;
|
||||
}
|
||||
return d.release();
|
||||
}
|
||||
|
||||
PYBIND11_TYPE_CASTER(Type, _("Dict[") + key_conv::name + _(", ") + value_conv::name + _("]"));
|
||||
PYBIND11_TYPE_CASTER(Type, _("Dict[") + key_conv::name + _(", ") +
|
||||
value_conv::name + _("]"));
|
||||
};
|
||||
|
||||
template <typename Type, typename Value> struct list_caster {
|
||||
using value_conv = make_caster<Value>;
|
||||
using value_conv = make_caster<Value>;
|
||||
|
||||
bool load(handle src, bool convert) {
|
||||
if (!isinstance<sequence>(src) || isinstance<str>(src))
|
||||
return false;
|
||||
auto s = reinterpret_borrow<sequence>(src);
|
||||
value.clear();
|
||||
reserve_maybe(s, &value);
|
||||
for (auto it : s) {
|
||||
value_conv conv;
|
||||
if (!conv.load(it, convert))
|
||||
return false;
|
||||
value.push_back(cast_op<Value &&>(std::move(conv)));
|
||||
}
|
||||
return true;
|
||||
bool load(handle src, bool convert) {
|
||||
if (!isinstance<sequence>(src) || isinstance<str>(src))
|
||||
return false;
|
||||
auto s = reinterpret_borrow<sequence>(src);
|
||||
value.clear();
|
||||
reserve_maybe(s, &value);
|
||||
for (auto it : s) {
|
||||
value_conv conv;
|
||||
if (!conv.load(it, convert))
|
||||
return false;
|
||||
value.push_back(cast_op<Value &&>(std::move(conv)));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename T = Type,
|
||||
enable_if_t<std::is_same<decltype(std::declval<T>().reserve(0)), void>::value, int> = 0>
|
||||
void reserve_maybe(sequence s, Type *) { value.reserve(s.size()); }
|
||||
void reserve_maybe(sequence, void *) { }
|
||||
template <typename T = Type,
|
||||
enable_if_t<std::is_same<decltype(std::declval<T>().reserve(0)),
|
||||
void>::value,
|
||||
int> = 0>
|
||||
void reserve_maybe(sequence s, Type *) {
|
||||
value.reserve(s.size());
|
||||
}
|
||||
void reserve_maybe(sequence, void *) {}
|
||||
|
||||
public:
|
||||
template <typename T>
|
||||
static handle cast(T &&src, return_value_policy policy, handle parent) {
|
||||
if (!std::is_lvalue_reference<T>::value)
|
||||
policy = return_value_policy_override<Value>::policy(policy);
|
||||
list l(src.size());
|
||||
size_t index = 0;
|
||||
for (auto &&value : src) {
|
||||
auto value_ = reinterpret_steal<object>(value_conv::cast(forward_like<T>(value), policy, parent));
|
||||
if (!value_)
|
||||
return handle();
|
||||
PyList_SET_ITEM(l.ptr(), (ssize_t) index++, value_.release().ptr()); // steals a reference
|
||||
}
|
||||
return l.release();
|
||||
template <typename T>
|
||||
static handle cast(T &&src, return_value_policy policy, handle parent) {
|
||||
if (!std::is_lvalue_reference<T>::value)
|
||||
policy = return_value_policy_override<Value>::policy(policy);
|
||||
list l(src.size());
|
||||
size_t index = 0;
|
||||
for (auto &&value : src) {
|
||||
auto value_ = reinterpret_steal<object>(
|
||||
value_conv::cast(forward_like<T>(value), policy, parent));
|
||||
if (!value_)
|
||||
return handle();
|
||||
PyList_SET_ITEM(l.ptr(), (ssize_t)index++,
|
||||
value_.release().ptr()); // steals a reference
|
||||
}
|
||||
return l.release();
|
||||
}
|
||||
|
||||
PYBIND11_TYPE_CASTER(Type, _("List[") + value_conv::name + _("]"));
|
||||
PYBIND11_TYPE_CASTER(Type, _("List[") + value_conv::name + _("]"));
|
||||
};
|
||||
|
||||
template <typename Type, typename Alloc> struct type_caster<std::vector<Type, Alloc>>
|
||||
: list_caster<std::vector<Type, Alloc>, Type> { };
|
||||
template <typename Type, typename Alloc>
|
||||
struct type_caster<std::vector<Type, Alloc>>
|
||||
: list_caster<std::vector<Type, Alloc>, Type> {};
|
||||
|
||||
template <typename Type, typename Alloc> struct type_caster<std::deque<Type, Alloc>>
|
||||
: list_caster<std::deque<Type, Alloc>, Type> { };
|
||||
template <typename Type, typename Alloc>
|
||||
struct type_caster<std::deque<Type, Alloc>>
|
||||
: list_caster<std::deque<Type, Alloc>, Type> {};
|
||||
|
||||
template <typename Type, typename Alloc> struct type_caster<std::list<Type, Alloc>>
|
||||
: list_caster<std::list<Type, Alloc>, Type> { };
|
||||
template <typename Type, typename Alloc>
|
||||
struct type_caster<std::list<Type, Alloc>>
|
||||
: list_caster<std::list<Type, Alloc>, Type> {};
|
||||
|
||||
template <typename ArrayType, typename Value, bool Resizable, size_t Size = 0> struct array_caster {
|
||||
using value_conv = make_caster<Value>;
|
||||
template <typename ArrayType, typename Value, bool Resizable, size_t Size = 0>
|
||||
struct array_caster {
|
||||
using value_conv = make_caster<Value>;
|
||||
|
||||
private:
|
||||
template <bool R = Resizable>
|
||||
bool require_size(enable_if_t<R, size_t> size) {
|
||||
if (value.size() != size)
|
||||
value.resize(size);
|
||||
return true;
|
||||
}
|
||||
template <bool R = Resizable>
|
||||
bool require_size(enable_if_t<!R, size_t> size) {
|
||||
return size == Size;
|
||||
}
|
||||
template <bool R = Resizable> bool require_size(enable_if_t<R, size_t> size) {
|
||||
if (value.size() != size)
|
||||
value.resize(size);
|
||||
return true;
|
||||
}
|
||||
template <bool R = Resizable>
|
||||
bool require_size(enable_if_t<!R, size_t> size) {
|
||||
return size == Size;
|
||||
}
|
||||
|
||||
public:
|
||||
bool load(handle src, bool convert) {
|
||||
if (!isinstance<sequence>(src))
|
||||
return false;
|
||||
auto l = reinterpret_borrow<sequence>(src);
|
||||
if (!require_size(l.size()))
|
||||
return false;
|
||||
size_t ctr = 0;
|
||||
for (auto it : l) {
|
||||
value_conv conv;
|
||||
if (!conv.load(it, convert))
|
||||
return false;
|
||||
value[ctr++] = cast_op<Value &&>(std::move(conv));
|
||||
}
|
||||
return true;
|
||||
bool load(handle src, bool convert) {
|
||||
if (!isinstance<sequence>(src))
|
||||
return false;
|
||||
auto l = reinterpret_borrow<sequence>(src);
|
||||
if (!require_size(l.size()))
|
||||
return false;
|
||||
size_t ctr = 0;
|
||||
for (auto it : l) {
|
||||
value_conv conv;
|
||||
if (!conv.load(it, convert))
|
||||
return false;
|
||||
value[ctr++] = cast_op<Value &&>(std::move(conv));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static handle cast(T &&src, return_value_policy policy, handle parent) {
|
||||
list l(src.size());
|
||||
size_t index = 0;
|
||||
for (auto &&value : src) {
|
||||
auto value_ = reinterpret_steal<object>(value_conv::cast(forward_like<T>(value), policy, parent));
|
||||
if (!value_)
|
||||
return handle();
|
||||
PyList_SET_ITEM(l.ptr(), (ssize_t) index++, value_.release().ptr()); // steals a reference
|
||||
}
|
||||
return l.release();
|
||||
template <typename T>
|
||||
static handle cast(T &&src, return_value_policy policy, handle parent) {
|
||||
list l(src.size());
|
||||
size_t index = 0;
|
||||
for (auto &&value : src) {
|
||||
auto value_ = reinterpret_steal<object>(
|
||||
value_conv::cast(forward_like<T>(value), policy, parent));
|
||||
if (!value_)
|
||||
return handle();
|
||||
PyList_SET_ITEM(l.ptr(), (ssize_t)index++,
|
||||
value_.release().ptr()); // steals a reference
|
||||
}
|
||||
return l.release();
|
||||
}
|
||||
|
||||
PYBIND11_TYPE_CASTER(ArrayType, _("List[") + value_conv::name + _<Resizable>(_(""), _("[") + _<Size>() + _("]")) + _("]"));
|
||||
PYBIND11_TYPE_CASTER(ArrayType,
|
||||
_("List[") + value_conv::name +
|
||||
_<Resizable>(_(""), _("[") + _<Size>() + _("]")) +
|
||||
_("]"));
|
||||
};
|
||||
|
||||
template <typename Type, size_t Size> struct type_caster<std::array<Type, Size>>
|
||||
: array_caster<std::array<Type, Size>, Type, false, Size> { };
|
||||
template <typename Type, size_t Size>
|
||||
struct type_caster<std::array<Type, Size>>
|
||||
: array_caster<std::array<Type, Size>, Type, false, Size> {};
|
||||
|
||||
template <typename Type> struct type_caster<std::valarray<Type>>
|
||||
: array_caster<std::valarray<Type>, Type, true> { };
|
||||
template <typename Type>
|
||||
struct type_caster<std::valarray<Type>>
|
||||
: array_caster<std::valarray<Type>, Type, true> {};
|
||||
|
||||
template <typename Key, typename Compare, typename Alloc> struct type_caster<std::set<Key, Compare, Alloc>>
|
||||
: set_caster<std::set<Key, Compare, Alloc>, Key> { };
|
||||
template <typename Key, typename Compare, typename Alloc>
|
||||
struct type_caster<std::set<Key, Compare, Alloc>>
|
||||
: set_caster<std::set<Key, Compare, Alloc>, Key> {};
|
||||
|
||||
template <typename Key, typename Hash, typename Equal, typename Alloc> struct type_caster<std::unordered_set<Key, Hash, Equal, Alloc>>
|
||||
: set_caster<std::unordered_set<Key, Hash, Equal, Alloc>, Key> { };
|
||||
template <typename Key, typename Hash, typename Equal, typename Alloc>
|
||||
struct type_caster<std::unordered_set<Key, Hash, Equal, Alloc>>
|
||||
: set_caster<std::unordered_set<Key, Hash, Equal, Alloc>, Key> {};
|
||||
|
||||
template <typename Key, typename Value, typename Compare, typename Alloc> struct type_caster<std::map<Key, Value, Compare, Alloc>>
|
||||
: map_caster<std::map<Key, Value, Compare, Alloc>, Key, Value> { };
|
||||
template <typename Key, typename Value, typename Compare, typename Alloc>
|
||||
struct type_caster<std::map<Key, Value, Compare, Alloc>>
|
||||
: map_caster<std::map<Key, Value, Compare, Alloc>, Key, Value> {};
|
||||
|
||||
template <typename Key, typename Value, typename Hash, typename Equal, typename Alloc> struct type_caster<std::unordered_map<Key, Value, Hash, Equal, Alloc>>
|
||||
: map_caster<std::unordered_map<Key, Value, Hash, Equal, Alloc>, Key, Value> { };
|
||||
template <typename Key, typename Value, typename Hash, typename Equal,
|
||||
typename Alloc>
|
||||
struct type_caster<std::unordered_map<Key, Value, Hash, Equal, Alloc>>
|
||||
: map_caster<std::unordered_map<Key, Value, Hash, Equal, Alloc>, Key,
|
||||
Value> {};
|
||||
|
||||
// This type caster is intended to be used for std::optional and std::experimental::optional
|
||||
template<typename T> struct optional_caster {
|
||||
using value_conv = make_caster<typename T::value_type>;
|
||||
// This type caster is intended to be used for std::optional and
|
||||
// std::experimental::optional
|
||||
template <typename T> struct optional_caster {
|
||||
using value_conv = make_caster<typename T::value_type>;
|
||||
|
||||
template <typename T_>
|
||||
static handle cast(T_ &&src, return_value_policy policy, handle parent) {
|
||||
if (!src)
|
||||
return none().inc_ref();
|
||||
policy = return_value_policy_override<typename T::value_type>::policy(policy);
|
||||
return value_conv::cast(*std::forward<T_>(src), policy, parent);
|
||||
template <typename T_>
|
||||
static handle cast(T_ &&src, return_value_policy policy, handle parent) {
|
||||
if (!src)
|
||||
return none().inc_ref();
|
||||
policy =
|
||||
return_value_policy_override<typename T::value_type>::policy(policy);
|
||||
return value_conv::cast(*std::forward<T_>(src), policy, parent);
|
||||
}
|
||||
|
||||
bool load(handle src, bool convert) {
|
||||
if (!src) {
|
||||
return false;
|
||||
} else if (src.is_none()) {
|
||||
return true; // default-constructed value is already empty
|
||||
}
|
||||
value_conv inner_caster;
|
||||
if (!inner_caster.load(src, convert))
|
||||
return false;
|
||||
|
||||
bool load(handle src, bool convert) {
|
||||
if (!src) {
|
||||
return false;
|
||||
} else if (src.is_none()) {
|
||||
return true; // default-constructed value is already empty
|
||||
}
|
||||
value_conv inner_caster;
|
||||
if (!inner_caster.load(src, convert))
|
||||
return false;
|
||||
value.emplace(cast_op<typename T::value_type &&>(std::move(inner_caster)));
|
||||
return true;
|
||||
}
|
||||
|
||||
value.emplace(cast_op<typename T::value_type &&>(std::move(inner_caster)));
|
||||
return true;
|
||||
}
|
||||
|
||||
PYBIND11_TYPE_CASTER(T, _("Optional[") + value_conv::name + _("]"));
|
||||
PYBIND11_TYPE_CASTER(T, _("Optional[") + value_conv::name + _("]"));
|
||||
};
|
||||
|
||||
#if PYBIND11_HAS_OPTIONAL
|
||||
template<typename T> struct type_caster<std::optional<T>>
|
||||
template <typename T>
|
||||
struct type_caster<std::optional<T>>
|
||||
: public optional_caster<std::optional<T>> {};
|
||||
|
||||
template<> struct type_caster<std::nullopt_t>
|
||||
: public void_caster<std::nullopt_t> {};
|
||||
template <>
|
||||
struct type_caster<std::nullopt_t> : public void_caster<std::nullopt_t> {};
|
||||
#endif
|
||||
|
||||
#if PYBIND11_HAS_EXP_OPTIONAL
|
||||
template<typename T> struct type_caster<std::experimental::optional<T>>
|
||||
template <typename T>
|
||||
struct type_caster<std::experimental::optional<T>>
|
||||
: public optional_caster<std::experimental::optional<T>> {};
|
||||
|
||||
template<> struct type_caster<std::experimental::nullopt_t>
|
||||
template <>
|
||||
struct type_caster<std::experimental::nullopt_t>
|
||||
: public void_caster<std::experimental::nullopt_t> {};
|
||||
#endif
|
||||
|
||||
/// Visit a variant and cast any found type to Python
|
||||
struct variant_caster_visitor {
|
||||
return_value_policy policy;
|
||||
handle parent;
|
||||
return_value_policy policy;
|
||||
handle parent;
|
||||
|
||||
using result_type = handle; // required by boost::variant in C++11
|
||||
using result_type = handle; // required by boost::variant in C++11
|
||||
|
||||
template <typename T>
|
||||
result_type operator()(T &&src) const {
|
||||
return make_caster<T>::cast(std::forward<T>(src), policy, parent);
|
||||
}
|
||||
template <typename T> result_type operator()(T &&src) const {
|
||||
return make_caster<T>::cast(std::forward<T>(src), policy, parent);
|
||||
}
|
||||
};
|
||||
|
||||
/// Helper class which abstracts away variant's `visit` function. `std::variant` and similar
|
||||
/// `namespace::variant` types which provide a `namespace::visit()` function are handled here
|
||||
/// automatically using argument-dependent lookup. Users can provide specializations for other
|
||||
/// variant-like classes, e.g. `boost::variant` and `boost::apply_visitor`.
|
||||
template <template<typename...> class Variant>
|
||||
struct visit_helper {
|
||||
template <typename... Args>
|
||||
static auto call(Args &&...args) -> decltype(visit(std::forward<Args>(args)...)) {
|
||||
return visit(std::forward<Args>(args)...);
|
||||
}
|
||||
/// Helper class which abstracts away variant's `visit` function. `std::variant`
|
||||
/// and similar `namespace::variant` types which provide a `namespace::visit()`
|
||||
/// function are handled here automatically using argument-dependent lookup.
|
||||
/// Users can provide specializations for other variant-like classes, e.g.
|
||||
/// `boost::variant` and `boost::apply_visitor`.
|
||||
template <template <typename...> class Variant> struct visit_helper {
|
||||
template <typename... Args>
|
||||
static auto call(Args &&... args)
|
||||
-> decltype(visit(std::forward<Args>(args)...)) {
|
||||
return visit(std::forward<Args>(args)...);
|
||||
}
|
||||
};
|
||||
|
||||
/// Generic variant caster
|
||||
template <typename Variant> struct variant_caster;
|
||||
|
||||
template <template<typename...> class V, typename... Ts>
|
||||
template <template <typename...> class V, typename... Ts>
|
||||
struct variant_caster<V<Ts...>> {
|
||||
static_assert(sizeof...(Ts) > 0, "Variant must consist of at least one alternative.");
|
||||
static_assert(sizeof...(Ts) > 0,
|
||||
"Variant must consist of at least one alternative.");
|
||||
|
||||
template <typename U, typename... Us>
|
||||
bool load_alternative(handle src, bool convert, type_list<U, Us...>) {
|
||||
auto caster = make_caster<U>();
|
||||
if (caster.load(src, convert)) {
|
||||
value = cast_op<U>(caster);
|
||||
return true;
|
||||
}
|
||||
return load_alternative(src, convert, type_list<Us...>{});
|
||||
template <typename U, typename... Us>
|
||||
bool load_alternative(handle src, bool convert, type_list<U, Us...>) {
|
||||
auto caster = make_caster<U>();
|
||||
if (caster.load(src, convert)) {
|
||||
value = cast_op<U>(caster);
|
||||
return true;
|
||||
}
|
||||
return load_alternative(src, convert, type_list<Us...>{});
|
||||
}
|
||||
|
||||
bool load_alternative(handle, bool, type_list<>) { return false; }
|
||||
bool load_alternative(handle, bool, type_list<>) { return false; }
|
||||
|
||||
bool load(handle src, bool convert) {
|
||||
// Do a first pass without conversions to improve constructor resolution.
|
||||
// E.g. `py::int_(1).cast<variant<double, int>>()` needs to fill the `int`
|
||||
// slot of the variant. Without two-pass loading `double` would be filled
|
||||
// because it appears first and a conversion is possible.
|
||||
if (convert && load_alternative(src, false, type_list<Ts...>{}))
|
||||
return true;
|
||||
return load_alternative(src, convert, type_list<Ts...>{});
|
||||
}
|
||||
bool load(handle src, bool convert) {
|
||||
// Do a first pass without conversions to improve constructor resolution.
|
||||
// E.g. `py::int_(1).cast<variant<double, int>>()` needs to fill the `int`
|
||||
// slot of the variant. Without two-pass loading `double` would be filled
|
||||
// because it appears first and a conversion is possible.
|
||||
if (convert && load_alternative(src, false, type_list<Ts...>{}))
|
||||
return true;
|
||||
return load_alternative(src, convert, type_list<Ts...>{});
|
||||
}
|
||||
|
||||
template <typename Variant>
|
||||
static handle cast(Variant &&src, return_value_policy policy, handle parent) {
|
||||
return visit_helper<V>::call(variant_caster_visitor{policy, parent},
|
||||
std::forward<Variant>(src));
|
||||
}
|
||||
template <typename Variant>
|
||||
static handle cast(Variant &&src, return_value_policy policy, handle parent) {
|
||||
return visit_helper<V>::call(variant_caster_visitor{policy, parent},
|
||||
std::forward<Variant>(src));
|
||||
}
|
||||
|
||||
using Type = V<Ts...>;
|
||||
PYBIND11_TYPE_CASTER(Type, _("Union[") + detail::concat(make_caster<Ts>::name...) + _("]"));
|
||||
using Type = V<Ts...>;
|
||||
PYBIND11_TYPE_CASTER(Type, _("Union[") +
|
||||
detail::concat(make_caster<Ts>::name...) +
|
||||
_("]"));
|
||||
};
|
||||
|
||||
#if PYBIND11_HAS_VARIANT
|
||||
template <typename... Ts>
|
||||
struct type_caster<std::variant<Ts...>> : variant_caster<std::variant<Ts...>> { };
|
||||
struct type_caster<std::variant<Ts...>> : variant_caster<std::variant<Ts...>> {
|
||||
};
|
||||
#endif
|
||||
|
||||
NAMESPACE_END(detail)
|
||||
|
||||
inline std::ostream &operator<<(std::ostream &os, const handle &obj) {
|
||||
os << (std::string) str(obj);
|
||||
return os;
|
||||
os << (std::string)str(obj);
|
||||
return os;
|
||||
}
|
||||
|
||||
NAMESPACE_END(PYBIND11_NAMESPACE)
|
||||
|
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user