Unverified Commit ec24786e authored by Ralf W. Grosse-Kunstleve's avatar Ralf W. Grosse-Kunstleve Committed by GitHub
Browse files

Fully-automatic clang-format with include reordering (#3713)

* chore: add clang-format

* Removing check-style (Classic check-style)

Ported from @henryiii's https://github.com/pybind/pybind11/pull/3683/commits/53056b1b0eeb4136b0d7362a8261b6b59658e0a7



* Automatic clang-format changes (NO manual changes).
Co-authored-by: default avatarHenry Schreiner <henryschreineriii@gmail.com>
parent e96221be
......@@ -141,11 +141,7 @@ repos:
entry: PyBind|Numpy|Cmake|CCache|PyTest
exclude: .pre-commit-config.yaml
- repo: local
- repo: https://github.com/pre-commit/mirrors-clang-format
rev: "v13.0.0"
hooks:
- id: check-style
name: Classic check-style
language: system
types:
- c++
entry: ./tools/check-style.sh
- id: clang-format
......@@ -20,54 +20,62 @@ PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
/// @{
/// Annotation for methods
struct is_method { handle class_;
struct is_method {
handle class_;
explicit is_method(const handle &c) : class_(c) {}
};
/// Annotation for operators
struct is_operator { };
struct is_operator {};
/// Annotation for classes that cannot be subclassed
struct is_final { };
struct is_final {};
/// Annotation for parent scope
struct scope { handle value;
struct scope {
handle value;
explicit scope(const handle &s) : value(s) {}
};
/// Annotation for documentation
struct doc { const char *value;
struct doc {
const char *value;
explicit doc(const char *value) : value(value) {}
};
/// Annotation for function names
struct name { const char *value;
struct name {
const char *value;
explicit name(const char *value) : value(value) {}
};
/// Annotation indicating that a function is an overload associated with a given "sibling"
struct sibling { handle value;
struct sibling {
handle value;
explicit sibling(const handle &value) : value(value.ptr()) {}
};
/// Annotation indicating that a class derives from another given type
template <typename T> struct base {
template <typename T>
struct base {
PYBIND11_DEPRECATED("base<T>() was deprecated in favor of specifying 'T' as a template argument to class_")
base() { } // NOLINT(modernize-use-equals-default): breaks MSVC 2015 when adding an attribute
PYBIND11_DEPRECATED(
"base<T>() was deprecated in favor of specifying 'T' as a template argument to class_")
base() {} // NOLINT(modernize-use-equals-default): breaks MSVC 2015 when adding an attribute
};
/// 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 { };
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 {
......@@ -78,7 +86,7 @@ struct metaclass {
metaclass() {}
/// Override pybind11's default metaclass
explicit metaclass(handle value) : value(value) { }
explicit metaclass(handle value) : value(value) {}
};
/// Specifies a custom callback with signature `void (PyHeapTypeObject*)` that
......@@ -99,15 +107,16 @@ struct custom_type_setup {
};
/// Annotation that marks a class as local to the module:
struct module_local { const bool value;
struct module_local {
const bool value;
constexpr explicit module_local(bool v = true) : value(v) {}
};
/// Annotation to mark enums as an arithmetic type
struct arithmetic { };
struct arithmetic {};
/// Mark a function for addition at the beginning of the existing overload chain instead of the end
struct prepend { };
struct prepend {};
/** \rst
A call policy which places one or more guard variables (``Ts...``) around the function call.
......@@ -127,9 +136,13 @@ struct prepend { };
return foo(args...); // forwarded arguments
});
\endrst */
template <typename... Ts> struct call_guard;
template <typename... Ts>
struct call_guard;
template <> struct call_guard<> { using type = detail::void_type; };
template <>
struct call_guard<> {
using type = detail::void_type;
};
template <typename T>
struct call_guard<T> {
......@@ -154,7 +167,8 @@ PYBIND11_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_;
template <op_id id, op_type ot, typename L = undefined_t, typename R = undefined_t>
struct op_;
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
......@@ -166,15 +180,16 @@ struct argument_record {
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) { }
: 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), is_method(false), has_args(false),
has_kwargs(false), prepend(false) { }
is_operator(false), is_method(false), has_args(false), has_kwargs(false),
prepend(false) {}
/// Function name
char *name = nullptr; /* why no C++ strings? They generate heavier code.. */
......@@ -189,13 +204,13 @@ struct function_record {
std::vector<argument_record> args;
/// Pointer to lambda function which converts arguments and performs the actual call
handle (*impl) (function_call &) = nullptr;
handle (*impl)(function_call &) = nullptr;
/// Storage for the wrapped function pointer and captured data, if any
void *data[3] = { };
void *data[3] = {};
/// Pointer to custom destructor for 'data' (if needed)
void (*free_data) (function_record *ptr) = nullptr;
void (*free_data)(function_record *ptr) = nullptr;
/// Return value policy associated with this function
return_value_policy policy = return_value_policy::automatic;
......@@ -251,7 +266,7 @@ struct function_record {
struct type_record {
PYBIND11_NOINLINE type_record()
: multiple_inheritance(false), dynamic_attr(false), buffer_protocol(false),
default_holder(true), module_local(false), is_final(false) { }
default_holder(true), module_local(false), is_final(false) {}
/// Handle to the parent scope
handle scope;
......@@ -310,22 +325,22 @@ struct type_record {
/// Is the class inheritable from python classes?
bool is_final : 1;
PYBIND11_NOINLINE void add_base(const std::type_info &base, void *(*caster)(void *)) {
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 + "\"");
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"));
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);
......@@ -340,14 +355,13 @@ struct type_record {
}
};
inline function_call::function_call(const function_record &f, handle p) :
func(f), parent(p) {
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
......@@ -355,60 +369,79 @@ struct is_new_style_constructor { };
* fields in the type_record and function_record data structures or executed at
* runtime to deal with custom call policies (e.g. keep_alive).
*/
template <typename T, typename SFINAE = void> struct process_attribute;
template <typename T, typename SFINAE = void>
struct process_attribute;
template <typename T> struct process_attribute_default {
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) { }
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> {
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); }
};
/// Process an attribute specifying the function's docstring
template <> struct process_attribute<doc> : process_attribute_default<doc> {
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); }
};
/// 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 *> {
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> {
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> {
/// 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> {
template <>
struct process_attribute<scope> : process_attribute_default<scope> {
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> {
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;
}
};
inline void check_kw_only_arg(const arg &a, function_record *r) {
......@@ -425,7 +458,8 @@ inline void append_self_arg_if_needed(function_record *r) {
}
/// Process a keyword argument attribute (*without* a default value)
template <> struct process_attribute<arg> : process_attribute_default<arg> {
template <>
struct process_attribute<arg> : process_attribute_default<arg> {
static void init(const arg &a, function_record *r) {
append_self_arg_if_needed(r);
r->args.emplace_back(a.name, nullptr, handle(), !a.flag_noconvert, a.flag_none);
......@@ -435,7 +469,8 @@ template <> struct process_attribute<arg> : process_attribute_default<arg> {
};
/// Process a keyword argument attribute (*with* a default value)
template <> struct process_attribute<arg_v> : process_attribute_default<arg_v> {
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(
......@@ -451,15 +486,16 @@ template <> struct process_attribute<arg_v> : process_attribute_default<arg_v> {
descr += a.type + "'";
if (r->is_method) {
if (r->name) {
descr += " in method '" + (std::string) str(r->scope) + "." + (std::string) 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?)");
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?). "
......@@ -473,7 +509,8 @@ template <> struct process_attribute<arg_v> : process_attribute_default<arg_v> {
};
/// Process a keyword-only-arguments-follow pseudo argument
template <> struct process_attribute<kw_only> : process_attribute_default<kw_only> {
template <>
struct process_attribute<kw_only> : process_attribute_default<kw_only> {
static void init(const kw_only &, function_record *r) {
append_self_arg_if_needed(r);
if (r->has_args && r->nargs_pos != static_cast<std::uint16_t>(r->args.size())) {
......@@ -485,7 +522,8 @@ template <> struct process_attribute<kw_only> : process_attribute_default<kw_onl
};
/// Process a positional-only-argument maker
template <> struct process_attribute<pos_only> : process_attribute_default<pos_only> {
template <>
struct process_attribute<pos_only> : process_attribute_default<pos_only> {
static void init(const pos_only &, function_record *r) {
append_self_arg_if_needed(r);
r->nargs_pos_only = static_cast<std::uint16_t>(r->args.size());
......@@ -496,9 +534,11 @@ template <> struct process_attribute<pos_only> : process_attribute_default<pos_o
}
};
/// 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> {
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); }
};
......@@ -511,7 +551,9 @@ struct process_attribute<base<T>> : process_attribute_default<base<T>> {
/// 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; }
static void init(const multiple_inheritance &, type_record *r) {
r->multiple_inheritance = true;
}
};
template <>
......@@ -557,34 +599,41 @@ 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 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()); }
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) { }
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 &) { }
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); }
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) {
template <typename... Args>
struct process_attributes {
static void init(const Args &...args, function_record *r) {
PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(r);
PYBIND11_WORKAROUND_INCORRECT_GCC_UNUSED_BUT_SET_PARAMETER(r);
using expander = int[];
(void) expander{
0, ((void) process_attribute<typename std::decay<Args>::type>::init(args, r), 0)...};
}
static void init(const Args&... args, type_record *r) {
static void init(const Args &...args, type_record *r) {
PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(r);
PYBIND11_WORKAROUND_INCORRECT_GCC_UNUSED_BUT_SET_PARAMETER(r);
using expander = int[];
......
......@@ -54,8 +54,13 @@ struct buffer_info {
buffer_info() = default;
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, bool readonly=false)
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,
bool readonly = false)
: ptr(ptr), itemsize(itemsize), size(1), format(format), ndim(ndim),
shape(std::move(shape_in)), strides(std::move(strides_in)), readonly(readonly) {
if (ndim != (ssize_t) shape.size() || ndim != (ssize_t) strides.size()) {
......@@ -67,22 +72,41 @@ struct buffer_info {
}
template <typename T>
buffer_info(T *ptr, detail::any_container<ssize_t> shape_in, detail::any_container<ssize_t> strides_in, bool readonly=false)
: 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), readonly) { }
buffer_info(void *ptr, ssize_t itemsize, const std::string &format, ssize_t size, bool readonly=false)
: buffer_info(ptr, itemsize, format, 1, {size}, {itemsize}, readonly) { }
buffer_info(T *ptr,
detail::any_container<ssize_t> shape_in,
detail::any_container<ssize_t> strides_in,
bool readonly = false)
: 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),
readonly) {}
buffer_info(void *ptr,
ssize_t itemsize,
const std::string &format,
ssize_t size,
bool readonly = false)
: buffer_info(ptr, itemsize, format, 1, {size}, {itemsize}, readonly) {}
template <typename T>
buffer_info(T *ptr, ssize_t size, bool readonly=false)
: buffer_info(ptr, sizeof(T), format_descriptor<T>::format(), size, readonly) { }
buffer_info(T *ptr, ssize_t size, bool readonly = false)
: buffer_info(ptr, sizeof(T), format_descriptor<T>::format(), size, readonly) {}
template <typename T>
buffer_info(const T *ptr, ssize_t size, bool readonly=true)
: buffer_info(const_cast<T*>(ptr), sizeof(T), format_descriptor<T>::format(), size, readonly) { }
buffer_info(const T *ptr, ssize_t size, bool readonly = true)
: buffer_info(
const_cast<T *>(ptr), sizeof(T), format_descriptor<T>::format(), size, readonly) {}
explicit buffer_info(Py_buffer *view, bool ownview = true)
: buffer_info(view->buf, view->itemsize, view->format, view->ndim,
: buffer_info(
view->buf,
view->itemsize,
view->format,
view->ndim,
{view->shape, view->shape + view->ndim},
/* Though buffer::request() requests PyBUF_STRIDES, ctypes objects
* ignore this flag and return a view with NULL strides.
......@@ -98,7 +122,7 @@ struct buffer_info {
}
buffer_info(const buffer_info &) = delete;
buffer_info& operator=(const buffer_info &) = delete;
buffer_info &operator=(const buffer_info &) = delete;
buffer_info(buffer_info &&other) noexcept { (*this) = std::move(other); }
......@@ -117,17 +141,28 @@ struct buffer_info {
}
~buffer_info() {
if (m_view && ownview) { PyBuffer_Release(m_view); delete m_view; }
if (m_view && ownview) {
PyBuffer_Release(m_view);
delete m_view;
}
}
Py_buffer *view() const { return m_view; }
Py_buffer *&view() { return m_view; }
private:
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, bool readonly)
: buffer_info(ptr, itemsize, format, ndim, std::move(shape_in), std::move(strides_in), readonly) { }
private:
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,
bool readonly)
: buffer_info(
ptr, itemsize, format, ndim, std::move(shape_in), std::move(strides_in), readonly) {}
Py_buffer *m_view = nullptr;
bool ownview = false;
......@@ -135,17 +170,22 @@ private:
PYBIND11_NAMESPACE_BEGIN(detail)
template <typename T, typename SFINAE = void> struct compare_buffer_info {
static bool compare(const buffer_info& b) {
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);
}
};
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")));
}
};
......
......@@ -10,11 +10,12 @@
#pragma once
#include "pytypes.h"
#include "detail/common.h"
#include "detail/descr.h"
#include "detail/type_caster_base.h"
#include "detail/typeid.h"
#include "pytypes.h"
#include <array>
#include <cstring>
#include <functional>
......@@ -30,35 +31,42 @@
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
PYBIND11_NAMESPACE_BEGIN(detail)
template <typename type, typename SFINAE = void> class type_caster : public type_caster_base<type> { };
template <typename type> using make_caster = type_caster<intrinsic_t<type>>;
template <typename type, typename SFINAE = void>
class type_caster : public type_caster_base<type> {};
template <typename type>
using make_caster = type_caster<intrinsic_t<type>>;
// Shortcut for calling a caster's `cast_op_type` cast operator for casting a type_caster to a T
template <typename T> typename make_caster<T>::template cast_op_type<T> cast_op(make_caster<T> &caster) {
template <typename T>
typename make_caster<T>::template cast_op_type<T> cast_op(make_caster<T> &caster) {
return caster.operator typename make_caster<T>::template cast_op_type<T>();
}
template <typename T> typename make_caster<T>::template cast_op_type<typename std::add_rvalue_reference<T>::type>
template <typename T>
typename make_caster<T>::template cast_op_type<typename std::add_rvalue_reference<T>::type>
cast_op(make_caster<T> &&caster) {
return std::move(caster).operator
typename make_caster<T>::template cast_op_type<typename std::add_rvalue_reference<T>::type>();
return std::move(caster).operator typename make_caster<T>::
template cast_op_type<typename std::add_rvalue_reference<T>::type>();
}
template <typename type> class type_caster<std::reference_wrapper<type>> {
template <typename type>
class type_caster<std::reference_wrapper<type>> {
private:
using caster_t = make_caster<type>;
caster_t subcaster;
using reference_t = type&;
using subcaster_cast_op_type =
typename caster_t::template cast_op_type<reference_t>;
using reference_t = type &;
using subcaster_cast_op_type = typename caster_t::template cast_op_type<reference_t>;
static_assert(std::is_same<typename std::remove_const<type>::type &, subcaster_cast_op_type>::value ||
std::is_same<reference_t, subcaster_cast_op_type>::value,
static_assert(
std::is_same<typename std::remove_const<type>::type &, subcaster_cast_op_type>::value
|| std::is_same<reference_t, subcaster_cast_op_type>::value,
"std::reference_wrapper<T> caster requires T to have a caster with an "
"`operator T &()` or `operator const T &()`");
public:
bool load(handle src, bool convert) { return subcaster.load(src, convert); }
static constexpr auto name = caster_t::name;
static handle cast(const std::reference_wrapper<type> &src, return_value_policy policy, handle parent) {
static handle
cast(const std::reference_wrapper<type> &src, return_value_policy policy, handle parent) {
// It is definitely wrong to take ownership of this pointer, so mask that rvp
if (policy == return_value_policy::take_ownership
|| policy == return_value_policy::automatic) {
......@@ -66,7 +74,8 @@ public:
}
return caster_t::cast(&src.get(), policy, parent);
}
template <typename T> using cast_op_type = std::reference_wrapper<type>;
template <typename T>
using cast_op_type = std::reference_wrapper<type>;
explicit operator std::reference_wrapper<type>() { return cast_op<type &>(subcaster); }
};
......@@ -93,24 +102,25 @@ public:
template <typename T_> \
using cast_op_type = pybind11::detail::movable_cast_op_type<T_>
template <typename CharT> using is_std_char_type = any_of<
std::is_same<CharT, char>, /* std::string */
template <typename CharT>
using is_std_char_type = any_of<std::is_same<CharT, char>, /* std::string */
#if defined(PYBIND11_HAS_U8STRING)
std::is_same<CharT, char8_t>, /* std::u8string */
#endif
std::is_same<CharT, char16_t>, /* std::u16string */
std::is_same<CharT, char32_t>, /* std::u32string */
std::is_same<CharT, wchar_t> /* std::wstring */
>;
>;
template <typename T>
struct type_caster<T, enable_if_t<std::is_arithmetic<T>::value && !is_std_char_type<T>::value>> {
using _py_type_0 = conditional_t<sizeof(T) <= sizeof(long), long, long long>;
using _py_type_1 = conditional_t<std::is_signed<T>::value, _py_type_0, typename std::make_unsigned<_py_type_0>::type>;
using _py_type_1 = conditional_t<std::is_signed<T>::value,
_py_type_0,
typename std::make_unsigned<_py_type_0>::type>;
using py_type = conditional_t<std::is_floating_point<T>::value, double, _py_type_1>;
public:
public:
bool load(handle src, bool convert) {
py_type py_value;
......@@ -146,8 +156,7 @@ public:
PyErr_Clear();
if (!convert)
return false;
}
else {
} else {
src_or_index = index;
}
}
......@@ -166,7 +175,9 @@ public:
// Check to see if the conversion is valid (integers should match exactly)
// Signed/unsigned checks happen elsewhere
if (py_err || (std::is_integral<T>::value && sizeof(py_type) != sizeof(T) && py_value != (py_type) (T) py_value)) {
if (py_err
|| (std::is_integral<T>::value && sizeof(py_type) != sizeof(T)
&& py_value != (py_type) (T) py_value)) {
PyErr_Clear();
if (py_err && convert && (PyNumber_Check(src.ptr()) != 0)) {
auto tmp = reinterpret_steal<object>(std::is_floating_point<T>::value
......@@ -182,32 +193,40 @@ public:
return true;
}
template<typename U = T>
template <typename U = T>
static typename std::enable_if<std::is_floating_point<U>::value, handle>::type
cast(U src, return_value_policy /* policy */, handle /* parent */) {
return PyFloat_FromDouble((double) src);
}
template<typename U = T>
static typename std::enable_if<!std::is_floating_point<U>::value && std::is_signed<U>::value && (sizeof(U) <= sizeof(long)), handle>::type
template <typename U = T>
static typename std::enable_if<!std::is_floating_point<U>::value && std::is_signed<U>::value
&& (sizeof(U) <= sizeof(long)),
handle>::type
cast(U src, return_value_policy /* policy */, handle /* parent */) {
return PYBIND11_LONG_FROM_SIGNED((long) src);
}
template<typename U = T>
static typename std::enable_if<!std::is_floating_point<U>::value && std::is_unsigned<U>::value && (sizeof(U) <= sizeof(unsigned long)), handle>::type
template <typename U = T>
static typename std::enable_if<!std::is_floating_point<U>::value && std::is_unsigned<U>::value
&& (sizeof(U) <= sizeof(unsigned long)),
handle>::type
cast(U src, return_value_policy /* policy */, handle /* parent */) {
return PYBIND11_LONG_FROM_UNSIGNED((unsigned long) src);
}
template<typename U = T>
static typename std::enable_if<!std::is_floating_point<U>::value && std::is_signed<U>::value && (sizeof(U) > sizeof(long)), handle>::type
template <typename U = T>
static typename std::enable_if<!std::is_floating_point<U>::value && std::is_signed<U>::value
&& (sizeof(U) > sizeof(long)),
handle>::type
cast(U src, return_value_policy /* policy */, handle /* parent */) {
return PyLong_FromLongLong((long long) src);
}
template<typename U = T>
static typename std::enable_if<!std::is_floating_point<U>::value && std::is_unsigned<U>::value && (sizeof(U) > sizeof(unsigned long)), handle>::type
template <typename U = T>
static typename std::enable_if<!std::is_floating_point<U>::value && std::is_unsigned<U>::value
&& (sizeof(U) > sizeof(unsigned long)),
handle>::type
cast(U src, return_value_policy /* policy */, handle /* parent */) {
return PyLong_FromUnsignedLongLong((unsigned long long) src);
}
......@@ -215,7 +234,8 @@ public:
PYBIND11_TYPE_CASTER(T, const_name<std::is_integral<T>::value>("int", "float"));
};
template<typename T> struct void_caster {
template <typename T>
struct void_caster {
public:
bool load(handle src, bool) {
if (src && src.is_none()) {
......@@ -229,9 +249,11 @@ public:
PYBIND11_TYPE_CASTER(T, const_name("None"));
};
template <> class type_caster<void_type> : public void_caster<void_type> {};
template <>
class type_caster<void_type> : public void_caster<void_type> {};
template <> class type_caster<void> : public type_caster<void_type> {
template <>
class type_caster<void> : public type_caster<void_type> {
public:
using type_caster<void_type>::cast;
......@@ -268,16 +290,20 @@ public:
return none().inc_ref();
}
template <typename T> using cast_op_type = void*&;
template <typename T>
using cast_op_type = void *&;
explicit operator void *&() { return value; }
static constexpr auto name = const_name("capsule");
private:
void *value = nullptr;
};
template <> class type_caster<std::nullptr_t> : public void_caster<std::nullptr_t> { };
template <>
class type_caster<std::nullptr_t> : public void_caster<std::nullptr_t> {};
template <> class type_caster<bool> {
template <>
class type_caster<bool> {
public:
bool load(handle src, bool convert) {
if (!src) {
......@@ -298,12 +324,12 @@ public:
if (src.is_none()) {
res = 0; // None is implicitly converted to False
}
#if defined(PYPY_VERSION)
#if defined(PYPY_VERSION)
// On PyPy, check that "__bool__" (or "__nonzero__" on Python 2.7) attr exists
else if (hasattr(src, PYBIND11_BOOL_ATTR)) {
res = PyObject_IsTrue(src.ptr());
}
#else
#else
// Alternate approach for CPython: this does the same as the above, but optimized
// using the CPython API so as to avoid an unneeded attribute lookup.
else if (auto *tp_as_number = src.ptr()->ob_type->tp_as_number) {
......@@ -311,7 +337,7 @@ public:
res = (*PYBIND11_NB_BOOL(tp_as_number))(src.ptr());
}
}
#endif
#endif
if (res == 0 || res == 1) {
value = (res != 0);
return true;
......@@ -327,17 +353,22 @@ public:
};
// Helper class for UTF-{8,16,32} C++ stl strings:
template <typename StringType, bool IsView = false> struct string_caster {
template <typename StringType, bool IsView = false>
struct string_caster {
using CharT = typename StringType::value_type;
// Simplify life by being able to assume standard char sizes (the standard only guarantees
// minimums, but Python requires exact sizes)
static_assert(!std::is_same<CharT, char>::value || sizeof(CharT) == 1, "Unsupported char size != 1");
static_assert(!std::is_same<CharT, char>::value || sizeof(CharT) == 1,
"Unsupported char size != 1");
#if defined(PYBIND11_HAS_U8STRING)
static_assert(!std::is_same<CharT, char8_t>::value || sizeof(CharT) == 1, "Unsupported char8_t size != 1");
static_assert(!std::is_same<CharT, char8_t>::value || sizeof(CharT) == 1,
"Unsupported char8_t size != 1");
#endif
static_assert(!std::is_same<CharT, char16_t>::value || sizeof(CharT) == 2, "Unsupported char16_t size != 2");
static_assert(!std::is_same<CharT, char32_t>::value || sizeof(CharT) == 4, "Unsupported char32_t size != 4");
static_assert(!std::is_same<CharT, char16_t>::value || sizeof(CharT) == 2,
"Unsupported char16_t size != 2");
static_assert(!std::is_same<CharT, char32_t>::value || sizeof(CharT) == 4,
"Unsupported char32_t size != 4");
// wchar_t can be either 16 bits (Windows) or 32 (everywhere else)
static_assert(!std::is_same<CharT, wchar_t>::value || sizeof(CharT) == 2 || sizeof(CharT) == 4,
"Unsupported wchar_t size != 2/4");
......@@ -364,7 +395,10 @@ template <typename StringType, bool IsView = false> struct string_caster {
return false;
temp = reinterpret_steal<object>(PyUnicode_FromObject(load_src.ptr()));
if (!temp) { PyErr_Clear(); return false; }
if (!temp) {
PyErr_Clear();
return false;
}
load_src = temp;
#endif
}
......@@ -385,11 +419,19 @@ template <typename StringType, bool IsView = false> struct string_caster {
}
#endif
auto utfNbytes = reinterpret_steal<object>(PyUnicode_AsEncodedString(
load_src.ptr(), UTF_N == 8 ? "utf-8" : UTF_N == 16 ? "utf-16" : "utf-32", nullptr));
if (!utfNbytes) { PyErr_Clear(); return false; }
auto utfNbytes
= reinterpret_steal<object>(PyUnicode_AsEncodedString(load_src.ptr(),
UTF_N == 8 ? "utf-8"
: UTF_N == 16 ? "utf-16"
: "utf-32",
nullptr));
if (!utfNbytes) {
PyErr_Clear();
return false;
}
const auto *buffer = reinterpret_cast<const CharT *>(PYBIND11_BYTES_AS_STRING(utfNbytes.ptr()));
const auto *buffer
= reinterpret_cast<const CharT *>(PYBIND11_BYTES_AS_STRING(utfNbytes.ptr()));
size_t length = (size_t) PYBIND11_BYTES_SIZE(utfNbytes.ptr()) / sizeof(CharT);
// Skip BOM for UTF-16/32
if (PYBIND11_SILENCE_MSVC_C4127(UTF_N > 8)) {
......@@ -406,7 +448,8 @@ template <typename StringType, bool IsView = false> struct string_caster {
return true;
}
static handle cast(const StringType &src, return_value_policy /* policy */, handle /* parent */) {
static handle
cast(const StringType &src, return_value_policy /* policy */, handle /* parent */) {
const char *buffer = reinterpret_cast<const char *>(src.data());
auto nbytes = ssize_t(src.size() * sizeof(CharT));
handle s = decode_utfN(buffer, nbytes);
......@@ -421,14 +464,19 @@ template <typename StringType, bool IsView = false> struct string_caster {
private:
static handle decode_utfN(const char *buffer, ssize_t nbytes) {
#if !defined(PYPY_VERSION)
return
UTF_N == 8 ? PyUnicode_DecodeUTF8(buffer, nbytes, nullptr) :
UTF_N == 16 ? PyUnicode_DecodeUTF16(buffer, nbytes, nullptr, nullptr) :
PyUnicode_DecodeUTF32(buffer, nbytes, nullptr, nullptr);
return UTF_N == 8 ? PyUnicode_DecodeUTF8(buffer, nbytes, nullptr)
: UTF_N == 16 ? PyUnicode_DecodeUTF16(buffer, nbytes, nullptr, nullptr)
: PyUnicode_DecodeUTF32(buffer, nbytes, nullptr, nullptr);
#else
// PyPy segfaults when on PyUnicode_DecodeUTF16 (and possibly on PyUnicode_DecodeUTF32 as well),
// so bypass the whole thing by just passing the encoding as a string value, which works properly:
return PyUnicode_Decode(buffer, nbytes, UTF_N == 8 ? "utf-8" : UTF_N == 16 ? "utf-16" : "utf-32", nullptr);
// PyPy segfaults when on PyUnicode_DecodeUTF16 (and possibly on PyUnicode_DecodeUTF32 as
// well), so bypass the whole thing by just passing the encoding as a string value, which
// works properly:
return PyUnicode_Decode(buffer,
nbytes,
UTF_N == 8 ? "utf-8"
: UTF_N == 16 ? "utf-16"
: "utf-32",
nullptr);
#endif
}
......@@ -451,27 +499,33 @@ private:
}
template <typename C = CharT>
bool load_bytes(enable_if_t<!std::is_same<C, char>::value, handle>) { return false; }
bool load_bytes(enable_if_t<!std::is_same<C, char>::value, handle>) {
return false;
}
};
template <typename CharT, class Traits, class Allocator>
struct type_caster<std::basic_string<CharT, Traits, Allocator>, enable_if_t<is_std_char_type<CharT>::value>>
struct type_caster<std::basic_string<CharT, Traits, Allocator>,
enable_if_t<is_std_char_type<CharT>::value>>
: string_caster<std::basic_string<CharT, Traits, Allocator>> {};
#ifdef PYBIND11_HAS_STRING_VIEW
template <typename CharT, class Traits>
struct type_caster<std::basic_string_view<CharT, Traits>, enable_if_t<is_std_char_type<CharT>::value>>
struct type_caster<std::basic_string_view<CharT, Traits>,
enable_if_t<is_std_char_type<CharT>::value>>
: string_caster<std::basic_string_view<CharT, Traits>, true> {};
#endif
// Type caster for C-style strings. We basically use a std::string type caster, but also add the
// ability to use None as a nullptr char* (which the string caster doesn't allow).
template <typename CharT> struct type_caster<CharT, enable_if_t<is_std_char_type<CharT>::value>> {
template <typename CharT>
struct type_caster<CharT, enable_if_t<is_std_char_type<CharT>::value>> {
using StringType = std::basic_string<CharT>;
using StringCaster = type_caster<StringType>;
StringCaster str_caster;
bool none = false;
CharT one_char = 0;
public:
bool load(handle src, bool convert) {
if (!src) {
......@@ -521,10 +575,10 @@ public:
}
// If we're in UTF-8 mode, we have two possible failures: one for a unicode character that
// is too high, and one for multiple unicode characters (caught later), so we need to figure
// out how long the first encoded character is in bytes to distinguish between these two
// errors. We also allow want to allow unicode characters U+0080 through U+00FF, as those
// can fit into a single char value.
// is too high, and one for multiple unicode characters (caught later), so we need to
// figure out how long the first encoded character is in bytes to distinguish between these
// two errors. We also allow want to allow unicode characters U+0080 through U+00FF, as
// those can fit into a single char value.
if (PYBIND11_SILENCE_MSVC_C4127(StringCaster::UTF_N == 8) && str_len > 1 && str_len <= 4) {
auto v0 = static_cast<unsigned char>(value[0]);
// low bits only: 0-127
......@@ -539,7 +593,8 @@ public:
if (char0_bytes == str_len) {
// If we have a 128-255 value, we can decode it into a single char:
if (char0_bytes == 2 && (v0 & 0xFC) == 0xC0) { // 0x110000xx 0x10xxxxxx
one_char = static_cast<CharT>(((v0 & 3) << 6) + (static_cast<unsigned char>(value[1]) & 0x3F));
one_char = static_cast<CharT>(((v0 & 3) << 6)
+ (static_cast<unsigned char>(value[1]) & 0x3F));
return one_char;
}
// Otherwise we have a single character, but it's > U+00FF
......@@ -566,16 +621,18 @@ public:
}
static constexpr auto name = const_name(PYBIND11_STRING_NAME);
template <typename _T> using cast_op_type = pybind11::detail::cast_op_type<_T>;
template <typename _T>
using cast_op_type = pybind11::detail::cast_op_type<_T>;
};
// Base implementation for std::tuple and std::pair
template <template<typename...> class Tuple, typename... Ts> class tuple_caster {
template <template <typename...> class Tuple, typename... Ts>
class tuple_caster {
using type = Tuple<Ts...>;
static constexpr auto size = sizeof...(Ts);
using indices = make_index_sequence<size>;
public:
public:
bool load(handle src, bool convert) {
if (!isinstance<sequence>(src)) {
return false;
......@@ -606,18 +663,24 @@ public:
return cast(*src, policy, parent);
}
static constexpr auto name = const_name("Tuple[") + concat(make_caster<Ts>::name...) + const_name("]");
static constexpr auto name
= const_name("Tuple[") + concat(make_caster<Ts>::name...) + const_name("]");
template <typename T> using cast_op_type = type;
template <typename T>
using cast_op_type = type;
explicit operator type() & { return implicit_cast(indices{}); }
explicit operator type() && { return std::move(*this).implicit_cast(indices{}); }
protected:
template <size_t... Is>
type implicit_cast(index_sequence<Is...>) & { return type(cast_op<Ts>(std::get<Is>(subcasters))...); }
type implicit_cast(index_sequence<Is...>) & {
return type(cast_op<Ts>(std::get<Is>(subcasters))...);
}
template <size_t... Is>
type implicit_cast(index_sequence<Is...>) && { return type(cast_op<Ts>(std::move(std::get<Is>(subcasters)))...); }
type implicit_cast(index_sequence<Is...>) && {
return type(cast_op<Ts>(std::move(std::get<Is>(subcasters)))...);
}
static constexpr bool load_impl(const sequence &, bool, index_sequence<>) { return true; }
......@@ -639,12 +702,12 @@ protected:
/* Implementation: Convert a C++ tuple into a Python tuple */
template <typename T, size_t... Is>
static handle cast_impl(T &&src, return_value_policy policy, handle parent, index_sequence<Is...>) {
static handle
cast_impl(T &&src, return_value_policy policy, handle parent, index_sequence<Is...>) {
PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(src, policy, parent);
PYBIND11_WORKAROUND_INCORRECT_GCC_UNUSED_BUT_SET_PARAMETER(policy, parent);
std::array<object, size> entries{{
reinterpret_steal<object>(make_caster<Ts>::cast(std::get<Is>(std::forward<T>(src)), policy, parent))...
}};
std::array<object, size> entries{{reinterpret_steal<object>(
make_caster<Ts>::cast(std::get<Is>(std::forward<T>(src)), policy, parent))...}};
for (const auto &entry : entries) {
if (!entry) {
return handle();
......@@ -661,11 +724,11 @@ protected:
Tuple<make_caster<Ts>...> subcasters;
};
template <typename T1, typename T2> class type_caster<std::pair<T1, T2>>
: public tuple_caster<std::pair, T1, T2> {};
template <typename T1, typename T2>
class type_caster<std::pair<T1, T2>> : public tuple_caster<std::pair, T1, T2> {};
template <typename... Ts> class type_caster<std::tuple<Ts...>>
: public tuple_caster<std::tuple, Ts...> {};
template <typename... Ts>
class type_caster<std::tuple<Ts...>> : public tuple_caster<std::tuple, Ts...> {};
/// Helper class which abstracts away certain actions. Users can provide specializations for
/// custom holders, but it's only necessary if the type has a non-standard interface.
......@@ -694,12 +757,12 @@ public:
return base::template load_impl<copyable_holder_caster<type, holder_type>>(src, convert);
}
explicit operator type*() { return this->value; }
explicit operator type *() { return this->value; }
// static_cast works around compiler error with MSVC 17 and CUDA 10.2
// see issue #2180
explicit operator type&() { return *(static_cast<type *>(this->value)); }
explicit operator holder_type*() { return std::addressof(holder); }
explicit operator holder_type&() { return holder; }
explicit operator type &() { return *(static_cast<type *>(this->value)); }
explicit operator holder_type *() { return std::addressof(holder); }
explicit operator holder_type &() { return holder; }
static handle cast(const holder_type &src, return_value_policy, handle) {
const auto *ptr = holder_helper<holder_type>::get(src);
......@@ -729,10 +792,14 @@ protected:
#endif
}
template <typename T = holder_type, detail::enable_if_t<!std::is_constructible<T, const T &, type*>::value, int> = 0>
bool try_implicit_casts(handle, bool) { return false; }
template <typename T = holder_type,
detail::enable_if_t<!std::is_constructible<T, const T &, type *>::value, int> = 0>
bool try_implicit_casts(handle, bool) {
return false;
}
template <typename T = holder_type, detail::enable_if_t<std::is_constructible<T, const T &, type*>::value, int> = 0>
template <typename T = holder_type,
detail::enable_if_t<std::is_constructible<T, const T &, type *>::value, int> = 0>
bool try_implicit_casts(handle src, bool convert) {
for (auto &cast : typeinfo->implicit_casts) {
copyable_holder_caster sub_caster(*cast.first);
......@@ -747,13 +814,12 @@ protected:
static bool try_direct_conversions(handle) { return false; }
holder_type holder;
};
/// Specialize for the common std::shared_ptr, so users don't need to
template <typename T>
class type_caster<std::shared_ptr<T>> : public copyable_holder_caster<T, std::shared_ptr<T>> { };
class type_caster<std::shared_ptr<T>> : public copyable_holder_caster<T, std::shared_ptr<T>> {};
/// Type caster for holder types like std::unique_ptr.
/// Please consider the SFINAE hook an implementation detail, as explained
......@@ -772,47 +838,87 @@ struct move_only_holder_caster {
template <typename type, typename deleter>
class type_caster<std::unique_ptr<type, deleter>>
: public move_only_holder_caster<type, std::unique_ptr<type, deleter>> { };
: public move_only_holder_caster<type, std::unique_ptr<type, deleter>> {};
template <typename type, typename holder_type>
using type_caster_holder = conditional_t<is_copy_constructible<holder_type>::value,
copyable_holder_caster<type, holder_type>,
move_only_holder_caster<type, holder_type>>;
template <typename T, bool Value = false> struct always_construct_holder { static constexpr bool value = Value; };
template <typename T, bool Value = false>
struct always_construct_holder {
static constexpr bool value = Value;
};
/// Create a specialization for custom holder types (silently ignores std::shared_ptr)
#define PYBIND11_DECLARE_HOLDER_TYPE(type, holder_type, ...) \
namespace pybind11 { namespace detail { \
namespace pybind11 { \
namespace detail { \
template <typename type> \
struct always_construct_holder<holder_type> : always_construct_holder<void, ##__VA_ARGS__> { }; \
struct always_construct_holder<holder_type> : always_construct_holder<void, ##__VA_ARGS__> { \
}; \
template <typename type> \
class type_caster<holder_type, enable_if_t<!is_shared_ptr<holder_type>::value>> \
: public type_caster_holder<type, holder_type> { }; \
}}
: public type_caster_holder<type, holder_type> {}; \
} \
}
// PYBIND11_DECLARE_HOLDER_TYPE holder types:
template <typename base, typename holder> struct is_holder_type :
std::is_base_of<detail::type_caster_holder<base, holder>, detail::type_caster<holder>> {};
template <typename base, typename holder>
struct is_holder_type
: std::is_base_of<detail::type_caster_holder<base, holder>, detail::type_caster<holder>> {};
// Specialization for always-supported unique_ptr holders:
template <typename base, typename deleter> struct is_holder_type<base, std::unique_ptr<base, deleter>> :
std::true_type {};
template <typename T> struct handle_type_name { static constexpr auto name = const_name<T>(); };
template <> struct handle_type_name<bool_> { static constexpr auto name = const_name("bool"); };
template <> struct handle_type_name<bytes> { static constexpr auto name = const_name(PYBIND11_BYTES_NAME); };
template <> struct handle_type_name<int_> { static constexpr auto name = const_name("int"); };
template <> struct handle_type_name<iterable> { static constexpr auto name = const_name("Iterable"); };
template <> struct handle_type_name<iterator> { static constexpr auto name = const_name("Iterator"); };
template <> struct handle_type_name<float_> { static constexpr auto name = const_name("float"); };
template <> struct handle_type_name<none> { static constexpr auto name = const_name("None"); };
template <> struct handle_type_name<args> { static constexpr auto name = const_name("*args"); };
template <> struct handle_type_name<kwargs> { static constexpr auto name = const_name("**kwargs"); };
template <typename base, typename deleter>
struct is_holder_type<base, std::unique_ptr<base, deleter>> : std::true_type {};
template <typename T>
struct handle_type_name {
static constexpr auto name = const_name<T>();
};
template <>
struct handle_type_name<bool_> {
static constexpr auto name = const_name("bool");
};
template <>
struct handle_type_name<bytes> {
static constexpr auto name = const_name(PYBIND11_BYTES_NAME);
};
template <>
struct handle_type_name<int_> {
static constexpr auto name = const_name("int");
};
template <>
struct handle_type_name<iterable> {
static constexpr auto name = const_name("Iterable");
};
template <>
struct handle_type_name<iterator> {
static constexpr auto name = const_name("Iterator");
};
template <>
struct handle_type_name<float_> {
static constexpr auto name = const_name("float");
};
template <>
struct handle_type_name<none> {
static constexpr auto name = const_name("None");
};
template <>
struct handle_type_name<args> {
static constexpr auto name = const_name("*args");
};
template <>
struct handle_type_name<kwargs> {
static constexpr auto name = const_name("**kwargs");
};
template <typename type>
struct pyobject_caster {
template <typename T = type, enable_if_t<std::is_same<T, handle>::value, int> = 0>
bool load(handle src, bool /* convert */) { value = src; return static_cast<bool>(value); }
bool load(handle src, bool /* convert */) {
value = src;
return static_cast<bool>(value);
}
template <typename T = type, enable_if_t<std::is_base_of<object, T>::value, int> = 0>
bool load(handle src, bool /* convert */) {
......@@ -822,7 +928,8 @@ struct pyobject_caster {
// un-cluttered later after Python 2 support is dropped.
if (PYBIND11_SILENCE_MSVC_C4127(std::is_same<T, str>::value) && isinstance<bytes>(src)) {
PyObject *str_from_bytes = PyUnicode_FromEncodedObject(src.ptr(), "utf-8", nullptr);
if (!str_from_bytes) throw error_already_set();
if (!str_from_bytes)
throw error_already_set();
value = reinterpret_steal<type>(str_from_bytes);
return true;
}
......@@ -841,7 +948,7 @@ struct pyobject_caster {
};
template <typename T>
class type_caster<T, enable_if_t<is_pyobject<T>::value>> : public pyobject_caster<T> { };
class type_caster<T, enable_if_t<is_pyobject<T>::value>> : public pyobject_caster<T> {};
// Our conditions for enabling moving are quite restrictive:
// At compile time:
......@@ -852,65 +959,81 @@ class type_caster<T, enable_if_t<is_pyobject<T>::value>> : public pyobject_caste
// - if the type is non-copy-constructible, the object must be the sole owner of the type (i.e. it
// must have ref_count() == 1)h
// If any of the above are not satisfied, we fall back to copying.
template <typename T> using move_is_plain_type = satisfies_none_of<T,
std::is_void, std::is_pointer, std::is_reference, std::is_const
>;
template <typename T, typename SFINAE = void> struct move_always : std::false_type {};
template <typename T> struct move_always<T, enable_if_t<all_of<
move_is_plain_type<T>,
template <typename T>
using move_is_plain_type
= satisfies_none_of<T, std::is_void, std::is_pointer, std::is_reference, std::is_const>;
template <typename T, typename SFINAE = void>
struct move_always : std::false_type {};
template <typename T>
struct move_always<
T,
enable_if_t<
all_of<move_is_plain_type<T>,
negation<is_copy_constructible<T>>,
std::is_move_constructible<T>,
std::is_same<decltype(std::declval<make_caster<T>>().operator T&()), T&>
>::value>> : std::true_type {};
template <typename T, typename SFINAE = void> struct move_if_unreferenced : std::false_type {};
template <typename T> struct move_if_unreferenced<T, enable_if_t<all_of<
move_is_plain_type<T>,
std::is_same<decltype(std::declval<make_caster<T>>().operator T &()), T &>>::value>>
: std::true_type {};
template <typename T, typename SFINAE = void>
struct move_if_unreferenced : std::false_type {};
template <typename T>
struct move_if_unreferenced<
T,
enable_if_t<
all_of<move_is_plain_type<T>,
negation<move_always<T>>,
std::is_move_constructible<T>,
std::is_same<decltype(std::declval<make_caster<T>>().operator T&()), T&>
>::value>> : std::true_type {};
template <typename T> using move_never = none_of<move_always<T>, move_if_unreferenced<T>>;
std::is_same<decltype(std::declval<make_caster<T>>().operator T &()), T &>>::value>>
: std::true_type {};
template <typename T>
using move_never = none_of<move_always<T>, move_if_unreferenced<T>>;
// Detect whether returning a `type` from a cast on type's type_caster is going to result in a
// reference or pointer to a local variable of the type_caster. Basically, only
// non-reference/pointer `type`s and reference/pointers from a type_caster_generic are safe;
// everything else returns a reference/pointer to a local variable.
template <typename type> using cast_is_temporary_value_reference = bool_constant<
(std::is_reference<type>::value || std::is_pointer<type>::value) &&
!std::is_base_of<type_caster_generic, make_caster<type>>::value &&
!std::is_same<intrinsic_t<type>, void>::value
>;
template <typename type>
using cast_is_temporary_value_reference
= bool_constant<(std::is_reference<type>::value || std::is_pointer<type>::value)
&& !std::is_base_of<type_caster_generic, make_caster<type>>::value
&& !std::is_same<intrinsic_t<type>, void>::value>;
// When a value returned from a C++ function is being cast back to Python, we almost always want to
// force `policy = move`, regardless of the return value policy the function/method was declared
// with.
template <typename Return, typename SFINAE = void> struct return_value_policy_override {
template <typename Return, typename SFINAE = void>
struct return_value_policy_override {
static return_value_policy policy(return_value_policy p) { return p; }
};
template <typename Return> struct return_value_policy_override<Return,
template <typename Return>
struct return_value_policy_override<
Return,
detail::enable_if_t<std::is_base_of<type_caster_generic, make_caster<Return>>::value, void>> {
static return_value_policy policy(return_value_policy p) {
return !std::is_lvalue_reference<Return>::value &&
!std::is_pointer<Return>::value
? return_value_policy::move : p;
return !std::is_lvalue_reference<Return>::value && !std::is_pointer<Return>::value
? return_value_policy::move
: p;
}
};
// Basic python -> C++ casting; throws if casting fails
template <typename T, typename SFINAE> type_caster<T, SFINAE> &load_type(type_caster<T, SFINAE> &conv, const handle &handle) {
template <typename T, typename SFINAE>
type_caster<T, SFINAE> &load_type(type_caster<T, SFINAE> &conv, const handle &handle) {
if (!conv.load(handle, true)) {
#if defined(NDEBUG)
throw cast_error("Unable to cast Python instance to C++ type (compile in debug mode for details)");
throw cast_error(
"Unable to cast Python instance to C++ type (compile in debug mode for details)");
#else
throw cast_error("Unable to cast Python instance of type " +
(std::string) str(type::handle_of(handle)) + " to C++ type '" + type_id<T>() + "'");
throw cast_error("Unable to cast Python instance of type "
+ (std::string) str(type::handle_of(handle)) + " to C++ type '"
+ type_id<T>() + "'");
#endif
}
return conv;
}
// Wrapper around the above that also constructs and returns a type_caster
template <typename T> make_caster<T> load_type(const handle &handle) {
template <typename T>
make_caster<T> load_type(const handle &handle) {
make_caster<T> conv;
load_type(conv, handle);
return conv;
......@@ -929,41 +1052,54 @@ T cast(const handle &handle) {
// pytype -> pytype (calls converting constructor)
template <typename T, detail::enable_if_t<detail::is_pyobject<T>::value, int> = 0>
T cast(const handle &handle) { return T(reinterpret_borrow<object>(handle)); }
T cast(const handle &handle) {
return T(reinterpret_borrow<object>(handle));
}
// C++ type -> py::object
template <typename T, detail::enable_if_t<!detail::is_pyobject<T>::value, int> = 0>
object cast(T &&value, return_value_policy policy = return_value_policy::automatic_reference,
object cast(T &&value,
return_value_policy policy = return_value_policy::automatic_reference,
handle parent = handle()) {
using no_ref_T = typename std::remove_reference<T>::type;
if (policy == return_value_policy::automatic) {
policy = std::is_pointer<no_ref_T>::value ? return_value_policy::take_ownership :
std::is_lvalue_reference<T>::value ? return_value_policy::copy : return_value_policy::move;
policy = std::is_pointer<no_ref_T>::value ? return_value_policy::take_ownership
: std::is_lvalue_reference<T>::value ? return_value_policy::copy
: return_value_policy::move;
} else if (policy == return_value_policy::automatic_reference) {
policy = std::is_pointer<no_ref_T>::value ? return_value_policy::reference
: std::is_lvalue_reference<T>::value ? return_value_policy::copy
: return_value_policy::move;
}
return reinterpret_steal<object>(detail::make_caster<T>::cast(std::forward<T>(value), policy, parent));
return reinterpret_steal<object>(
detail::make_caster<T>::cast(std::forward<T>(value), policy, parent));
}
template <typename T> T handle::cast() const { return pybind11::cast<T>(*this); }
template <> inline void handle::cast() const { return; }
template <typename T>
T handle::cast() const {
return pybind11::cast<T>(*this);
}
template <>
inline void handle::cast() const {
return;
}
template <typename T>
detail::enable_if_t<!detail::move_never<T>::value, T> move(object &&obj) {
if (obj.ref_count() > 1) {
#if defined(NDEBUG)
throw cast_error("Unable to cast Python instance to C++ rvalue: instance has multiple references"
throw cast_error(
"Unable to cast Python instance to C++ rvalue: instance has multiple references"
" (compile in debug mode for details)");
#else
throw cast_error("Unable to move from Python " + (std::string) str(type::handle_of(obj)) +
" instance to C++ " + type_id<T>() + " instance: instance has multiple references");
throw cast_error("Unable to move from Python " + (std::string) str(type::handle_of(obj))
+ " instance to C++ " + type_id<T>()
+ " instance: instance has multiple references");
#endif
}
// Move into a temporary and return that, because the reference may be a local value of `conv`
T ret = std::move(detail::load_type<T>(obj).operator T&());
T ret = std::move(detail::load_type<T>(obj).operator T &());
return ret;
}
......@@ -972,52 +1108,81 @@ detail::enable_if_t<!detail::move_never<T>::value, T> move(object &&obj) {
// object has multiple references, but trying to copy will fail to compile.
// - If both movable and copyable, check ref count: if 1, move; otherwise copy
// - Otherwise (not movable), copy.
template <typename T> detail::enable_if_t<detail::move_always<T>::value, T> cast(object &&object) {
template <typename T>
detail::enable_if_t<detail::move_always<T>::value, T> cast(object &&object) {
return move<T>(std::move(object));
}
template <typename T> detail::enable_if_t<detail::move_if_unreferenced<T>::value, T> cast(object &&object) {
template <typename T>
detail::enable_if_t<detail::move_if_unreferenced<T>::value, T> cast(object &&object) {
if (object.ref_count() > 1) {
return cast<T>(object);
}
return move<T>(std::move(object));
}
template <typename T> detail::enable_if_t<detail::move_never<T>::value, T> cast(object &&object) {
template <typename T>
detail::enable_if_t<detail::move_never<T>::value, T> cast(object &&object) {
return cast<T>(object);
}
template <typename T> T object::cast() const & { return pybind11::cast<T>(*this); }
template <typename T> T object::cast() && { return pybind11::cast<T>(std::move(*this)); }
template <> inline void object::cast() const & { return; }
template <> inline void object::cast() && { return; }
template <typename T>
T object::cast() const & {
return pybind11::cast<T>(*this);
}
template <typename T>
T object::cast() && {
return pybind11::cast<T>(std::move(*this));
}
template <>
inline void object::cast() const & {
return;
}
template <>
inline void object::cast() && {
return;
}
PYBIND11_NAMESPACE_BEGIN(detail)
// Declared in pytypes.h:
template <typename T, enable_if_t<!is_pyobject<T>::value, int>>
object object_or_cast(T &&o) { return pybind11::cast(std::forward<T>(o)); }
object object_or_cast(T &&o) {
return pybind11::cast(std::forward<T>(o));
}
// Placeholder type for the unneeded (and dead code) static variable in the
// PYBIND11_OVERRIDE_OVERRIDE macro
struct override_unused {};
template <typename ret_type> using override_caster_t = conditional_t<
cast_is_temporary_value_reference<ret_type>::value, make_caster<ret_type>, override_unused>;
template <typename ret_type>
using override_caster_t = conditional_t<cast_is_temporary_value_reference<ret_type>::value,
make_caster<ret_type>,
override_unused>;
// Trampoline use: for reference/pointer types to value-converted values, we do a value cast, then
// store the result in the given variable. For other types, this is a no-op.
template <typename T> enable_if_t<cast_is_temporary_value_reference<T>::value, T> cast_ref(object &&o, make_caster<T> &caster) {
template <typename T>
enable_if_t<cast_is_temporary_value_reference<T>::value, T> cast_ref(object &&o,
make_caster<T> &caster) {
return cast_op<T>(load_type(caster, o));
}
template <typename T> enable_if_t<!cast_is_temporary_value_reference<T>::value, T> cast_ref(object &&, override_unused &) {
pybind11_fail("Internal error: cast_ref fallback invoked"); }
// Trampoline use: Having a pybind11::cast with an invalid reference type is going to static_assert, even
// though if it's in dead code, so we provide a "trampoline" to pybind11::cast that only does anything in
// cases where pybind11::cast is valid.
template <typename T> enable_if_t<!cast_is_temporary_value_reference<T>::value, T> cast_safe(object &&o) {
return pybind11::cast<T>(std::move(o)); }
template <typename T> enable_if_t<cast_is_temporary_value_reference<T>::value, T> cast_safe(object &&) {
pybind11_fail("Internal error: cast_safe fallback invoked"); }
template <> inline void cast_safe<void>(object &&) {}
template <typename T>
enable_if_t<!cast_is_temporary_value_reference<T>::value, T> cast_ref(object &&,
override_unused &) {
pybind11_fail("Internal error: cast_ref fallback invoked");
}
// Trampoline use: Having a pybind11::cast with an invalid reference type is going to
// static_assert, even though if it's in dead code, so we provide a "trampoline" to pybind11::cast
// that only does anything in cases where pybind11::cast is valid.
template <typename T>
enable_if_t<!cast_is_temporary_value_reference<T>::value, T> cast_safe(object &&o) {
return pybind11::cast<T>(std::move(o));
}
template <typename T>
enable_if_t<cast_is_temporary_value_reference<T>::value, T> cast_safe(object &&) {
pybind11_fail("Internal error: cast_safe fallback invoked");
}
template <>
inline void cast_safe<void>(object &&) {}
PYBIND11_NAMESPACE_END(detail)
......@@ -1037,21 +1202,21 @@ inline cast_error cast_error_unable_to_convert_call_arg(const std::string &name,
#endif
template <return_value_policy policy = return_value_policy::automatic_reference>
tuple make_tuple() { return tuple(0); }
tuple make_tuple() {
return tuple(0);
}
template <return_value_policy policy = return_value_policy::automatic_reference,
typename... Args> tuple make_tuple(Args&&... args_) {
template <return_value_policy policy = return_value_policy::automatic_reference, typename... Args>
tuple make_tuple(Args &&...args_) {
constexpr size_t size = sizeof...(Args);
std::array<object, size> args {
{ reinterpret_steal<object>(detail::make_caster<Args>::cast(
std::forward<Args>(args_), policy, nullptr))... }
};
std::array<object, size> args{{reinterpret_steal<object>(
detail::make_caster<Args>::cast(std::forward<Args>(args_), policy, nullptr))...}};
for (size_t i = 0; i < args.size(); i++) {
if (!args[i]) {
#if defined(NDEBUG)
throw cast_error_unable_to_convert_call_arg();
#else
std::array<std::string, size> argtypes { {type_id<Args>()...} };
std::array<std::string, size> argtypes{{type_id<Args>()...}};
throw cast_error_unable_to_convert_call_arg(std::to_string(i), argtypes[i]);
#endif
}
......@@ -1067,17 +1232,27 @@ template <return_value_policy policy = return_value_policy::automatic_reference,
/// \ingroup annotations
/// Annotation for arguments
struct arg {
/// Constructs an argument with the name of the argument; if null or omitted, this is a positional argument.
constexpr explicit arg(const char *name = nullptr) : name(name), flag_noconvert(false), flag_none(true) { }
/// Constructs an argument with the name of the argument; if null or omitted, this is a
/// positional argument.
constexpr explicit arg(const char *name = nullptr)
: name(name), flag_noconvert(false), flag_none(true) {}
/// Assign a value to this argument
template <typename T> arg_v operator=(T &&value) const;
template <typename T>
arg_v operator=(T &&value) const;
/// Indicate that the type should not be converted in the type caster
arg &noconvert(bool flag = true) { flag_noconvert = flag; return *this; }
arg &noconvert(bool flag = true) {
flag_noconvert = flag;
return *this;
}
/// Indicates that the argument should/shouldn't allow None (e.g. for nullable pointer args)
arg &none(bool flag = true) { flag_none = flag; return *this; }
arg &none(bool flag = true) {
flag_none = flag;
return *this;
}
const char *name; ///< If non-null, this is a named kwargs argument
bool flag_noconvert : 1; ///< If set, do not allow conversion (requires a supporting type caster!)
bool flag_noconvert : 1; ///< If set, do not allow conversion (requires a supporting type
///< caster!)
bool flag_none : 1; ///< If set (the default), allow None to be passed to this argument
};
......@@ -1087,13 +1262,12 @@ struct arg_v : arg {
private:
template <typename T>
arg_v(arg &&base, T &&x, const char *descr = nullptr)
: arg(base),
value(reinterpret_steal<object>(
detail::make_caster<T>::cast(x, return_value_policy::automatic, {})
)),
: arg(base), value(reinterpret_steal<object>(
detail::make_caster<T>::cast(x, return_value_policy::automatic, {}))),
descr(descr)
#if !defined(NDEBUG)
, type(type_id<T>())
,
type(type_id<T>())
#endif
{
// Workaround! See:
......@@ -1108,18 +1282,24 @@ public:
/// Direct construction with name, default, and description
template <typename T>
arg_v(const char *name, T &&x, const char *descr = nullptr)
: arg_v(arg(name), std::forward<T>(x), descr) { }
: arg_v(arg(name), std::forward<T>(x), descr) {}
/// Called internally when invoking `py::arg("a") = value`
template <typename T>
arg_v(const arg &base, T &&x, const char *descr = nullptr)
: arg_v(arg(base), std::forward<T>(x), descr) { }
: arg_v(arg(base), std::forward<T>(x), descr) {}
/// Same as `arg::noconvert()`, but returns *this as arg_v&, not arg&
arg_v &noconvert(bool flag = true) { arg::noconvert(flag); return *this; }
arg_v &noconvert(bool flag = true) {
arg::noconvert(flag);
return *this;
}
/// Same as `arg::nonone()`, but returns *this as arg_v&, not arg&
arg_v &none(bool flag = true) { arg::none(flag); return *this; }
arg_v &none(bool flag = true) {
arg::none(flag);
return *this;
}
/// The default value
object value;
......@@ -1132,13 +1312,13 @@ public:
};
/// \ingroup annotations
/// Annotation indicating that all following arguments are keyword-only; the is the equivalent of an
/// unnamed '*' argument (in Python 3)
/// Annotation indicating that all following arguments are keyword-only; the is the equivalent of
/// an unnamed '*' argument (in Python 3)
struct kw_only {};
/// \ingroup annotations
/// Annotation indicating that all previous arguments are positional-only; the is the equivalent of an
/// unnamed '/' argument (in Python 3.8)
/// Annotation indicating that all previous arguments are positional-only; the is the equivalent of
/// an unnamed '/' argument (in Python 3.8)
struct pos_only {};
template <typename T>
......@@ -1147,7 +1327,8 @@ arg_v arg::operator=(T &&value) const {
}
/// Alias for backward compatibility -- to be removed in version 2.0
template <typename /*unused*/> using arg_t = arg_v;
template <typename /*unused*/>
using arg_t = arg_v;
inline namespace literals {
/** \rst
......@@ -1158,8 +1339,10 @@ constexpr arg operator"" _a(const char *name, size_t) { return arg(name); }
PYBIND11_NAMESPACE_BEGIN(detail)
template <typename T> using is_kw_only = std::is_same<intrinsic_t<T>, kw_only>;
template <typename T> using is_pos_only = std::is_same<intrinsic_t<T>, pos_only>;
template <typename T>
using is_kw_only = std::is_same<intrinsic_t<T>, kw_only>;
template <typename T>
using is_pos_only = std::is_same<intrinsic_t<T>, pos_only>;
// forward declaration (definition in attr.h)
struct function_record;
......@@ -1188,18 +1371,20 @@ struct function_call {
handle init_self;
};
/// Helper class which loads arguments for C++ functions called from Python
template <typename... Args>
class argument_loader {
using indices = make_index_sequence<sizeof...(Args)>;
template <typename Arg> using argument_is_args = std::is_same<intrinsic_t<Arg>, args>;
template <typename Arg> using argument_is_kwargs = std::is_same<intrinsic_t<Arg>, kwargs>;
template <typename Arg>
using argument_is_args = std::is_same<intrinsic_t<Arg>, args>;
template <typename Arg>
using argument_is_kwargs = std::is_same<intrinsic_t<Arg>, kwargs>;
// Get kwargs argument position, or -1 if not present:
static constexpr auto kwargs_pos = constexpr_last<argument_is_kwargs, Args...>();
static_assert(kwargs_pos == -1 || kwargs_pos == (int) sizeof...(Args) - 1, "py::kwargs is only permitted as the last argument of a function");
static_assert(kwargs_pos == -1 || kwargs_pos == (int) sizeof...(Args) - 1,
"py::kwargs is only permitted as the last argument of a function");
public:
static constexpr bool has_kwargs = kwargs_pos != -1;
......@@ -1207,28 +1392,28 @@ public:
// py::args argument position; -1 if not present.
static constexpr int args_pos = constexpr_last<argument_is_args, Args...>();
static_assert(args_pos == -1 || args_pos == constexpr_first<argument_is_args, Args...>(), "py::args cannot be specified more than once");
static_assert(args_pos == -1 || args_pos == constexpr_first<argument_is_args, Args...>(),
"py::args cannot be specified more than once");
static constexpr auto arg_names = concat(type_descr(make_caster<Args>::name)...);
bool load_args(function_call &call) {
return load_impl_sequence(call, indices{});
}
bool load_args(function_call &call) { return load_impl_sequence(call, indices{}); }
template <typename Return, typename Guard, typename Func>
// NOLINTNEXTLINE(readability-const-return-type)
enable_if_t<!std::is_void<Return>::value, Return> call(Func &&f) && {
return std::move(*this).template call_impl<remove_cv_t<Return>>(std::forward<Func>(f), indices{}, Guard{});
return std::move(*this).template call_impl<remove_cv_t<Return>>(
std::forward<Func>(f), indices{}, Guard{});
}
template <typename Return, typename Guard, typename Func>
enable_if_t<std::is_void<Return>::value, void_type> call(Func &&f) && {
std::move(*this).template call_impl<remove_cv_t<Return>>(std::forward<Func>(f), indices{}, Guard{});
std::move(*this).template call_impl<remove_cv_t<Return>>(
std::forward<Func>(f), indices{}, Guard{});
return void_type();
}
private:
static bool load_impl_sequence(function_call &, index_sequence<>) { return true; }
template <size_t... Is>
......@@ -1262,7 +1447,7 @@ class simple_collector {
public:
template <typename... Ts>
explicit simple_collector(Ts &&...values)
: m_args(pybind11::make_tuple<policy>(std::forward<Ts>(values)...)) { }
: m_args(pybind11::make_tuple<policy>(std::forward<Ts>(values)...)) {}
const tuple &args() const & { return m_args; }
dict kwargs() const { return {}; }
......@@ -1315,13 +1500,14 @@ public:
private:
template <typename T>
void process(list &args_list, T &&x) {
auto o = reinterpret_steal<object>(detail::make_caster<T>::cast(std::forward<T>(x), policy, {}));
auto o = reinterpret_steal<object>(
detail::make_caster<T>::cast(std::forward<T>(x), policy, {}));
if (!o) {
#if defined(NDEBUG)
throw cast_error_unable_to_convert_call_arg();
#else
throw cast_error_unable_to_convert_call_arg(
std::to_string(args_list.size()), type_id<T>());
throw cast_error_unable_to_convert_call_arg(std::to_string(args_list.size()),
type_id<T>());
#endif
}
args_list.append(o);
......@@ -1333,7 +1519,7 @@ private:
}
}
void process(list &/*args_list*/, arg_v a) {
void process(list & /*args_list*/, arg_v a) {
if (!a.name) {
#if defined(NDEBUG)
nameless_argument_error();
......@@ -1358,7 +1544,7 @@ private:
m_kwargs[a.name] = a.value;
}
void process(list &/*args_list*/, detail::kwargs_proxy kp) {
void process(list & /*args_list*/, detail::kwargs_proxy kp) {
if (!kp) {
return;
}
......@@ -1380,7 +1566,8 @@ private:
"(compile in debug mode for details)");
}
[[noreturn]] static void nameless_argument_error(const std::string &type) {
throw type_error("Got kwargs without a name of type '" + type + "'; only named "
throw type_error("Got kwargs without a name of type '" + type
+ "'; only named "
"arguments may be passed via py::arg() to a python function call. ");
}
[[noreturn]] static void multiple_values_error() {
......@@ -1402,29 +1589,30 @@ private:
// fails to compile enable_if_t<!all_of<is_positional<Args>...>::value>
// (tested with ICC 2021.1 Beta 20200827).
template <typename... Args>
constexpr bool args_are_all_positional()
{
constexpr bool args_are_all_positional() {
return all_of<is_positional<Args>...>::value;
}
/// Collect only positional arguments for a Python function call
template <return_value_policy policy, typename... Args,
template <return_value_policy policy,
typename... Args,
typename = enable_if_t<args_are_all_positional<Args...>()>>
simple_collector<policy> collect_arguments(Args &&...args) {
return simple_collector<policy>(std::forward<Args>(args)...);
}
/// Collect all arguments, including keywords and unpacking (only instantiated when needed)
template <return_value_policy policy, typename... Args,
template <return_value_policy policy,
typename... Args,
typename = enable_if_t<!args_are_all_positional<Args...>()>>
unpacking_collector<policy> collect_arguments(Args &&...args) {
// Following argument order rules for generalized unpacking according to PEP 448
static_assert(
constexpr_last<is_positional, Args...>() < constexpr_first<is_keyword_or_ds, Args...>()
&& constexpr_last<is_s_unpacking, Args...>() < constexpr_first<is_ds_unpacking, Args...>(),
static_assert(constexpr_last<is_positional, Args...>()
< constexpr_first<is_keyword_or_ds, Args...>()
&& constexpr_last<is_s_unpacking, Args...>()
< constexpr_first<is_ds_unpacking, Args...>(),
"Invalid function call: positional args must precede keywords and ** unpacking; "
"* unpacking must precede ** unpacking"
);
"* unpacking must precede ** unpacking");
return unpacking_collector<policy>(std::forward<Args>(args)...);
}
......@@ -1447,22 +1635,21 @@ object object_api<Derived>::call(Args &&...args) const {
PYBIND11_NAMESPACE_END(detail)
template<typename T>
template <typename T>
handle type::handle_of() {
static_assert(
std::is_base_of<detail::type_caster_generic, detail::make_caster<T>>::value,
"py::type::of<T> only supports the case where T is a registered C++ types."
);
static_assert(std::is_base_of<detail::type_caster_generic, detail::make_caster<T>>::value,
"py::type::of<T> only supports the case where T is a registered C++ types.");
return detail::get_type_handle(typeid(T), true);
}
#define PYBIND11_MAKE_OPAQUE(...) \
namespace pybind11 { namespace detail { \
template<> class type_caster<__VA_ARGS__> : public type_caster_base<__VA_ARGS__> { }; \
}}
namespace pybind11 { \
namespace detail { \
template <> \
class type_caster<__VA_ARGS__> : public type_caster_base<__VA_ARGS__> {}; \
} \
}
/// Lets you pass a type containing a `,` through a macro parameter without needing a separate
/// typedef, e.g.:
......
......@@ -15,25 +15,25 @@
#include <chrono>
#include <cmath>
#include <ctime>
#include <mutex>
#include <datetime.h>
#include <mutex>
// 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
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
PYBIND11_NAMESPACE_BEGIN(detail)
template <typename type> class duration_caster {
template <typename type>
class duration_caster {
public:
using rep = typename type::rep;
using period = typename type::period;
......@@ -45,7 +45,9 @@ public:
using namespace std::chrono;
// Lazy initialise the PyDateTime import
if (!PyDateTimeAPI) { PyDateTime_IMPORT; }
if (!PyDateTimeAPI) {
PyDateTime_IMPORT;
}
if (!src) {
return false;
......@@ -60,19 +62,23 @@ public:
}
// If invoked with a float we assume it is seconds and convert
if (PyFloat_Check(src.ptr())) {
value = type(duration_cast<duration<rep, period>>(duration<double>(PyFloat_AsDouble(src.ptr()))));
value = type(duration_cast<duration<rep, period>>(
duration<double>(PyFloat_AsDouble(src.ptr()))));
return true;
}
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) {
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) {
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();
}
......@@ -84,9 +90,12 @@ public:
auto d = get_duration(src);
// Lazy initialise the PyDateTime import
if (!PyDateTimeAPI) { PyDateTime_IMPORT; }
if (!PyDateTimeAPI) {
PyDateTime_IMPORT;
}
// Declare these special duration types so the conversions happen with the correct primitive types (int)
// 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>;
......@@ -118,14 +127,17 @@ inline std::tm *localtime_thread_safe(const std::time_t *time, std::tm *buf) {
}
// 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>> {
template <typename Duration>
class type_caster<std::chrono::time_point<std::chrono::system_clock, Duration>> {
public:
using type = std::chrono::time_point<std::chrono::system_clock, Duration>;
bool load(handle src, bool) {
using namespace std::chrono;
// Lazy initialise the PyDateTime import
if (!PyDateTimeAPI) { PyDateTime_IMPORT; }
if (!PyDateTimeAPI) {
PyDateTime_IMPORT;
}
if (!src) {
return false;
......@@ -169,14 +181,18 @@ public:
return true;
}
static handle cast(const std::chrono::time_point<std::chrono::system_clock, Duration> &src, return_value_policy /* policy */, handle /* parent */) {
static handle cast(const std::chrono::time_point<std::chrono::system_clock, Duration> &src,
return_value_policy /* policy */,
handle /* parent */) {
using namespace std::chrono;
// Lazy initialise the PyDateTime import
if (!PyDateTimeAPI) { PyDateTime_IMPORT; }
if (!PyDateTimeAPI) {
PyDateTime_IMPORT;
}
// Get out microseconds, and make sure they are positive, to avoid bug in eastern hemisphere time zones
// (cfr. https://github.com/pybind/pybind11/issues/2417)
// Get out microseconds, and make sure they are positive, to avoid bug in eastern
// hemisphere time zones (cfr. https://github.com/pybind/pybind11/issues/2417)
using us_t = duration<int, std::micro>;
auto us = duration_cast<us_t>(src.time_since_epoch() % seconds(1));
if (us.count() < 0) {
......@@ -184,9 +200,10 @@ public:
}
// Subtract microseconds BEFORE `system_clock::to_time_t`, because:
// > If std::time_t has lower precision, it is implementation-defined whether the value is rounded or truncated.
// (https://en.cppreference.com/w/cpp/chrono/system_clock/to_time_t)
std::time_t tt = system_clock::to_time_t(time_point_cast<system_clock::duration>(src - us));
// > If std::time_t has lower precision, it is implementation-defined whether the value is
// rounded or truncated. (https://en.cppreference.com/w/cpp/chrono/system_clock/to_time_t)
std::time_t tt
= system_clock::to_time_t(time_point_cast<system_clock::duration>(src - us));
std::tm localtime;
std::tm *localtime_ptr = localtime_thread_safe(&tt, &localtime);
......@@ -207,13 +224,13 @@ public:
// 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 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>> {};
PYBIND11_NAMESPACE_END(detail)
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
......@@ -10,6 +10,7 @@
#pragma once
#include "pybind11.h"
#include <complex>
/// glibc defines I as a macro which breaks things, e.g., boost template names
......@@ -19,27 +20,32 @@
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
template <typename T> struct format_descriptor<std::complex<T>, detail::enable_if_t<std::is_floating_point<T>::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 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
PYBIND11_NAMESPACE_BEGIN(detail)
template <typename T> struct is_fmt_numeric<std::complex<T>, detail::enable_if_t<std::is_floating_point<T>::value>> {
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>> {
template <typename T>
class type_caster<std::complex<T>> {
public:
bool load(handle src, bool convert) {
if (!src) {
......@@ -57,7 +63,8 @@ public:
return true;
}
static handle cast(const std::complex<T> &src, return_value_policy /* policy */, handle /* parent */) {
static handle
cast(const std::complex<T> &src, return_value_policy /* policy */, handle /* parent */) {
return PyComplex_FromDoubles((double) src.real(), (double) src.imag());
}
......
......@@ -21,7 +21,8 @@ PYBIND11_NAMESPACE_BEGIN(detail)
#else
// In pre-3.3 Python, we still set __qualname__ so that we can produce reliable function type
// signatures; in 3.3+ this macro expands to nothing:
# define PYBIND11_SET_OLDPY_QUALNAME(obj, nameobj) setattr((PyObject *) obj, "__qualname__", nameobj)
# define PYBIND11_SET_OLDPY_QUALNAME(obj, nameobj) \
setattr((PyObject *) obj, "__qualname__", nameobj)
#endif
inline std::string get_fully_qualified_tp_name(PyTypeObject *type) {
......@@ -71,9 +72,9 @@ inline PyTypeObject *make_static_property_type() {
}
heap_type->ht_name = name_obj.inc_ref().ptr();
#ifdef PYBIND11_BUILTIN_QUALNAME
# ifdef PYBIND11_BUILTIN_QUALNAME
heap_type->ht_qualname = name_obj.inc_ref().ptr();
#endif
# endif
auto *type = &heap_type->ht_type;
type->tp_name = name;
......@@ -107,8 +108,10 @@ inline PyTypeObject *make_static_property_type() {
def __set__(self, obj, value):
cls = obj if isinstance(obj, type) else type(obj)
property.__set__(self, cls, value)
)", Py_file_input, d.ptr(), d.ptr()
);
)",
Py_file_input,
d.ptr(),
d.ptr());
if (result == nullptr)
throw error_already_set();
Py_DECREF(result);
......@@ -121,7 +124,7 @@ inline PyTypeObject *make_static_property_type() {
By default, Python replaces the `static_property` itself, but for wrapped C++ types
we need to call `static_property.__set__()` in order to propagate the new value to
the underlying C++ data structure. */
extern "C" inline int pybind11_meta_setattro(PyObject* obj, PyObject* name, PyObject* value) {
extern "C" inline int pybind11_meta_setattro(PyObject *obj, PyObject *name, PyObject *value) {
// Use `_PyType_Lookup()` instead of `PyObject_GetAttr()` in order to get the raw
// descriptor (`property`) instead of calling `tp_descr_get` (`property.__get__()`).
PyObject *descr = _PyType_Lookup((PyTypeObject *) obj, name);
......@@ -184,7 +187,8 @@ extern "C" inline PyObject *pybind11_meta_call(PyObject *type, PyObject *args, P
// Ensure that the base __init__ function(s) were called
for (const auto &vh : values_and_holders(instance)) {
if (!vh.holder_constructed()) {
PyErr_Format(PyExc_TypeError, "%.200s.__init__() must be called when overriding __init__",
PyErr_Format(PyExc_TypeError,
"%.200s.__init__() must be called when overriding __init__",
get_fully_qualified_tp_name(vh.type->type).c_str());
Py_DECREF(self);
return nullptr;
......@@ -203,9 +207,8 @@ extern "C" inline void pybind11_meta_dealloc(PyObject *obj) {
// 1) be found in internals.registered_types_py
// 2) have exactly one associated `detail::type_info`
auto found_type = internals.registered_types_py.find(type);
if (found_type != internals.registered_types_py.end() &&
found_type->second.size() == 1 &&
found_type->second[0]->type == type) {
if (found_type != internals.registered_types_py.end() && found_type->second.size() == 1
&& found_type->second[0]->type == type) {
auto *tinfo = found_type->second[0];
auto tindex = std::type_index(*tinfo->cpptype);
......@@ -220,7 +223,7 @@ extern "C" inline void pybind11_meta_dealloc(PyObject *obj) {
// Actually just `std::erase_if`, but that's only available in C++20
auto &cache = internals.inactive_override_cache;
for (auto it = cache.begin(), last = cache.end(); it != last; ) {
for (auto it = cache.begin(), last = cache.end(); it != last;) {
if (it->first == (PyObject *) tinfo->type) {
it = cache.erase(it);
} else {
......@@ -237,7 +240,7 @@ extern "C" inline void pybind11_meta_dealloc(PyObject *obj) {
/** This metaclass is assigned by default to all pybind11 types and is required in order
for static properties to function correctly. Users may override this using `py::metaclass`.
Return value: New reference. */
inline PyTypeObject* make_default_metaclass() {
inline PyTypeObject *make_default_metaclass() {
constexpr auto *name = "pybind11_type";
auto name_obj = reinterpret_steal<object>(PYBIND11_FROM_STRING(name));
......@@ -281,8 +284,11 @@ inline PyTypeObject* make_default_metaclass() {
/// For multiple inheritance types we need to recursively register/deregister base pointers for any
/// base classes with pointers that are difference from the instance value pointer so that we can
/// correctly recognize an offset base class pointer. This calls a function with any offset base ptrs.
inline void traverse_offset_bases(void *valueptr, const detail::type_info *tinfo, instance *self,
/// correctly recognize an offset base class pointer. This calls a function with any offset base
/// ptrs.
inline void traverse_offset_bases(void *valueptr,
const detail::type_info *tinfo,
instance *self,
bool (*f)(void * /*parentptr*/, instance * /*self*/)) {
for (handle h : reinterpret_borrow<tuple>(tinfo->type->tp_bases)) {
if (auto *parent_tinfo = get_type_info((PyTypeObject *) h.ptr())) {
......@@ -331,13 +337,13 @@ inline bool deregister_instance(instance *self, void *valptr, const type_info *t
return ret;
}
/// Instance creation function for all pybind11 types. It allocates the internal instance layout for
/// holding C++ objects and holders. Allocation is done lazily (the first time the instance is cast
/// to a reference or pointer), and initialization is done by an `__init__` function.
/// Instance creation function for all pybind11 types. It allocates the internal instance layout
/// for holding C++ objects and holders. Allocation is done lazily (the first time the instance is
/// cast to a reference or pointer), and initialization is done by an `__init__` function.
inline PyObject *make_new_instance(PyTypeObject *type) {
#if defined(PYPY_VERSION)
// PyPy gets tp_basicsize wrong (issue 2482) under multiple inheritance when the first inherited
// object is a plain Python type (i.e. not derived from an extension type). Fix it.
// PyPy gets tp_basicsize wrong (issue 2482) under multiple inheritance when the first
// inherited object is a plain Python type (i.e. not derived from an extension type). Fix it.
ssize_t instance_size = static_cast<ssize_t>(sizeof(instance));
if (type->tp_basicsize < instance_size) {
type->tp_basicsize = instance_size;
......@@ -511,7 +517,8 @@ extern "C" inline PyObject *pybind11_get_dict(PyObject *self, void *) {
/// dynamic_attr: Support for `instance.__dict__ = dict()`.
extern "C" inline int pybind11_set_dict(PyObject *self, PyObject *new_dict, void *) {
if (!PyDict_Check(new_dict)) {
PyErr_Format(PyExc_TypeError, "__dict__ must be set to a dictionary, not a '%.200s'",
PyErr_Format(PyExc_TypeError,
"__dict__ must be set to a dictionary, not a '%.200s'",
get_fully_qualified_tp_name(Py_TYPE(new_dict)).c_str());
return -1;
}
......@@ -541,14 +548,13 @@ inline void enable_dynamic_attributes(PyHeapTypeObject *heap_type) {
auto *type = &heap_type->ht_type;
type->tp_flags |= Py_TPFLAGS_HAVE_GC;
type->tp_dictoffset = type->tp_basicsize; // place dict at the end
type->tp_basicsize += (ssize_t)sizeof(PyObject *); // and allocate enough space for it
type->tp_basicsize += (ssize_t) sizeof(PyObject *); // and allocate enough space for it
type->tp_traverse = pybind11_traverse;
type->tp_clear = pybind11_clear;
static PyGetSetDef getset[] = {
{const_cast<char*>("__dict__"), pybind11_get_dict, pybind11_set_dict, nullptr, nullptr},
{nullptr, nullptr, nullptr, nullptr, nullptr}
};
{const_cast<char *>("__dict__"), pybind11_get_dict, pybind11_set_dict, nullptr, nullptr},
{nullptr, nullptr, nullptr, nullptr, nullptr}};
type->tp_getset = getset;
}
......@@ -617,7 +623,7 @@ inline void enable_buffer_protocol(PyHeapTypeObject *heap_type) {
/** Create a brand new Python type according to the `type_record` specification.
Return value: New reference. */
inline PyObject* make_new_python_type(const type_record &rec) {
inline PyObject *make_new_python_type(const type_record &rec) {
auto name = reinterpret_steal<object>(PYBIND11_FROM_STRING(rec.name));
auto qualname = name;
......@@ -678,7 +684,7 @@ inline PyObject* make_new_python_type(const type_record &rec) {
auto *type = &heap_type->ht_type;
type->tp_name = full_name;
type->tp_doc = tp_doc;
type->tp_base = type_incref((PyTypeObject *)base);
type->tp_base = type_incref((PyTypeObject *) base);
type->tp_basicsize = static_cast<ssize_t>(sizeof(instance));
if (!bases.empty()) {
type->tp_bases = bases.release().ptr();
......
......@@ -21,8 +21,8 @@
#define PYBIND11_NAMESPACE_END(name) }
// Robust support for some features and loading modules compiled against different pybind versions
// requires forcing hidden visibility on pybind code, so we enforce this by setting the attribute on
// the main `pybind11` namespace.
// requires forcing hidden visibility on pybind code, so we enforce this by setting the attribute
// on the main `pybind11` namespace.
#if !defined(PYBIND11_NAMESPACE)
# ifdef __GNUG__
# define PYBIND11_NAMESPACE pybind11 __attribute__((visibility("hidden")))
......@@ -92,14 +92,15 @@
# if defined(WIN32) || defined(_WIN32)
# define PYBIND11_EXPORT __declspec(dllexport)
# else
# define PYBIND11_EXPORT __attribute__ ((visibility("default")))
# define PYBIND11_EXPORT __attribute__((visibility("default")))
# endif
#endif
#if !defined(PYBIND11_EXPORT_EXCEPTION)
# ifdef __MINGW32__
// workaround for:
// error: 'dllexport' implies default visibility, but xxx has already been declared with a different visibility
// error: 'dllexport' implies default visibility, but xxx has already been declared with a
// different visibility
# define PYBIND11_EXPORT_EXCEPTION
# else
# define PYBIND11_EXPORT_EXCEPTION PYBIND11_EXPORT
......@@ -112,8 +113,8 @@
// However, the measured shared-library size saving when using noinline are only
// 1.7% for CUDA, -0.2% for GCC7, and 0.0% for GCC8 (using -DCMAKE_BUILD_TYPE=MinSizeRel,
// the default under pybind11/tests).
#if !defined(PYBIND11_NOINLINE_FORCED) && \
(defined(__CUDACC__) || (defined(__GNUC__) && (__GNUC__ == 7 || __GNUC__ == 8)))
#if !defined(PYBIND11_NOINLINE_FORCED) \
&& (defined(__CUDACC__) || (defined(__GNUC__) && (__GNUC__ == 7 || __GNUC__ == 8)))
# define PYBIND11_NOINLINE_DISABLED
#endif
......@@ -125,7 +126,7 @@
#elif defined(_MSC_VER)
# define PYBIND11_NOINLINE __declspec(noinline) inline
#else
# define PYBIND11_NOINLINE __attribute__ ((noinline)) inline
# define PYBIND11_NOINLINE __attribute__((noinline)) inline
#endif
#if defined(__MINGW32__)
......@@ -143,7 +144,7 @@
#elif defined(_MSC_VER) && !defined(__clang__)
# define PYBIND11_MAYBE_UNUSED
#else
# define PYBIND11_MAYBE_UNUSED __attribute__ ((__unused__))
# define PYBIND11_MAYBE_UNUSED __attribute__((__unused__))
#endif
/* Don't let Python.h #define (v)snprintf as macro because they are implemented
......@@ -156,7 +157,7 @@
#if defined(_MSC_VER)
# pragma warning(push)
// C4505: 'PySlice_GetIndicesEx': unreferenced local function has been removed (PyPy only)
# pragma warning(disable: 4505)
# pragma warning(disable : 4505)
# if defined(_DEBUG) && !defined(Py_DEBUG)
// Workaround for a VS 2022 issue.
// NOTE: This workaround knowingly violates the Python.h include order requirement:
......@@ -209,7 +210,6 @@
# define PYBIND11_HAS_U8STRING
#endif
#include <Python.h>
#include <frameobject.h>
#include <pythread.h>
......@@ -241,16 +241,16 @@
#include <cstddef>
#include <cstring>
#include <forward_list>
#include <vector>
#include <string>
#include <stdexcept>
#include <exception>
#include <unordered_set>
#include <unordered_map>
#include <forward_list>
#include <memory>
#include <typeindex>
#include <stdexcept>
#include <string>
#include <type_traits>
#include <typeindex>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#if defined(__has_include)
# if __has_include(<version>)
# include <version>
......@@ -271,70 +271,71 @@
// behavior.
#if PY_MAJOR_VERSION >= 3 /// Compatibility macros for various Python versions
#define PYBIND11_INSTANCE_METHOD_NEW(ptr, class_) PyInstanceMethod_New(ptr)
#define PYBIND11_INSTANCE_METHOD_CHECK PyInstanceMethod_Check
#define PYBIND11_INSTANCE_METHOD_GET_FUNCTION PyInstanceMethod_GET_FUNCTION
#define PYBIND11_BYTES_CHECK PyBytes_Check
#define PYBIND11_BYTES_FROM_STRING PyBytes_FromString
#define PYBIND11_BYTES_FROM_STRING_AND_SIZE PyBytes_FromStringAndSize
#define PYBIND11_BYTES_AS_STRING_AND_SIZE PyBytes_AsStringAndSize
#define PYBIND11_BYTES_AS_STRING PyBytes_AsString
#define PYBIND11_BYTES_SIZE PyBytes_Size
#define PYBIND11_LONG_CHECK(o) PyLong_Check(o)
#define PYBIND11_LONG_AS_LONGLONG(o) PyLong_AsLongLong(o)
#define PYBIND11_LONG_FROM_SIGNED(o) PyLong_FromSsize_t((ssize_t) (o))
#define PYBIND11_LONG_FROM_UNSIGNED(o) PyLong_FromSize_t((size_t) (o))
#define PYBIND11_BYTES_NAME "bytes"
#define PYBIND11_STRING_NAME "str"
#define PYBIND11_SLICE_OBJECT PyObject
#define PYBIND11_FROM_STRING PyUnicode_FromString
#define PYBIND11_STR_TYPE ::pybind11::str
#define PYBIND11_BOOL_ATTR "__bool__"
#define PYBIND11_NB_BOOL(ptr) ((ptr)->nb_bool)
#define PYBIND11_BUILTINS_MODULE "builtins"
# define PYBIND11_INSTANCE_METHOD_NEW(ptr, class_) PyInstanceMethod_New(ptr)
# define PYBIND11_INSTANCE_METHOD_CHECK PyInstanceMethod_Check
# define PYBIND11_INSTANCE_METHOD_GET_FUNCTION PyInstanceMethod_GET_FUNCTION
# define PYBIND11_BYTES_CHECK PyBytes_Check
# define PYBIND11_BYTES_FROM_STRING PyBytes_FromString
# define PYBIND11_BYTES_FROM_STRING_AND_SIZE PyBytes_FromStringAndSize
# define PYBIND11_BYTES_AS_STRING_AND_SIZE PyBytes_AsStringAndSize
# define PYBIND11_BYTES_AS_STRING PyBytes_AsString
# define PYBIND11_BYTES_SIZE PyBytes_Size
# define PYBIND11_LONG_CHECK(o) PyLong_Check(o)
# define PYBIND11_LONG_AS_LONGLONG(o) PyLong_AsLongLong(o)
# define PYBIND11_LONG_FROM_SIGNED(o) PyLong_FromSsize_t((ssize_t) (o))
# define PYBIND11_LONG_FROM_UNSIGNED(o) PyLong_FromSize_t((size_t) (o))
# define PYBIND11_BYTES_NAME "bytes"
# define PYBIND11_STRING_NAME "str"
# define PYBIND11_SLICE_OBJECT PyObject
# define PYBIND11_FROM_STRING PyUnicode_FromString
# define PYBIND11_STR_TYPE ::pybind11::str
# define PYBIND11_BOOL_ATTR "__bool__"
# define PYBIND11_NB_BOOL(ptr) ((ptr)->nb_bool)
# define PYBIND11_BUILTINS_MODULE "builtins"
// Providing a separate declaration to make Clang's -Wmissing-prototypes happy.
// See comment for PYBIND11_MODULE below for why this is marked "maybe unused".
#define PYBIND11_PLUGIN_IMPL(name) \
# define PYBIND11_PLUGIN_IMPL(name) \
extern "C" PYBIND11_MAYBE_UNUSED PYBIND11_EXPORT PyObject *PyInit_##name(); \
extern "C" PYBIND11_EXPORT PyObject *PyInit_##name()
#else
#define PYBIND11_INSTANCE_METHOD_NEW(ptr, class_) PyMethod_New(ptr, nullptr, class_)
#define PYBIND11_INSTANCE_METHOD_CHECK PyMethod_Check
#define PYBIND11_INSTANCE_METHOD_GET_FUNCTION PyMethod_GET_FUNCTION
#define PYBIND11_BYTES_CHECK PyString_Check
#define PYBIND11_BYTES_FROM_STRING PyString_FromString
#define PYBIND11_BYTES_FROM_STRING_AND_SIZE PyString_FromStringAndSize
#define PYBIND11_BYTES_AS_STRING_AND_SIZE PyString_AsStringAndSize
#define PYBIND11_BYTES_AS_STRING PyString_AsString
#define PYBIND11_BYTES_SIZE PyString_Size
#define PYBIND11_LONG_CHECK(o) (PyInt_Check(o) || PyLong_Check(o))
#define PYBIND11_LONG_AS_LONGLONG(o) (PyInt_Check(o) ? (long long) PyLong_AsLong(o) : PyLong_AsLongLong(o))
#define PYBIND11_LONG_FROM_SIGNED(o) PyInt_FromSsize_t((ssize_t) o) // Returns long if needed.
#define PYBIND11_LONG_FROM_UNSIGNED(o) PyInt_FromSize_t((size_t) o) // Returns long if needed.
#define PYBIND11_BYTES_NAME "str"
#define PYBIND11_STRING_NAME "unicode"
#define PYBIND11_SLICE_OBJECT PySliceObject
#define PYBIND11_FROM_STRING PyString_FromString
#define PYBIND11_STR_TYPE ::pybind11::bytes
#define PYBIND11_BOOL_ATTR "__nonzero__"
#define PYBIND11_NB_BOOL(ptr) ((ptr)->nb_nonzero)
#define PYBIND11_BUILTINS_MODULE "__builtin__"
# define PYBIND11_INSTANCE_METHOD_NEW(ptr, class_) PyMethod_New(ptr, nullptr, class_)
# define PYBIND11_INSTANCE_METHOD_CHECK PyMethod_Check
# define PYBIND11_INSTANCE_METHOD_GET_FUNCTION PyMethod_GET_FUNCTION
# define PYBIND11_BYTES_CHECK PyString_Check
# define PYBIND11_BYTES_FROM_STRING PyString_FromString
# define PYBIND11_BYTES_FROM_STRING_AND_SIZE PyString_FromStringAndSize
# define PYBIND11_BYTES_AS_STRING_AND_SIZE PyString_AsStringAndSize
# define PYBIND11_BYTES_AS_STRING PyString_AsString
# define PYBIND11_BYTES_SIZE PyString_Size
# define PYBIND11_LONG_CHECK(o) (PyInt_Check(o) || PyLong_Check(o))
# define PYBIND11_LONG_AS_LONGLONG(o) \
(PyInt_Check(o) ? (long long) PyLong_AsLong(o) : PyLong_AsLongLong(o))
# define PYBIND11_LONG_FROM_SIGNED(o) PyInt_FromSsize_t((ssize_t) o) // Returns long if needed.
# define PYBIND11_LONG_FROM_UNSIGNED(o) PyInt_FromSize_t((size_t) o) // Returns long if needed.
# define PYBIND11_BYTES_NAME "str"
# define PYBIND11_STRING_NAME "unicode"
# define PYBIND11_SLICE_OBJECT PySliceObject
# define PYBIND11_FROM_STRING PyString_FromString
# define PYBIND11_STR_TYPE ::pybind11::bytes
# define PYBIND11_BOOL_ATTR "__nonzero__"
# define PYBIND11_NB_BOOL(ptr) ((ptr)->nb_nonzero)
# define PYBIND11_BUILTINS_MODULE "__builtin__"
// Providing a separate PyInit decl to make Clang's -Wmissing-prototypes happy.
// See comment for PYBIND11_MODULE below for why this is marked "maybe unused".
#define PYBIND11_PLUGIN_IMPL(name) \
# define PYBIND11_PLUGIN_IMPL(name) \
static PyObject *pybind11_init_wrapper(); \
extern "C" PYBIND11_MAYBE_UNUSED PYBIND11_EXPORT void init##name(); \
extern "C" PYBIND11_EXPORT void init##name() { \
(void)pybind11_init_wrapper(); \
} \
extern "C" PYBIND11_EXPORT void init##name() { (void) pybind11_init_wrapper(); } \
PyObject *pybind11_init_wrapper()
#endif
#if PY_VERSION_HEX >= 0x03050000 && PY_VERSION_HEX < 0x03050200
extern "C" {
struct _Py_atomic_address { void *value; };
PyAPI_DATA(_Py_atomic_address) _PyThreadState_Current;
struct _Py_atomic_address {
void *value;
};
PyAPI_DATA(_Py_atomic_address) _PyThreadState_Current;
}
#endif
......@@ -342,13 +343,12 @@ extern "C" {
#define PYBIND11_STRINGIFY(x) #x
#define PYBIND11_TOSTRING(x) PYBIND11_STRINGIFY(x)
#define PYBIND11_CONCAT(first, second) first##second
#define PYBIND11_ENSURE_INTERNALS_READY \
pybind11::detail::get_internals();
#define PYBIND11_ENSURE_INTERNALS_READY pybind11::detail::get_internals();
#define PYBIND11_CHECK_PYTHON_VERSION \
{ \
const char *compiled_ver = PYBIND11_TOSTRING(PY_MAJOR_VERSION) \
"." PYBIND11_TOSTRING(PY_MINOR_VERSION); \
const char *compiled_ver \
= PYBIND11_TOSTRING(PY_MAJOR_VERSION) "." PYBIND11_TOSTRING(PY_MINOR_VERSION); \
const char *runtime_ver = Py_GetVersion(); \
size_t len = std::strlen(compiled_ver); \
if (std::strncmp(runtime_ver, compiled_ver, len) != 0 \
......@@ -356,32 +356,35 @@ extern "C" {
PyErr_Format(PyExc_ImportError, \
"Python version mismatch: module was compiled for Python %s, " \
"but the interpreter version is incompatible: %s.", \
compiled_ver, runtime_ver); \
compiled_ver, \
runtime_ver); \
return nullptr; \
} \
}
#if PY_VERSION_HEX >= 0x03030000
#define PYBIND11_CATCH_INIT_EXCEPTIONS \
catch (pybind11::error_already_set &e) { \
# define PYBIND11_CATCH_INIT_EXCEPTIONS \
catch (pybind11::error_already_set & e) { \
pybind11::raise_from(e, PyExc_ImportError, "initialization failed"); \
return nullptr; \
} catch (const std::exception &e) { \
} \
catch (const std::exception &e) { \
PyErr_SetString(PyExc_ImportError, e.what()); \
return nullptr; \
} \
}
#else
#define PYBIND11_CATCH_INIT_EXCEPTIONS \
catch (pybind11::error_already_set &e) { \
# define PYBIND11_CATCH_INIT_EXCEPTIONS \
catch (pybind11::error_already_set & e) { \
PyErr_SetString(PyExc_ImportError, e.what()); \
return nullptr; \
} catch (const std::exception &e) { \
} \
catch (const std::exception &e) { \
PyErr_SetString(PyExc_ImportError, e.what()); \
return nullptr; \
} \
}
#endif
......@@ -408,7 +411,8 @@ extern "C" {
PYBIND11_ENSURE_INTERNALS_READY \
try { \
return pybind11_init(); \
} PYBIND11_CATCH_INIT_EXCEPTIONS \
} \
PYBIND11_CATCH_INIT_EXCEPTIONS \
} \
PyObject *pybind11_init()
......@@ -516,10 +520,14 @@ enum class return_value_policy : uint8_t {
PYBIND11_NAMESPACE_BEGIN(detail)
inline static constexpr int log2(size_t n, int k = 0) { return (n <= 1) ? k : log2(n >> 1, k + 1); }
inline static constexpr int log2(size_t n, int k = 0) {
return (n <= 1) ? k : log2(n >> 1, k + 1);
}
// Returns the size as a multiple of sizeof(void *), rounded up.
inline static constexpr size_t size_in_ptrs(size_t s) { return 1 + ((s - 1) >> log2(sizeof(void *))); }
inline static constexpr size_t size_in_ptrs(size_t s) {
return 1 + ((s - 1) >> log2(sizeof(void *)));
}
/**
* The space to allocate for simple layout instance holders (see below) in multiple of the size of
......@@ -557,21 +565,21 @@ struct instance {
/**
* An instance has two possible value/holder layouts.
*
* Simple layout (when this flag is true), means the `simple_value_holder` is set with a pointer
* and the holder object governing that pointer, i.e. [val1*][holder]. This layout is applied
* whenever there is no python-side multiple inheritance of bound C++ types *and* the type's
* holder will fit in the default space (which is large enough to hold either a std::unique_ptr
* or std::shared_ptr).
* Simple layout (when this flag is true), means the `simple_value_holder` is set with a
* pointer and the holder object governing that pointer, i.e. [val1*][holder]. This layout is
* applied whenever there is no python-side multiple inheritance of bound C++ types *and* the
* type's holder will fit in the default space (which is large enough to hold either a
* std::unique_ptr or std::shared_ptr).
*
* Non-simple layout applies when using custom holders that require more space than `shared_ptr`
* (which is typically the size of two pointers), or when multiple inheritance is used on the
* python side. Non-simple layout allocates the required amount of memory to have multiple
* bound C++ classes as parents. Under this layout, `nonsimple.values_and_holders` is set to a
* pointer to allocated space of the required space to hold a sequence of value pointers and
* holders followed `status`, a set of bit flags (1 byte each), i.e.
* [val1*][holder1][val2*][holder2]...[bb...] where each [block] is rounded up to a multiple of
* `sizeof(void *)`. `nonsimple.status` is, for convenience, a pointer to the
* beginning of the [bb...] block (but not independently allocated).
* Non-simple layout applies when using custom holders that require more space than
* `shared_ptr` (which is typically the size of two pointers), or when multiple inheritance is
* used on the python side. Non-simple layout allocates the required amount of memory to have
* multiple bound C++ classes as parents. Under this layout, `nonsimple.values_and_holders` is
* set to a pointer to allocated space of the required space to hold a sequence of value
* pointers and holders followed `status`, a set of bit flags (1 byte each), i.e.
* [val1*][holder1][val2*][holder2]...[bb...] where each [block] is rounded up to a multiple
* of `sizeof(void *)`. `nonsimple.status` is, for convenience, a pointer to the beginning of
* the [bb...] block (but not independently allocated).
*
* Status bits indicate whether the associated holder is constructed (&
* status_holder_constructed) and whether the value pointer is registered (&
......@@ -585,7 +593,8 @@ struct instance {
/// If true, get_internals().patients has an entry for this object
bool has_patients : 1;
/// Initializes all of the above type/values/holders data (but not the instance values themselves)
/// Initializes all of the above type/values/holders data (but not the instance values
/// themselves)
void allocate_layout();
/// Destroys/deallocates all of the above
......@@ -594,26 +603,32 @@ struct instance {
/// Returns the value_and_holder wrapper for the given type (or the first, if `find_type`
/// omitted). Returns a default-constructed (with `.inst = nullptr`) object on failure if
/// `throw_if_missing` is false.
value_and_holder get_value_and_holder(const type_info *find_type = nullptr, bool throw_if_missing = true);
value_and_holder get_value_and_holder(const type_info *find_type = nullptr,
bool throw_if_missing = true);
/// Bit values for the non-simple status flags
static constexpr uint8_t status_holder_constructed = 1;
static constexpr uint8_t status_instance_registered = 2;
};
static_assert(std::is_standard_layout<instance>::value, "Internal error: `pybind11::detail::instance` is not standard layout!");
static_assert(std::is_standard_layout<instance>::value,
"Internal error: `pybind11::detail::instance` is not standard layout!");
/// from __cpp_future__ import (convenient aliases from C++14/17)
#if defined(PYBIND11_CPP14) && (!defined(_MSC_VER) || _MSC_VER >= 1910)
using std::enable_if_t;
using std::conditional_t;
using std::enable_if_t;
using std::remove_cv_t;
using std::remove_reference_t;
#else
template <bool B, typename T = void> using enable_if_t = typename std::enable_if<B, T>::type;
template <bool B, typename T, typename F> using conditional_t = typename std::conditional<B, T, F>::type;
template <typename T> using remove_cv_t = typename std::remove_cv<T>::type;
template <typename T> using remove_reference_t = typename std::remove_reference<T>::type;
template <bool B, typename T = void>
using enable_if_t = typename std::enable_if<B, T>::type;
template <bool B, typename T, typename F>
using conditional_t = typename std::conditional<B, T, F>::type;
template <typename T>
using remove_cv_t = typename std::remove_cv<T>::type;
template <typename T>
using remove_reference_t = typename std::remove_reference<T>::type;
#endif
#if defined(PYBIND11_CPP20)
......@@ -633,114 +648,189 @@ using remove_cvref_t = typename remove_cvref<T>::type;
using std::index_sequence;
using std::make_index_sequence;
#else
template<size_t ...> struct index_sequence { };
template<size_t N, size_t ...S> struct make_index_sequence_impl : make_index_sequence_impl <N - 1, N - 1, S...> { };
template<size_t ...S> struct make_index_sequence_impl <0, S...> { using type = index_sequence<S...>; };
template<size_t N> using make_index_sequence = typename make_index_sequence_impl<N>::type;
template <size_t...>
struct index_sequence {};
template <size_t N, size_t... S>
struct make_index_sequence_impl : make_index_sequence_impl<N - 1, N - 1, S...> {};
template <size_t... S>
struct make_index_sequence_impl<0, S...> {
using type = index_sequence<S...>;
};
template <size_t N>
using make_index_sequence = typename make_index_sequence_impl<N>::type;
#endif
/// Make an index sequence of the indices of true arguments
template <typename ISeq, size_t, bool...> struct select_indices_impl { using type = ISeq; };
template <size_t... IPrev, size_t I, bool B, bool... Bs> struct select_indices_impl<index_sequence<IPrev...>, I, B, Bs...>
: select_indices_impl<conditional_t<B, index_sequence<IPrev..., I>, index_sequence<IPrev...>>, I + 1, Bs...> {};
template <bool... Bs> using select_indices = typename select_indices_impl<index_sequence<>, 0, Bs...>::type;
template <typename ISeq, size_t, bool...>
struct select_indices_impl {
using type = ISeq;
};
template <size_t... IPrev, size_t I, bool B, bool... Bs>
struct select_indices_impl<index_sequence<IPrev...>, I, B, Bs...>
: select_indices_impl<conditional_t<B, index_sequence<IPrev..., I>, index_sequence<IPrev...>>,
I + 1,
Bs...> {};
template <bool... Bs>
using select_indices = typename select_indices_impl<index_sequence<>, 0, Bs...>::type;
/// Backports of std::bool_constant and std::negation to accommodate older compilers
template <bool B> using bool_constant = std::integral_constant<bool, B>;
template <typename T> struct negation : bool_constant<!T::value> { };
template <bool B>
using bool_constant = std::integral_constant<bool, B>;
template <typename T>
struct negation : bool_constant<!T::value> {};
// PGI/Intel cannot detect operator delete with the "compatible" void_t impl, so
// using the new one (C++14 defect, so generally works on newer compilers, even
// if not in C++17 mode)
#if defined(__PGIC__) || defined(__INTEL_COMPILER)
template<typename... > using void_t = void;
template <typename...>
using void_t = void;
#else
template <typename...> struct void_t_impl { using type = void; };
template <typename... Ts> using void_t = typename void_t_impl<Ts...>::type;
template <typename...>
struct void_t_impl {
using type = void;
};
template <typename... Ts>
using void_t = typename void_t_impl<Ts...>::type;
#endif
/// Compile-time all/any/none of that check the boolean value of all template types
#if defined(__cpp_fold_expressions) && !(defined(_MSC_VER) && (_MSC_VER < 1916))
template <class... Ts> using all_of = bool_constant<(Ts::value && ...)>;
template <class... Ts> using any_of = bool_constant<(Ts::value || ...)>;
template <class... Ts>
using all_of = bool_constant<(Ts::value && ...)>;
template <class... Ts>
using any_of = bool_constant<(Ts::value || ...)>;
#elif !defined(_MSC_VER)
template <bool...> struct bools {};
template <class... Ts> using all_of = std::is_same<
bools<Ts::value..., true>,
bools<true, Ts::value...>>;
template <class... Ts> using any_of = negation<all_of<negation<Ts>...>>;
template <bool...>
struct bools {};
template <class... Ts>
using all_of = std::is_same<bools<Ts::value..., true>, bools<true, Ts::value...>>;
template <class... Ts>
using any_of = negation<all_of<negation<Ts>...>>;
#else
// MSVC has trouble with the above, but supports std::conjunction, which we can use instead (albeit
// at a slight loss of compilation efficiency).
template <class... Ts> using all_of = std::conjunction<Ts...>;
template <class... Ts> using any_of = std::disjunction<Ts...>;
template <class... Ts>
using all_of = std::conjunction<Ts...>;
template <class... Ts>
using any_of = std::disjunction<Ts...>;
#endif
template <class... Ts> using none_of = negation<any_of<Ts...>>;
template <class... Ts>
using none_of = negation<any_of<Ts...>>;
template <class T, template<class> class... Predicates> using satisfies_all_of = all_of<Predicates<T>...>;
template <class T, template<class> class... Predicates> using satisfies_any_of = any_of<Predicates<T>...>;
template <class T, template<class> class... Predicates> using satisfies_none_of = none_of<Predicates<T>...>;
template <class T, template <class> class... Predicates>
using satisfies_all_of = all_of<Predicates<T>...>;
template <class T, template <class> class... Predicates>
using satisfies_any_of = any_of<Predicates<T>...>;
template <class T, template <class> class... Predicates>
using satisfies_none_of = none_of<Predicates<T>...>;
/// Strip the class from a method type
template <typename T> struct remove_class { };
template <typename C, typename R, typename... A> struct remove_class<R (C::*)(A...)> { using type = R (A...); };
template <typename C, typename R, typename... A> struct remove_class<R (C::*)(A...) const> { using type = R (A...); };
template <typename T>
struct remove_class {};
template <typename C, typename R, typename... A>
struct remove_class<R (C::*)(A...)> {
using type = R(A...);
};
template <typename C, typename R, typename... A>
struct remove_class<R (C::*)(A...) const> {
using type = R(A...);
};
/// Helper template to strip away type modifiers
template <typename T> struct intrinsic_type { using type = T; };
template <typename T> struct intrinsic_type<const T> { using type = typename intrinsic_type<T>::type; };
template <typename T> struct intrinsic_type<T*> { using type = typename intrinsic_type<T>::type; };
template <typename T> struct intrinsic_type<T&> { using type = typename intrinsic_type<T>::type; };
template <typename T> struct intrinsic_type<T&&> { using type = typename intrinsic_type<T>::type; };
template <typename T, size_t N> struct intrinsic_type<const T[N]> { using type = typename intrinsic_type<T>::type; };
template <typename T, size_t N> struct intrinsic_type<T[N]> { using type = typename intrinsic_type<T>::type; };
template <typename T> using intrinsic_t = typename intrinsic_type<T>::type;
template <typename T>
struct intrinsic_type {
using type = T;
};
template <typename T>
struct intrinsic_type<const T> {
using type = typename intrinsic_type<T>::type;
};
template <typename T>
struct intrinsic_type<T *> {
using type = typename intrinsic_type<T>::type;
};
template <typename T>
struct intrinsic_type<T &> {
using type = typename intrinsic_type<T>::type;
};
template <typename T>
struct intrinsic_type<T &&> {
using type = typename intrinsic_type<T>::type;
};
template <typename T, size_t N>
struct intrinsic_type<const T[N]> {
using type = typename intrinsic_type<T>::type;
};
template <typename T, size_t N>
struct intrinsic_type<T[N]> {
using type = typename intrinsic_type<T>::type;
};
template <typename T>
using intrinsic_t = typename intrinsic_type<T>::type;
/// Helper type to replace 'void' in some expressions
struct void_type { };
struct void_type {};
/// Helper template which holds a list of types
template <typename...> struct type_list { };
template <typename...>
struct type_list {};
/// Compile-time integer sum
#ifdef __cpp_fold_expressions
template <typename... Ts> constexpr size_t constexpr_sum(Ts... ns) { return (0 + ... + size_t{ns}); }
template <typename... Ts>
constexpr size_t constexpr_sum(Ts... ns) {
return (0 + ... + size_t{ns});
}
#else
constexpr size_t constexpr_sum() { return 0; }
template <typename T, typename... Ts>
constexpr size_t constexpr_sum(T n, Ts... ns) { return size_t{n} + constexpr_sum(ns...); }
constexpr size_t constexpr_sum(T n, Ts... ns) {
return size_t{n} + constexpr_sum(ns...);
}
#endif
PYBIND11_NAMESPACE_BEGIN(constexpr_impl)
/// Implementation details for constexpr functions
constexpr int first(int i) { return i; }
template <typename T, typename... Ts>
constexpr int first(int i, T v, Ts... vs) { return v ? i : first(i + 1, vs...); }
constexpr int first(int i, T v, Ts... vs) {
return v ? i : first(i + 1, vs...);
}
constexpr int last(int /*i*/, int result) { return result; }
template <typename T, typename... Ts>
constexpr int last(int i, int result, T v, Ts... vs) { return last(i + 1, v ? i : result, vs...); }
constexpr int last(int i, int result, T v, Ts... vs) {
return last(i + 1, v ? i : result, vs...);
}
PYBIND11_NAMESPACE_END(constexpr_impl)
/// Return the index of the first type in Ts which satisfies Predicate<T>.
/// Returns sizeof...(Ts) if none match.
template <template<typename> class Predicate, typename... Ts>
constexpr int constexpr_first() { return constexpr_impl::first(0, Predicate<Ts>::value...); }
template <template <typename> class Predicate, typename... Ts>
constexpr int constexpr_first() {
return constexpr_impl::first(0, Predicate<Ts>::value...);
}
/// Return the index of the last type in Ts which satisfies Predicate<T>, or -1 if none match.
template <template<typename> class Predicate, typename... Ts>
constexpr int constexpr_last() { return constexpr_impl::last(0, -1, Predicate<Ts>::value...); }
template <template <typename> class Predicate, typename... Ts>
constexpr int constexpr_last() {
return constexpr_impl::last(0, -1, Predicate<Ts>::value...);
}
/// Return the Nth element from the parameter pack
template <size_t N, typename T, typename... Ts>
struct pack_element { using type = typename pack_element<N - 1, Ts...>::type; };
struct pack_element {
using type = typename pack_element<N - 1, Ts...>::type;
};
template <typename T, typename... Ts>
struct pack_element<0, T, Ts...> { using type = T; };
struct pack_element<0, T, Ts...> {
using type = T;
};
/// Return the one and only type which matches the predicate, or Default if none match.
/// If more than one type matches the predicate, fail at compile-time.
template <template<typename> class Predicate, typename Default, typename... Ts>
template <template <typename> class Predicate, typename Default, typename... Ts>
struct exactly_one {
static constexpr auto found = constexpr_sum(Predicate<Ts>::value...);
static_assert(found <= 1, "Found more than one type matching the predicate");
......@@ -748,62 +838,81 @@ struct exactly_one {
static constexpr auto index = found ? constexpr_first<Predicate, Ts...>() : 0;
using type = conditional_t<found, typename pack_element<index, Ts...>::type, Default>;
};
template <template<typename> class P, typename Default>
struct exactly_one<P, Default> { using type = Default; };
template <template <typename> class P, typename Default>
struct exactly_one<P, Default> {
using type = Default;
};
template <template<typename> class Predicate, typename Default, typename... Ts>
template <template <typename> class Predicate, typename Default, typename... Ts>
using exactly_one_t = typename exactly_one<Predicate, Default, Ts...>::type;
/// Defer the evaluation of type T until types Us are instantiated
template <typename T, typename... /*Us*/> struct deferred_type { using type = T; };
template <typename T, typename... Us> using deferred_t = typename deferred_type<T, Us...>::type;
template <typename T, typename... /*Us*/>
struct deferred_type {
using type = T;
};
template <typename T, typename... Us>
using deferred_t = typename deferred_type<T, Us...>::type;
/// Like is_base_of, but requires a strict base (i.e. `is_strict_base_of<T, T>::value == false`,
/// unlike `std::is_base_of`)
template <typename Base, typename Derived> using is_strict_base_of = bool_constant<
std::is_base_of<Base, Derived>::value && !std::is_same<Base, Derived>::value>;
/// Like is_base_of, but also requires that the base type is accessible (i.e. that a Derived pointer
/// can be converted to a Base pointer)
/// For unions, `is_base_of<T, T>::value` is False, so we need to check `is_same` as well.
template <typename Base, typename Derived> using is_accessible_base_of = bool_constant<
(std::is_same<Base, Derived>::value || std::is_base_of<Base, Derived>::value) && std::is_convertible<Derived *, Base *>::value>;
template <template<typename...> class Base>
template <typename Base, typename Derived>
using is_strict_base_of
= bool_constant<std::is_base_of<Base, Derived>::value && !std::is_same<Base, Derived>::value>;
/// Like is_base_of, but also requires that the base type is accessible (i.e. that a Derived
/// pointer can be converted to a Base pointer) For unions, `is_base_of<T, T>::value` is False, so
/// we need to check `is_same` as well.
template <typename Base, typename Derived>
using is_accessible_base_of
= bool_constant<(std::is_same<Base, Derived>::value || std::is_base_of<Base, Derived>::value)
&& std::is_convertible<Derived *, Base *>::value>;
template <template <typename...> class Base>
struct is_template_base_of_impl {
template <typename... Us> static std::true_type check(Base<Us...> *);
template <typename... Us>
static std::true_type check(Base<Us...> *);
static std::false_type check(...);
};
/// Check if a template is the base of a type. For example:
/// `is_template_base_of<Base, T>` is true if `struct T : Base<U> {}` where U can be anything
template <template<typename...> class Base, typename T>
template <template <typename...> class Base, typename T>
#if !defined(_MSC_VER)
using is_template_base_of = decltype(is_template_base_of_impl<Base>::check((intrinsic_t<T>*)nullptr));
using is_template_base_of
= decltype(is_template_base_of_impl<Base>::check((intrinsic_t<T> *) nullptr));
#else // MSVC2015 has trouble with decltype in template aliases
struct is_template_base_of : decltype(is_template_base_of_impl<Base>::check((intrinsic_t<T>*)nullptr)) { };
struct is_template_base_of
: decltype(is_template_base_of_impl<Base>::check((intrinsic_t<T> *) nullptr)) {
};
#endif
/// Check if T is an instantiation of the template `Class`. For example:
/// `is_instantiation<shared_ptr, T>` is true if `T == shared_ptr<U>` where U can be anything.
template <template<typename...> class Class, typename T>
struct is_instantiation : std::false_type { };
template <template<typename...> class Class, typename... Us>
struct is_instantiation<Class, Class<Us...>> : std::true_type { };
template <template <typename...> class Class, typename T>
struct is_instantiation : std::false_type {};
template <template <typename...> class Class, typename... Us>
struct is_instantiation<Class, Class<Us...>> : std::true_type {};
/// Check if T is std::shared_ptr<U> where U can be anything
template <typename T> using is_shared_ptr = is_instantiation<std::shared_ptr, T>;
template <typename T>
using is_shared_ptr = is_instantiation<std::shared_ptr, T>;
/// Check if T looks like an input iterator
template <typename T, typename = void> struct is_input_iterator : std::false_type {};
template <typename T, typename = void>
struct is_input_iterator : std::false_type {};
template <typename T>
struct is_input_iterator<T, void_t<decltype(*std::declval<T &>()), decltype(++std::declval<T &>())>>
struct is_input_iterator<T,
void_t<decltype(*std::declval<T &>()), decltype(++std::declval<T &>())>>
: std::true_type {};
template <typename T> using is_function_pointer = bool_constant<
std::is_pointer<T>::value && std::is_function<typename std::remove_pointer<T>::type>::value>;
template <typename T>
using is_function_pointer
= bool_constant<std::is_pointer<T>::value
&& std::is_function<typename std::remove_pointer<T>::type>::value>;
template <typename F> struct strip_function_object {
template <typename F>
struct strip_function_object {
// If you are encountering an
// 'error: name followed by "::" must be a class or namespace name'
// with the Intel compiler and a noexcept function here,
......@@ -816,34 +925,35 @@ template <typename Function, typename F = remove_reference_t<Function>>
using function_signature_t = conditional_t<
std::is_function<F>::value,
F,
typename conditional_t<
std::is_pointer<F>::value || std::is_member_pointer<F>::value,
typename conditional_t<std::is_pointer<F>::value || std::is_member_pointer<F>::value,
std::remove_pointer<F>,
strip_function_object<F>
>::type
>;
strip_function_object<F>>::type>;
/// Returns true if the type looks like a lambda: that is, isn't a function, pointer or member
/// pointer. Note that this can catch all sorts of other things, too; this is intended to be used
/// in a place where passing a lambda makes sense.
template <typename T> using is_lambda = satisfies_none_of<remove_reference_t<T>,
std::is_function, std::is_pointer, std::is_member_pointer>;
template <typename T>
using is_lambda = satisfies_none_of<remove_reference_t<T>,
std::is_function,
std::is_pointer,
std::is_member_pointer>;
// [workaround(intel)] Internal error on fold expression
/// Apply a function over each element of a parameter pack
#if defined(__cpp_fold_expressions) && !defined(__INTEL_COMPILER)
// Intel compiler produces an internal error on this fold expression (tested with ICC 19.0.2)
#define PYBIND11_EXPAND_SIDE_EFFECTS(PATTERN) (((PATTERN), void()), ...)
# define PYBIND11_EXPAND_SIDE_EFFECTS(PATTERN) (((PATTERN), void()), ...)
#else
using expand_side_effects = bool[];
#define PYBIND11_EXPAND_SIDE_EFFECTS(PATTERN) (void)pybind11::detail::expand_side_effects{ ((PATTERN), void(), false)..., false }
# define PYBIND11_EXPAND_SIDE_EFFECTS(PATTERN) \
(void) pybind11::detail::expand_side_effects { ((PATTERN), void(), false)..., false }
#endif
PYBIND11_NAMESPACE_END(detail)
#if defined(_MSC_VER)
# pragma warning(push)
# pragma warning(disable: 4275)
# pragma warning(disable : 4275)
// warning C4275: An exported class was derived from a class that wasn't exported.
// Can be ignored when derived from a STL class.
#endif
......@@ -859,9 +969,10 @@ public:
#endif
#define PYBIND11_RUNTIME_EXCEPTION(name, type) \
class PYBIND11_EXPORT_EXCEPTION name : public builtin_exception { public: \
class PYBIND11_EXPORT_EXCEPTION name : public builtin_exception { \
public: \
using builtin_exception::builtin_exception; \
name() : name("") { } \
name() : name("") {} \
void set_error() const override { PyErr_SetString(type, what()); } \
};
......@@ -878,10 +989,15 @@ PYBIND11_RUNTIME_EXCEPTION(cast_error, PyExc_RuntimeError) /// Thrown when pybin
/// casting error
PYBIND11_RUNTIME_EXCEPTION(reference_cast_error, PyExc_RuntimeError) /// Used internally
[[noreturn]] PYBIND11_NOINLINE void pybind11_fail(const char *reason) { throw std::runtime_error(reason); }
[[noreturn]] PYBIND11_NOINLINE void pybind11_fail(const std::string &reason) { throw std::runtime_error(reason); }
[[noreturn]] PYBIND11_NOINLINE void pybind11_fail(const char *reason) {
throw std::runtime_error(reason);
}
[[noreturn]] PYBIND11_NOINLINE void pybind11_fail(const std::string &reason) {
throw std::runtime_error(reason);
}
template <typename T, typename SFINAE = void> struct format_descriptor { };
template <typename T, typename SFINAE = void>
struct format_descriptor {};
PYBIND11_NAMESPACE_BEGIN(detail)
// Returns the index of the given type in the type char array below, and in the list in numpy.h
......@@ -889,25 +1005,38 @@ PYBIND11_NAMESPACE_BEGIN(detail)
// complex float,double,long double. Note that the long double types only participate when long
// double is actually longer than double (it isn't under MSVC).
// NB: not only the string below but also complex.h and numpy.h rely on this order.
template <typename T, typename SFINAE = void> struct is_fmt_numeric { static constexpr bool value = false; };
template <typename T> struct is_fmt_numeric<T, enable_if_t<std::is_arithmetic<T>::value>> {
template <typename T, typename SFINAE = void>
struct is_fmt_numeric {
static constexpr bool value = false;
};
template <typename T>
struct is_fmt_numeric<T, enable_if_t<std::is_arithmetic<T>::value>> {
static constexpr bool value = true;
static constexpr int index = std::is_same<T, bool>::value ? 0 : 1 + (
std::is_integral<T>::value ? detail::log2(sizeof(T))*2 + std::is_unsigned<T>::value : 8 + (
std::is_same<T, double>::value ? 1 : std::is_same<T, long double>::value ? 2 : 0));
static constexpr int index
= std::is_same<T, bool>::value
? 0
: 1
+ (std::is_integral<T>::value
? detail::log2(sizeof(T)) * 2 + std::is_unsigned<T>::value
: 8
+ (std::is_same<T, double>::value ? 1
: std::is_same<T, long double>::value ? 2
: 0));
};
PYBIND11_NAMESPACE_END(detail)
template <typename T> struct format_descriptor<T, detail::enable_if_t<std::is_arithmetic<T>::value>> {
template <typename T>
struct format_descriptor<T, detail::enable_if_t<std::is_arithmetic<T>::value>> {
static constexpr const char c = "?bBhHiIqQfdg"[detail::is_fmt_numeric<T>::index];
static constexpr const char value[2] = { c, '\0' };
static constexpr const char value[2] = {c, '\0'};
static std::string format() { return std::string(1, c); }
};
#if !defined(PYBIND11_CPP17)
template <typename T> constexpr const char format_descriptor<
T, detail::enable_if_t<std::is_arithmetic<T>::value>>::value[2];
template <typename T>
constexpr const char
format_descriptor<T, detail::enable_if_t<std::is_arithmetic<T>::value>>::value[2];
#endif
......@@ -919,7 +1048,10 @@ struct error_scope {
};
/// Dummy destructor wrapper that can be used to expose classes with a private destructor
struct nodelete { template <typename T> void operator()(T*) { } };
struct nodelete {
template <typename T>
void operator()(T *) {}
};
PYBIND11_NAMESPACE_BEGIN(detail)
template <typename... Args>
......@@ -928,22 +1060,27 @@ struct overload_cast_impl {
constexpr overload_cast_impl() {}
template <typename Return>
constexpr auto operator()(Return (*pf)(Args...)) const noexcept
-> decltype(pf) { return pf; }
constexpr auto operator()(Return (*pf)(Args...)) const noexcept -> decltype(pf) {
return pf;
}
template <typename Return, typename Class>
constexpr auto operator()(Return (Class::*pmf)(Args...), std::false_type = {}) const noexcept
-> decltype(pmf) { return pmf; }
-> decltype(pmf) {
return pmf;
}
template <typename Return, typename Class>
constexpr auto operator()(Return (Class::*pmf)(Args...) const, std::true_type) const noexcept
-> decltype(pmf) { return pmf; }
-> decltype(pmf) {
return pmf;
}
};
PYBIND11_NAMESPACE_END(detail)
// overload_cast requires variable templates: C++14
#if defined(PYBIND11_CPP14)
#define PYBIND11_OVERLOAD_CAST 1
# define PYBIND11_OVERLOAD_CAST 1
/// Syntax sugar for resolving overloaded function pointers:
/// - regular: static_cast<Return (Class::*)(Arg0, Arg1, Arg2)>(&Class::func)
/// - sweet: overload_cast<Arg0, Arg1, Arg2>(&Class::func)
......@@ -958,7 +1095,8 @@ static constexpr detail::overload_cast_impl<Args...> overload_cast = {};
static constexpr auto const_ = std::true_type{};
#if !defined(PYBIND11_CPP14) // no overload_cast: providing something that static_assert-fails:
template <typename... Args> struct overload_cast {
template <typename... Args>
struct overload_cast {
static_assert(detail::deferred_t<std::false_type, Args...>::value,
"pybind11::overload_cast<...> requires compiling in C++14 mode");
};
......@@ -972,27 +1110,31 @@ PYBIND11_NAMESPACE_BEGIN(detail)
template <typename T>
class any_container {
std::vector<T> v;
public:
any_container() = default;
// Can construct from a pair of iterators
template <typename It, typename = enable_if_t<is_input_iterator<It>::value>>
any_container(It first, It last) : v(first, last) { }
any_container(It first, It last) : v(first, last) {}
// Implicit conversion constructor from any arbitrary container type
// with values convertible to T
template <typename Container, typename = enable_if_t<std::is_convertible<decltype(*std::begin(std::declval<const Container &>())), T>::value>>
template <typename Container,
typename = enable_if_t<
std::is_convertible<decltype(*std::begin(std::declval<const Container &>())),
T>::value>>
// NOLINTNEXTLINE(google-explicit-constructor)
any_container(const Container &c) : any_container(std::begin(c), std::end(c)) { }
any_container(const Container &c) : any_container(std::begin(c), std::end(c)) {}
// initializer_list's aren't deducible, so don't get matched by the above template;
// we need this to explicitly allow implicit conversion from one:
template <typename TIn, typename = enable_if_t<std::is_convertible<TIn, T>::value>>
any_container(const std::initializer_list<TIn> &c) : any_container(c.begin(), c.end()) { }
any_container(const std::initializer_list<TIn> &c) : any_container(c.begin(), c.end()) {}
// Avoid copying if given an rvalue vector of the correct type.
// NOLINTNEXTLINE(google-explicit-constructor)
any_container(std::vector<T> &&v) : v(std::move(v)) { }
any_container(std::vector<T> &&v) : v(std::move(v)) {}
// Moves the vector out of an rvalue any_container
// NOLINTNEXTLINE(google-explicit-constructor)
......@@ -1008,10 +1150,11 @@ public:
};
// Forward-declaration; see detail/class.h
std::string get_fully_qualified_tp_name(PyTypeObject*);
std::string get_fully_qualified_tp_name(PyTypeObject *);
template <typename T>
inline static std::shared_ptr<T> try_get_shared_from_this(std::enable_shared_from_this<T> *holder_value_ptr) {
inline static std::shared_ptr<T>
try_get_shared_from_this(std::enable_shared_from_this<T> *holder_value_ptr) {
// Pre C++17, this code path exploits undefined behavior, but is known to work on many platforms.
// Use at your own risk!
// See also https://en.cppreference.com/w/cpp/memory/enable_shared_from_this, and in particular
......@@ -1021,8 +1164,7 @@ inline static std::shared_ptr<T> try_get_shared_from_this(std::enable_shared_fro
#else
try {
return holder_value_ptr->shared_from_this();
}
catch (const std::bad_weak_ptr &) {
} catch (const std::bad_weak_ptr &) {
return nullptr;
}
#endif
......@@ -1033,7 +1175,9 @@ template <typename... Args>
#if defined(_MSC_VER) && _MSC_VER >= 1910 && _MSC_VER < 1920 // MSVC 2017
constexpr
#endif
inline void silence_unused_warnings(Args &&...) {}
inline void
silence_unused_warnings(Args &&...) {
}
// MSVC warning C4100: Unreferenced formal parameter
#if defined(_MSC_VER) && _MSC_VER <= 1916
......
......@@ -27,14 +27,14 @@ struct descr {
constexpr descr() = default;
// NOLINTNEXTLINE(google-explicit-constructor)
constexpr descr(char const (&s)[N+1]) : descr(s, make_index_sequence<N>()) { }
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'} { }
constexpr descr(char const (&s)[N + 1], index_sequence<Is...>) : text{s[Is]..., '\0'} {}
template <typename... Chars>
// NOLINTNEXTLINE(google-explicit-constructor)
constexpr descr(char c, Chars... cs) : text{c, static_cast<char>(cs)..., '\0'} { }
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}};
......@@ -42,81 +42,106 @@ struct descr {
};
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...>) {
constexpr descr<N1 + N2, Ts1..., Ts2...> plus_impl(const descr<N1, Ts1...> &a,
const descr<N2, Ts2...> &b,
index_sequence<Is1...>,
index_sequence<Is2...>) {
PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(b);
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) {
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> const_name(char const(&text)[N]) { return descr<N - 1>(text); }
constexpr descr<0> const_name(char const(&)[1]) { return {}; }
constexpr descr<N - 1> const_name(char const (&text)[N]) {
return descr<N - 1>(text);
}
constexpr descr<0> const_name(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...> {
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...> {
// WARNING: This only works with C++17 or higher.
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>> const_name(char const(&text1)[N1], char const(&)[N2]) {
constexpr enable_if_t<B, descr<N1 - 1>> const_name(char const (&text1)[N1], char const (&)[N2]) {
return const_name(text1);
}
template <bool B, size_t N1, size_t N2>
constexpr enable_if_t<!B, descr<N2 - 1>> const_name(char const(&)[N1], char const(&text2)[N2]) {
constexpr enable_if_t<!B, descr<N2 - 1>> const_name(char const (&)[N1], char const (&text2)[N2]) {
return const_name(text2);
}
template <bool B, typename T1, typename T2>
constexpr enable_if_t<B, T1> const_name(const T1 &d, const T2 &) { return d; }
constexpr enable_if_t<B, T1> const_name(const T1 &d, const T2 &) {
return d;
}
template <bool B, typename T1, typename T2>
constexpr enable_if_t<!B, T2> const_name(const T1 &, const T2 &d) { return d; }
constexpr enable_if_t<!B, T2> const_name(const T1 &, const T2 &d) {
return d;
}
template <size_t Size>
auto constexpr const_name() -> remove_cv_t<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> const_name() { return {'%'}; }
template <typename Type>
constexpr descr<1, Type> const_name() {
return {'%'};
}
// If "_" is defined as a macro, py::detail::_ cannot be provided.
// It is therefore best to use py::detail::const_name universally.
// This block is for backward compatibility only.
// (The const_name code is repeated to avoid introducing a "_" #define ourselves.)
#ifndef _
#define PYBIND11_DETAIL_UNDERSCORE_BACKWARD_COMPATIBILITY
# define PYBIND11_DETAIL_UNDERSCORE_BACKWARD_COMPATIBILITY
template <size_t N>
constexpr descr<N-1> _(char const(&text)[N]) { return const_name<N>(text); }
constexpr descr<N - 1> _(char const (&text)[N]) {
return const_name<N>(text);
}
template <bool B, size_t N1, size_t N2>
constexpr enable_if_t<B, descr<N1 - 1>> _(char const(&text1)[N1], char const(&text2)[N2]) {
return const_name<B,N1,N2>(text1, text2);
constexpr enable_if_t<B, descr<N1 - 1>> _(char const (&text1)[N1], char const (&text2)[N2]) {
return const_name<B, N1, N2>(text1, text2);
}
template <bool B, size_t N1, size_t N2>
constexpr enable_if_t<!B, descr<N2 - 1>> _(char const(&text1)[N1], char const(&text2)[N2]) {
return const_name<B,N1,N2>(text1, text2);
constexpr enable_if_t<!B, descr<N2 - 1>> _(char const (&text1)[N1], char const (&text2)[N2]) {
return const_name<B, N1, N2>(text1, text2);
}
template <bool B, typename T1, typename T2>
constexpr enable_if_t<B, T1> _(const T1 &d1, const T2 &d2) { return const_name<B,T1,T2>(d1, d2); }
constexpr enable_if_t<B, T1> _(const T1 &d1, const T2 &d2) {
return const_name<B, T1, T2>(d1, d2);
}
template <bool B, typename T1, typename T2>
constexpr enable_if_t<!B, T2> _(const T1 &d1, const T2 &d2) { return const_name<B,T1,T2>(d1, d2); }
constexpr enable_if_t<!B, T2> _(const T1 &d1, const T2 &d2) {
return const_name<B, T1, T2>(d1, d2);
}
template <size_t Size>
auto constexpr _() -> remove_cv_t<decltype(int_to_str<Size / 10, Size % 10>::digits)> {
return const_name<Size>();
}
template <typename Type> constexpr descr<1, Type> _() { return const_name<Type>(); }
template <typename Type>
constexpr descr<1, Type> _() {
return const_name<Type>();
}
#endif // #ifndef _
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)
......
......@@ -22,7 +22,8 @@ public:
return true;
}
template <typename> using cast_op_type = value_and_holder &;
template <typename>
using cast_op_type = value_and_holder &;
explicit operator value_and_holder &() { return *value; }
static constexpr auto name = const_name<value_and_holder>();
......@@ -39,11 +40,15 @@ inline void no_nullptr(void *ptr) {
}
// Implementing functions for all forms of py::init<...> and py::init(...)
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 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.
template <typename Class, enable_if_t<Class::has_alias, int> = 0>
......@@ -52,17 +57,27 @@ bool is_alias(Cpp<Class> *ptr) {
}
// Failing fallback version of the above for a no-alias class (always returns false)
template <typename /*Class*/>
constexpr bool is_alias(void *) { return false; }
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)...}; }
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
......@@ -71,12 +86,14 @@ inline Class *construct_or_initialize(Args &&...args) { return new Class{std::fo
// 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) {
value_and_holder &v_h,
Cpp<Class> &&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> &&) {
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");
}
......@@ -131,7 +148,8 @@ void construct(value_and_holder &v_h, Alias<Class> *alias_ptr, bool) {
// 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).
// 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) {
PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(need_alias);
......@@ -168,7 +186,8 @@ void construct(value_and_holder &v_h, Cpp<Class> &&result, bool need_alias) {
// 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,
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));
}
......@@ -177,16 +196,21 @@ void construct(value_and_holder &v_h, Alias<Class> &&result, bool) {
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) {
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...);
},
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) {
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) {
......@@ -202,30 +226,46 @@ struct 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... 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...);
}
};
// 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>>
template <typename CFunc,
typename AFunc = void_type (*)(),
typename = function_signature_t<CFunc>,
typename = function_signature_t<AFunc>>
struct factory;
// Specialization for py::init(Func)
......@@ -243,22 +283,32 @@ struct factory<Func, void_type (*)(), Return(Args...)> {
// 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
#if defined(PYBIND11_CPP14)
cl.def(
"__init__",
[func = std::move(class_factory)]
#else
auto &func = class_factory;
cl.def("__init__", [func]
#endif
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 "
......@@ -271,30 +321,37 @@ struct factory<CFunc, AFunc, CReturn(CArgs...), AReturn(AArgs...)> {
remove_reference_t<AFunc> alias_factory;
factory(CFunc &&c, AFunc &&a)
: class_factory(std::forward<CFunc>(c)), alias_factory(std::forward<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 "
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
#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
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:
// 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...);
},
is_new_style_constructor(),
extra...);
}
};
......@@ -305,7 +362,9 @@ void setstate(value_and_holder &v_h, T &&result, bool need_alias) {
}
/// Set both the C++ and Python states
template <typename Class, typename T, typename O,
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);
......@@ -319,12 +378,18 @@ void setstate(value_and_holder &v_h, std::pair<T, O> &&result, bool need_alias)
}
/// 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 "
......@@ -333,23 +398,28 @@ struct pickle_factory<Get, Set, RetState(Self), NewInstance(ArgState)> {
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));
#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]
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...);
}
};
......
......@@ -10,6 +10,7 @@
#pragma once
#include "../pytypes.h"
#include <exception>
/// Tracks the `internals` and `type_info` ABI version independent of the main library version.
......@@ -136,9 +137,9 @@ template <typename value_type>
using type_map = std::unordered_map<std::type_index, value_type, type_hash, type_equal_to>;
struct override_hash {
inline size_t operator()(const std::pair<const PyObject *, const char *>& v) const {
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);
value ^= std::hash<const void *>()(v.second) + 0x9e3779b9 + (value << 6) + (value >> 2);
return value;
}
};
......@@ -151,8 +152,9 @@ struct internals {
type_map<type_info *> registered_types_cpp;
// PyTypeObject* -> base type_info(s)
std::unordered_map<PyTypeObject *, std::vector<type_info *>> registered_types_py;
std::unordered_multimap<const void *, instance*> registered_instances; // void * -> instance*
std::unordered_set<std::pair<const PyObject *, const char *>, override_hash> inactive_override_cache;
std::unordered_multimap<const void *, instance *> registered_instances; // void * -> instance*
std::unordered_set<std::pair<const PyObject *, const char *>, override_hash>
inactive_override_cache;
type_map<std::vector<bool (*)(PyObject *, void *&)>> direct_conversions;
std::unordered_map<const PyObject *, std::vector<PyObject *>> patients;
std::forward_list<ExceptionTranslator> registered_exception_translators;
......@@ -198,8 +200,8 @@ struct type_info {
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<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;
......@@ -275,11 +277,15 @@ struct type_info {
# endif
#endif
#define PYBIND11_INTERNALS_ID "__pybind11_internals_v" \
PYBIND11_TOSTRING(PYBIND11_INTERNALS_VERSION) PYBIND11_INTERNALS_KIND PYBIND11_COMPILER_TYPE PYBIND11_STDLIB PYBIND11_BUILD_ABI PYBIND11_BUILD_TYPE "__"
#define PYBIND11_INTERNALS_ID \
"__pybind11_internals_v" PYBIND11_TOSTRING(PYBIND11_INTERNALS_VERSION) \
PYBIND11_INTERNALS_KIND PYBIND11_COMPILER_TYPE PYBIND11_STDLIB PYBIND11_BUILD_ABI \
PYBIND11_BUILD_TYPE "__"
#define PYBIND11_MODULE_LOCAL_ID "__pybind11_module_local_v" \
PYBIND11_TOSTRING(PYBIND11_INTERNALS_VERSION) PYBIND11_INTERNALS_KIND PYBIND11_COMPILER_TYPE PYBIND11_STDLIB PYBIND11_BUILD_ABI PYBIND11_BUILD_TYPE "__"
#define PYBIND11_MODULE_LOCAL_ID \
"__pybind11_module_local_v" PYBIND11_TOSTRING(PYBIND11_INTERNALS_VERSION) \
PYBIND11_INTERNALS_KIND PYBIND11_COMPILER_TYPE PYBIND11_STDLIB PYBIND11_BUILD_ABI \
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`.
......@@ -396,8 +402,12 @@ inline void translate_local_exception(std::exception_ptr p) {
if (p) {
std::rethrow_exception(p);
}
} catch (error_already_set &e) { e.restore(); return;
} catch (const builtin_exception &e) { e.set_error(); return;
} catch (error_already_set &e) {
e.restore();
return;
} catch (const builtin_exception &e) {
e.set_error();
return;
}
}
#endif
......@@ -412,7 +422,7 @@ PYBIND11_NOINLINE internals &get_internals() {
// Ensure that the GIL is held since we will need to make Python calls.
// Cannot use py::gil_scoped_acquire here since that constructor calls get_internals.
struct gil_scoped_acquire_local {
gil_scoped_acquire_local() : state (PyGILState_Ensure()) {}
gil_scoped_acquire_local() : state(PyGILState_Ensure()) {}
~gil_scoped_acquire_local() { PyGILState_Release(state); }
const PyGILState_STATE state;
} gil;
......@@ -516,7 +526,6 @@ inline local_internals &get_local_internals() {
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
......@@ -548,7 +557,7 @@ PYBIND11_NOINLINE void *set_shared_data(const std::string &name, void *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>
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);
......
......@@ -14,6 +14,7 @@
#include "descr.h"
#include "internals.h"
#include "typeid.h"
#include <cstdint>
#include <iterator>
#include <new>
......@@ -32,7 +33,7 @@ PYBIND11_NAMESPACE_BEGIN(detail)
/// Adding a patient will keep it alive up until the enclosing function returns.
class loader_life_support {
private:
loader_life_support* parent = nullptr;
loader_life_support *parent = nullptr;
std::unordered_set<PyObject *> keep_alive;
#if defined(WITH_THREAD)
......@@ -98,7 +99,8 @@ public:
// Gets the cache entry for the given type, creating it if necessary. The return value is the pair
// returned by emplace, i.e. an iterator for the entry and a bool set to `true` if the entry was
// just created.
inline std::pair<decltype(internals::registered_types_py)::iterator, bool> all_type_info_get_cache(PyTypeObject *type);
inline std::pair<decltype(internals::registered_types_py)::iterator, bool>
all_type_info_get_cache(PyTypeObject *type);
// Populates a just-created cache entry.
PYBIND11_NOINLINE void all_type_info_populate(PyTypeObject *t, std::vector<type_info *> &bases) {
......@@ -119,23 +121,25 @@ PYBIND11_NOINLINE void all_type_info_populate(PyTypeObject *t, std::vector<type_
auto it = type_dict.find(type);
if (it != type_dict.end()) {
// We found a cache entry for it, so it's either pybind-registered or has pre-computed
// pybind bases, but we have to make sure we haven't already seen the type(s) before: we
// want to follow Python/virtual C++ rules that there should only be one instance of a
// common base.
// pybind bases, but we have to make sure we haven't already seen the type(s) before:
// we want to follow Python/virtual C++ rules that there should only be one instance of
// a common base.
for (auto *tinfo : it->second) {
// NB: Could use a second set here, rather than doing a linear search, but since
// having a large number of immediate pybind11-registered types seems fairly
// unlikely, that probably isn't worthwhile.
bool found = false;
for (auto *known : bases) {
if (known == tinfo) { found = true; break; }
if (known == tinfo) {
found = true;
break;
}
}
if (!found) {
bases.push_back(tinfo);
}
}
}
else if (type->tp_bases) {
} else if (type->tp_bases) {
// It's some python type, so keep follow its bases classes to look for one or more
// registered types
if (i + 1 == check.size()) {
......@@ -177,7 +181,7 @@ inline const std::vector<detail::type_info *> &all_type_info(PyTypeObject *type)
* ancestors are pybind11-registered. Throws an exception if there are multiple bases--use
* `all_type_info` instead if you want to support multiple bases.
*/
PYBIND11_NOINLINE detail::type_info* get_type_info(PyTypeObject *type) {
PYBIND11_NOINLINE detail::type_info *get_type_info(PyTypeObject *type) {
const auto &bases = all_type_info(type);
if (bases.empty()) {
return nullptr;
......@@ -207,7 +211,8 @@ inline detail::type_info *get_global_type_info(const std::type_index &tp) {
return nullptr;
}
/// Return the type info for a given C++ type; on lookup failure can either throw or return nullptr.
/// Return the type info for a given C++ type; on lookup failure can either throw or return
/// nullptr.
PYBIND11_NOINLINE detail::type_info *get_type_info(const std::type_index &tp,
bool throw_if_missing = false) {
if (auto *ltype = get_local_type_info(tp)) {
......@@ -220,7 +225,8 @@ PYBIND11_NOINLINE detail::type_info *get_type_info(const std::type_index &tp,
if (throw_if_missing) {
std::string tname = tp.name();
detail::clean_type_id(tname);
pybind11_fail("pybind11::detail::get_type_info: unable to find type info for \"" + tname + "\"");
pybind11_fail("pybind11::detail::get_type_info: unable to find type info for \"" + tname
+ "\"");
}
return nullptr;
}
......@@ -251,10 +257,10 @@ struct value_and_holder {
void **vh = nullptr;
// Main constructor for a found value/holder:
value_and_holder(instance *i, const detail::type_info *type, size_t vpos, size_t index) :
inst{i}, index{index}, type{type},
vh{inst->simple_layout ? inst->simple_value_holder : &inst->nonsimple.values_and_holders[vpos]}
{}
value_and_holder(instance *i, const detail::type_info *type, size_t vpos, size_t index)
: inst{i}, index{index}, type{type}, vh{inst->simple_layout
? inst->simple_value_holder
: &inst->nonsimple.values_and_holders[vpos]} {}
// Default constructor (used to signal a value-and-holder not found by get_value_and_holder())
value_and_holder() = default;
......@@ -262,13 +268,15 @@ struct value_and_holder {
// Used for past-the-end iterator
explicit value_and_holder(size_t index) : index{index} {}
template <typename V = void> V *&value_ptr() const {
template <typename V = void>
V *&value_ptr() const {
return reinterpret_cast<V *&>(vh[0]);
}
// True if this `value_and_holder` has a non-null value pointer
explicit operator bool() const { return value_ptr() != nullptr; }
template <typename H> H &holder() const {
template <typename H>
H &holder() const {
return reinterpret_cast<H &>(vh[1]);
}
bool holder_constructed() const {
......@@ -325,8 +333,7 @@ public:
curr(inst /* instance */,
types->empty() ? nullptr : (*types)[0] /* type info */,
0, /* vpos: (non-simple types only): the first vptr comes first */
0 /* index */)
{}
0 /* index */) {}
// Past-the-end iterator:
explicit iterator(size_t end) : curr(end) {}
......@@ -369,7 +376,9 @@ public:
* The returned object should be short-lived: in particular, it must not outlive the called-upon
* instance.
*/
PYBIND11_NOINLINE value_and_holder instance::get_value_and_holder(const type_info *find_type /*= nullptr default in common.h*/, bool throw_if_missing /*= true in common.h*/) {
PYBIND11_NOINLINE value_and_holder
instance::get_value_and_holder(const type_info *find_type /*= nullptr default in common.h*/,
bool throw_if_missing /*= true in common.h*/) {
// Optimize common case:
if (!find_type || Py_TYPE(this) == find_type->type) {
return value_and_holder(this, find_type, 0, 0);
......@@ -390,9 +399,10 @@ PYBIND11_NOINLINE value_and_holder instance::get_value_and_holder(const type_inf
"type is not a pybind11 base of the given instance "
"(compile in debug mode for type details)");
#else
pybind11_fail("pybind11::detail::instance::get_value_and_holder: `" +
get_fully_qualified_tp_name(find_type->type) + "' is not a pybind11 base of the given `" +
get_fully_qualified_tp_name(Py_TYPE(this)) + "' instance");
pybind11_fail("pybind11::detail::instance::get_value_and_holder: `"
+ get_fully_qualified_tp_name(find_type->type)
+ "' is not a pybind11 base of the given `"
+ get_fully_qualified_tp_name(Py_TYPE(this)) + "' instance");
#endif
}
......@@ -406,16 +416,15 @@ PYBIND11_NOINLINE void instance::allocate_layout() {
"instance allocation failed: new instance has no pybind11-registered base types");
}
simple_layout =
n_types == 1 && tinfo.front()->holder_size_in_ptrs <= instance_simple_holder_in_ptrs();
simple_layout
= n_types == 1 && tinfo.front()->holder_size_in_ptrs <= instance_simple_holder_in_ptrs();
// Simple path: no python-side multiple inheritance, and a small-enough holder
if (simple_layout) {
simple_value_holder[0] = nullptr;
simple_holder_constructed = false;
simple_instance_registered = false;
}
else { // multiple base types or a too-large holder
} else { // multiple base types or a too-large holder
// Allocate space to hold: [v1*][h1][v2*][h2]...[bb...] where [vN*] is a value pointer,
// [hN] is the (uninitialized) holder instance for value N, and [bb...] is a set of bool
// values that tracks whether each associated holder has been initialized. Each [block] is
......@@ -441,10 +450,12 @@ PYBIND11_NOINLINE void instance::allocate_layout() {
}
#else
nonsimple.values_and_holders = (void **) PyMem_New(void *, space);
if (!nonsimple.values_and_holders) throw std::bad_alloc();
if (!nonsimple.values_and_holders)
throw std::bad_alloc();
std::memset(nonsimple.values_and_holders, 0, space * sizeof(void *));
#endif
nonsimple.status = reinterpret_cast<std::uint8_t *>(&nonsimple.values_and_holders[flags_at]);
nonsimple.status
= reinterpret_cast<std::uint8_t *>(&nonsimple.values_and_holders[flags_at]);
}
owned = true;
}
......@@ -501,17 +512,16 @@ PYBIND11_NOINLINE std::string error_string() {
PyFrameObject *frame = trace->tb_frame;
errorString += "\n\nAt:\n";
while (frame) {
#if PY_VERSION_HEX >= 0x03090000
# if PY_VERSION_HEX >= 0x03090000
PyCodeObject *f_code = PyFrame_GetCode(frame);
#else
# else
PyCodeObject *f_code = frame->f_code;
Py_INCREF(f_code);
#endif
# endif
int lineno = PyFrame_GetLineNumber(frame);
errorString +=
" " + handle(f_code->co_filename).cast<std::string>() +
"(" + std::to_string(lineno) + "): " +
handle(f_code->co_name).cast<std::string>() + "\n";
errorString += " " + handle(f_code->co_filename).cast<std::string>() + "("
+ std::to_string(lineno)
+ "): " + handle(f_code->co_name).cast<std::string>() + "\n";
frame = frame->f_back;
Py_DECREF(f_code);
}
......@@ -521,7 +531,7 @@ PYBIND11_NOINLINE std::string error_string() {
return errorString;
}
PYBIND11_NOINLINE handle get_object_handle(const void *ptr, const detail::type_info *type ) {
PYBIND11_NOINLINE handle get_object_handle(const void *ptr, const detail::type_info *type) {
auto &instances = get_internals().registered_instances;
auto range = instances.equal_range(ptr);
for (auto it = range.first; it != range.second; ++it) {
......@@ -540,9 +550,9 @@ inline PyThreadState *get_thread_state_unchecked() {
#elif PY_VERSION_HEX < 0x03000000
return _PyThreadState_Current;
#elif PY_VERSION_HEX < 0x03050000
return (PyThreadState*) _Py_atomic_load_relaxed(&_PyThreadState_Current);
return (PyThreadState *) _Py_atomic_load_relaxed(&_PyThreadState_Current);
#elif PY_VERSION_HEX < 0x03050200
return (PyThreadState*) _PyThreadState_Current.value;
return (PyThreadState *) _PyThreadState_Current.value;
#else
return _PyThreadState_UncheckedGet();
#endif
......@@ -560,11 +570,11 @@ public:
explicit type_caster_generic(const type_info *typeinfo)
: typeinfo(typeinfo), cpptype(typeinfo ? typeinfo->cpptype : nullptr) {}
bool load(handle src, bool convert) {
return load_impl<type_caster_generic>(src, convert);
}
bool load(handle src, bool convert) { return load_impl<type_caster_generic>(src, convert); }
PYBIND11_NOINLINE static handle cast(const void *_src, return_value_policy policy, handle parent,
PYBIND11_NOINLINE static handle cast(const void *_src,
return_value_policy policy,
handle parent,
const detail::type_info *tinfo,
void *(*copy_constructor)(const void *),
void *(*move_constructor)(const void *),
......@@ -610,8 +620,8 @@ public:
#else
std::string type_name(tinfo->cpptype->name());
detail::clean_type_id(type_name);
throw cast_error("return_value_policy = copy, but type " +
type_name + " is non-copyable!");
throw cast_error("return_value_policy = copy, but type " + type_name
+ " is non-copyable!");
#endif
}
wrapper->owned = true;
......@@ -630,8 +640,8 @@ public:
#else
std::string type_name(tinfo->cpptype->name());
detail::clean_type_id(type_name);
throw cast_error("return_value_policy = move, but type " +
type_name + " is neither movable nor copyable!");
throw cast_error("return_value_policy = move, but type " + type_name
+ " is neither movable nor copyable!");
#endif
}
wrapper->owned = true;
......@@ -661,16 +671,15 @@ public:
if (type->operator_new) {
vptr = type->operator_new(type->type_size);
} else {
#if defined(__cpp_aligned_new) && (!defined(_MSC_VER) || _MSC_VER >= 1912)
#if defined(__cpp_aligned_new) && (!defined(_MSC_VER) || _MSC_VER >= 1912)
if (type->type_align > __STDCPP_DEFAULT_NEW_ALIGNMENT__) {
vptr = ::operator new(type->type_size,
std::align_val_t(type->type_align));
vptr = ::operator new(type->type_size, std::align_val_t(type->type_align));
} else {
vptr = ::operator new(type->type_size);
}
#else
#else
vptr = ::operator new(type->type_size);
#endif
#endif
}
}
value = vptr;
......@@ -713,7 +722,8 @@ public:
}
type_info *foreign_typeinfo = reinterpret_borrow<capsule>(getattr(pytype, local_key));
// Only consider this foreign loader if actually foreign and is a loader of the correct cpp type
// Only consider this foreign loader if actually foreign and is a loader of the correct cpp
// type
if (foreign_typeinfo->module_local_load == &local_load
|| (cpptype && !same_type(*cpptype, *foreign_typeinfo->cpptype))) {
return false;
......@@ -764,21 +774,23 @@ public:
this_.load_value(reinterpret_cast<instance *>(src.ptr())->get_value_and_holder());
return true;
}
// Case 2b: the python type inherits from multiple C++ bases. Check the bases to see if
// we can find an exact match (or, for a simple C++ type, an inherited match); if so, we
// can safely reinterpret_cast to the relevant pointer.
// Case 2b: the python type inherits from multiple C++ bases. Check the bases to see
// if we can find an exact match (or, for a simple C++ type, an inherited match); if
// so, we can safely reinterpret_cast to the relevant pointer.
if (bases.size() > 1) {
for (auto *base : bases) {
if (no_cpp_mi ? PyType_IsSubtype(base->type, typeinfo->type) : base->type == typeinfo->type) {
this_.load_value(reinterpret_cast<instance *>(src.ptr())->get_value_and_holder(base));
if (no_cpp_mi ? PyType_IsSubtype(base->type, typeinfo->type)
: base->type == typeinfo->type) {
this_.load_value(
reinterpret_cast<instance *>(src.ptr())->get_value_and_holder(base));
return true;
}
}
}
// Case 2c: C++ multiple inheritance is involved and we couldn't find an exact type match
// in the registered bases, above, so try implicit casting (needed for proper C++ casting
// when MI is involved).
// Case 2c: C++ multiple inheritance is involved and we couldn't find an exact type
// match in the registered bases, above, so try implicit casting (needed for proper C++
// casting when MI is involved).
if (this_.try_implicit_casts(src, convert)) {
return true;
}
......@@ -824,12 +836,13 @@ public:
return false;
}
// Called to do type lookup and wrap the pointer and type in a pair when a dynamic_cast
// isn't needed or can't be used. If the type is unknown, sets the error and returns a pair
// with .second = nullptr. (p.first = nullptr is not an error: it becomes None).
PYBIND11_NOINLINE static std::pair<const void *, const type_info *> src_and_type(
const void *src, const std::type_info &cast_type, const std::type_info *rtti_type = nullptr) {
PYBIND11_NOINLINE static std::pair<const void *, const type_info *>
src_and_type(const void *src,
const std::type_info &cast_type,
const std::type_info *rtti_type = nullptr) {
if (auto *tpi = get_type_info(cast_type)) {
return {src, const_cast<const type_info *>(tpi)};
}
......@@ -855,8 +868,7 @@ public:
* `movable_cast_op_type` instead.
*/
template <typename T>
using cast_op_type =
conditional_t<std::is_pointer<remove_reference_t<T>>::value,
using cast_op_type = conditional_t<std::is_pointer<remove_reference_t<T>>::value,
typename std::add_pointer<intrinsic_t<T>>::type,
typename std::add_lvalue_reference<intrinsic_t<T>>::type>;
......@@ -868,8 +880,8 @@ using cast_op_type =
* These operator are automatically provided when using the PYBIND11_TYPE_CASTER macro.
*/
template <typename T>
using movable_cast_op_type =
conditional_t<std::is_pointer<typename std::remove_reference<T>::type>::value,
using movable_cast_op_type
= conditional_t<std::is_pointer<typename std::remove_reference<T>::type>::value,
typename std::add_pointer<intrinsic_t<T>>::type,
conditional_t<std::is_rvalue_reference<T>::value,
typename std::add_rvalue_reference<intrinsic_t<T>>::type,
......@@ -877,31 +889,41 @@ using movable_cast_op_type =
// std::is_copy_constructible isn't quite enough: it lets std::vector<T> (and similar) through when
// T is non-copyable, but code containing such a copy constructor fails to actually compile.
template <typename T, typename SFINAE = void> struct is_copy_constructible : std::is_copy_constructible<T> {};
template <typename T, typename SFINAE = void>
struct is_copy_constructible : std::is_copy_constructible<T> {};
// Specialization for types that appear to be copy constructible but also look like stl containers
// (we specifically check for: has `value_type` and `reference` with `reference = value_type&`): if
// so, copy constructability depends on whether the value_type is copy constructible.
template <typename Container> struct is_copy_constructible<Container, enable_if_t<all_of<
std::is_copy_constructible<Container>,
template <typename Container>
struct is_copy_constructible<
Container,
enable_if_t<
all_of<std::is_copy_constructible<Container>,
std::is_same<typename Container::value_type &, typename Container::reference>,
// Avoid infinite recursion
negation<std::is_same<Container, typename Container::value_type>>
>::value>> : is_copy_constructible<typename Container::value_type> {};
negation<std::is_same<Container, typename Container::value_type>>>::value>>
: is_copy_constructible<typename Container::value_type> {};
// Likewise for std::pair
// (after C++17 it is mandatory that the copy constructor not exist when the two types aren't themselves
// copy constructible, but this can not be relied upon when T1 or T2 are themselves containers).
template <typename T1, typename T2> struct is_copy_constructible<std::pair<T1, T2>>
// (after C++17 it is mandatory that the copy constructor not exist when the two types aren't
// themselves copy constructible, but this can not be relied upon when T1 or T2 are themselves
// containers).
template <typename T1, typename T2>
struct is_copy_constructible<std::pair<T1, T2>>
: all_of<is_copy_constructible<T1>, is_copy_constructible<T2>> {};
// The same problems arise with std::is_copy_assignable, so we use the same workaround.
template <typename T, typename SFINAE = void> struct is_copy_assignable : std::is_copy_assignable<T> {};
template <typename Container> struct is_copy_assignable<Container, enable_if_t<all_of<
std::is_copy_assignable<Container>,
std::is_same<typename Container::value_type &, typename Container::reference>
>::value>> : is_copy_assignable<typename Container::value_type> {};
template <typename T1, typename T2> struct is_copy_assignable<std::pair<T1, T2>>
template <typename T, typename SFINAE = void>
struct is_copy_assignable : std::is_copy_assignable<T> {};
template <typename Container>
struct is_copy_assignable<Container,
enable_if_t<all_of<std::is_copy_assignable<Container>,
std::is_same<typename Container::value_type &,
typename Container::reference>>::value>>
: is_copy_assignable<typename Container::value_type> {};
template <typename T1, typename T2>
struct is_copy_assignable<std::pair<T1, T2>>
: all_of<is_copy_assignable<T1>, is_copy_assignable<T2>> {};
PYBIND11_NAMESPACE_END(detail)
......@@ -928,16 +950,14 @@ PYBIND11_NAMESPACE_END(detail)
// std::enable_if. User provided specializations will always have higher priority than
// the default implementation and specialization provided in polymorphic_type_hook_base.
template <typename itype, typename SFINAE = void>
struct polymorphic_type_hook_base
{
static const void *get(const itype *src, const std::type_info*&) { return src; }
struct polymorphic_type_hook_base {
static const void *get(const itype *src, const std::type_info *&) { return src; }
};
template <typename itype>
struct polymorphic_type_hook_base<itype, detail::enable_if_t<std::is_polymorphic<itype>::value>>
{
static const void *get(const itype *src, const std::type_info*& type) {
struct polymorphic_type_hook_base<itype, detail::enable_if_t<std::is_polymorphic<itype>::value>> {
static const void *get(const itype *src, const std::type_info *&type) {
type = src ? &typeid(*src) : nullptr;
return dynamic_cast<const void*>(src);
return dynamic_cast<const void *>(src);
}
};
template <typename itype, typename SFINAE = void>
......@@ -946,14 +966,15 @@ struct polymorphic_type_hook : public polymorphic_type_hook_base<itype> {};
PYBIND11_NAMESPACE_BEGIN(detail)
/// Generic type caster for objects stored on the heap
template <typename type> class type_caster_base : public type_caster_generic {
template <typename type>
class type_caster_base : public type_caster_generic {
using itype = intrinsic_t<type>;
public:
static constexpr auto name = const_name<type>();
type_caster_base() : type_caster_base(typeid(type)) { }
explicit type_caster_base(const std::type_info &info) : type_caster_generic(info) { }
type_caster_base() : type_caster_base(typeid(type)) {}
explicit type_caster_base(const std::type_info &info) : type_caster_generic(info) {}
static handle cast(const itype &src, return_value_policy policy, handle parent) {
if (policy == return_value_policy::automatic
......@@ -987,31 +1008,39 @@ public:
return {vsrc, tpi};
}
}
// Otherwise we have either a nullptr, an `itype` pointer, or an unknown derived pointer, so
// don't do a cast
// Otherwise we have either a nullptr, an `itype` pointer, or an unknown derived pointer,
// so don't do a cast
return type_caster_generic::src_and_type(src, cast_type, instance_type);
}
static handle cast(const itype *src, return_value_policy policy, handle parent) {
auto st = src_and_type(src);
return type_caster_generic::cast(
st.first, policy, parent, st.second,
make_copy_constructor(src), make_move_constructor(src));
return type_caster_generic::cast(st.first,
policy,
parent,
st.second,
make_copy_constructor(src),
make_move_constructor(src));
}
static handle cast_holder(const itype *src, const void *holder) {
auto st = src_and_type(src);
return type_caster_generic::cast(
st.first, return_value_policy::take_ownership, {}, st.second,
nullptr, nullptr, holder);
return type_caster_generic::cast(st.first,
return_value_policy::take_ownership,
{},
st.second,
nullptr,
nullptr,
holder);
}
template <typename T> using cast_op_type = detail::cast_op_type<T>;
template <typename T>
using cast_op_type = detail::cast_op_type<T>;
// NOLINTNEXTLINE(google-explicit-constructor)
operator itype*() { return (type *) value; }
operator itype *() { return (type *) value; }
// NOLINTNEXTLINE(google-explicit-constructor)
operator itype&() {
operator itype &() {
if (!value) {
throw reference_cast_error();
}
......@@ -1019,20 +1048,20 @@ public:
}
protected:
using Constructor = void *(*)(const void *);
using Constructor = void *(*) (const void *);
/* Only enabled when the types are {copy,move}-constructible *and* when the type
does not have a private operator new implementation. A comma operator is used in the decltype
argument to apply SFINAE to the public copy/move constructors.*/
does not have a private operator new implementation. A comma operator is used in the
decltype argument to apply SFINAE to the public copy/move constructors.*/
template <typename T, typename = enable_if_t<is_copy_constructible<T>::value>>
static auto make_copy_constructor(const T *) -> decltype(new T(std::declval<const T>()), Constructor{}) {
return [](const void *arg) -> void * {
return new T(*reinterpret_cast<const T *>(arg));
};
static auto make_copy_constructor(const T *)
-> decltype(new T(std::declval<const T>()), Constructor{}) {
return [](const void *arg) -> void * { return new T(*reinterpret_cast<const T *>(arg)); };
}
template <typename T, typename = enable_if_t<std::is_move_constructible<T>::value>>
static auto make_move_constructor(const T *) -> decltype(new T(std::declval<T&&>()), Constructor{}) {
static auto make_move_constructor(const T *)
-> decltype(new T(std::declval<T &&>()), Constructor{}) {
return [](const void *arg) -> void * {
return new T(std::move(*const_cast<T *>(reinterpret_cast<const T *>(arg))));
};
......
......@@ -13,7 +13,7 @@
#include <cstdlib>
#if defined(__GNUG__)
#include <cxxabi.h>
# include <cxxabi.h>
#endif
#include "common.h"
......@@ -34,8 +34,8 @@ inline void erase_all(std::string &string, const std::string &search) {
PYBIND11_NOINLINE 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 };
std::unique_ptr<char, void (*)(void *)> res{
abi::__cxa_demangle(name.c_str(), nullptr, nullptr, &status), std::free};
if (status == 0) {
name = res.get();
}
......@@ -49,7 +49,8 @@ PYBIND11_NOINLINE void clean_type_id(std::string &name) {
PYBIND11_NAMESPACE_END(detail)
/// Return a string representation of a C++ type
template <typename T> static std::string type_id() {
template <typename T>
static std::string type_id() {
std::string name(typeid(T).name());
detail::clean_type_id(name);
return name;
......
......@@ -24,7 +24,7 @@
// it is probably best to keep this around indefinitely.
#if defined(_MSC_VER)
# pragma warning(push)
# pragma warning(disable: 4127) // C4127: conditional expression is constant
# pragma warning(disable : 4127) // C4127: conditional expression is constant
#endif
#include <Eigen/Core>
......@@ -37,43 +37,53 @@
// Eigen prior to 3.2.7 doesn't have proper move constructors--but worse, some classes get implicit
// move constructors that break things. We could detect this an explicitly copy, but an extra copy
// of matrices seems highly undesirable.
static_assert(EIGEN_VERSION_AT_LEAST(3,2,7), "Eigen support in pybind11 requires Eigen >= 3.2.7");
static_assert(EIGEN_VERSION_AT_LEAST(3, 2, 7),
"Eigen support in pybind11 requires Eigen >= 3.2.7");
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
// Provide a convenience alias for easier pass-by-ref usage with fully dynamic strides:
using EigenDStride = Eigen::Stride<Eigen::Dynamic, Eigen::Dynamic>;
template <typename MatrixType> using EigenDRef = Eigen::Ref<MatrixType, 0, EigenDStride>;
template <typename MatrixType> using EigenDMap = Eigen::Map<MatrixType, 0, EigenDStride>;
template <typename MatrixType>
using EigenDRef = Eigen::Ref<MatrixType, 0, EigenDStride>;
template <typename MatrixType>
using EigenDMap = Eigen::Map<MatrixType, 0, EigenDStride>;
PYBIND11_NAMESPACE_BEGIN(detail)
#if EIGEN_VERSION_AT_LEAST(3,3,0)
#if EIGEN_VERSION_AT_LEAST(3, 3, 0)
using EigenIndex = Eigen::Index;
template<typename Scalar, int Flags, typename StorageIndex>
template <typename Scalar, int Flags, typename StorageIndex>
using EigenMapSparseMatrix = Eigen::Map<Eigen::SparseMatrix<Scalar, Flags, StorageIndex>>;
#else
using EigenIndex = EIGEN_DEFAULT_DENSE_INDEX_TYPE;
template<typename Scalar, int Flags, typename StorageIndex>
template <typename Scalar, int Flags, typename StorageIndex>
using EigenMapSparseMatrix = Eigen::MappedSparseMatrix<Scalar, Flags, StorageIndex>;
#endif
// Matches Eigen::Map, Eigen::Ref, blocks, etc:
template <typename T> using is_eigen_dense_map = all_of<is_template_base_of<Eigen::DenseBase, T>, std::is_base_of<Eigen::MapBase<T, Eigen::ReadOnlyAccessors>, T>>;
template <typename T> using is_eigen_mutable_map = std::is_base_of<Eigen::MapBase<T, Eigen::WriteAccessors>, T>;
template <typename T> using is_eigen_dense_plain = all_of<negation<is_eigen_dense_map<T>>, is_template_base_of<Eigen::PlainObjectBase, T>>;
template <typename T> using is_eigen_sparse = is_template_base_of<Eigen::SparseMatrixBase, T>;
template <typename T>
using is_eigen_dense_map = all_of<is_template_base_of<Eigen::DenseBase, T>,
std::is_base_of<Eigen::MapBase<T, Eigen::ReadOnlyAccessors>, T>>;
template <typename T>
using is_eigen_mutable_map = std::is_base_of<Eigen::MapBase<T, Eigen::WriteAccessors>, T>;
template <typename T>
using is_eigen_dense_plain
= all_of<negation<is_eigen_dense_map<T>>, is_template_base_of<Eigen::PlainObjectBase, T>>;
template <typename T>
using is_eigen_sparse = is_template_base_of<Eigen::SparseMatrixBase, T>;
// Test for objects inheriting from EigenBase<Derived> that aren't captured by the above. This
// basically covers anything that can be assigned to a dense matrix but that don't have a typical
// matrix data layout that can be copied from their .data(). For example, DiagonalMatrix and
// SelfAdjointView fall into this category.
template <typename T> using is_eigen_other = all_of<
is_template_base_of<Eigen::EigenBase, T>,
negation<any_of<is_eigen_dense_map<T>, is_eigen_dense_plain<T>, is_eigen_sparse<T>>>
>;
template <typename T>
using is_eigen_other
= all_of<is_template_base_of<Eigen::EigenBase, T>,
negation<any_of<is_eigen_dense_map<T>, is_eigen_dense_plain<T>, is_eigen_sparse<T>>>>;
// Captures numpy/eigen conformability status (returned by EigenProps::conformable()):
template <bool EigenRowMajor> struct EigenConformable {
template <bool EigenRowMajor>
struct EigenConformable {
bool conformable = false;
EigenIndex rows = 0, cols = 0;
EigenDStride stride{0, 0}; // Only valid if negativestrides is false!
......@@ -82,63 +92,76 @@ template <bool EigenRowMajor> struct EigenConformable {
// NOLINTNEXTLINE(google-explicit-constructor)
EigenConformable(bool fits = false) : conformable{fits} {}
// Matrix type:
EigenConformable(EigenIndex r, EigenIndex c,
EigenIndex rstride, EigenIndex cstride) :
conformable{true}, rows{r}, cols{c},
//TODO: when Eigen bug #747 is fixed, remove the tests for non-negativity. http://eigen.tuxfamily.org/bz/show_bug.cgi?id=747
stride{EigenRowMajor ? (rstride > 0 ? rstride : 0) : (cstride > 0 ? cstride : 0) /* outer stride */,
EigenRowMajor ? (cstride > 0 ? cstride : 0) : (rstride > 0 ? rstride : 0) /* inner stride */ },
negativestrides{rstride < 0 || cstride < 0} {
}
EigenConformable(EigenIndex r, EigenIndex c, EigenIndex rstride, EigenIndex cstride)
: conformable{true}, rows{r}, cols{c},
// TODO: when Eigen bug #747 is fixed, remove the tests for non-negativity.
// http://eigen.tuxfamily.org/bz/show_bug.cgi?id=747
stride{EigenRowMajor ? (rstride > 0 ? rstride : 0)
: (cstride > 0 ? cstride : 0) /* outer stride */,
EigenRowMajor ? (cstride > 0 ? cstride : 0)
: (rstride > 0 ? rstride : 0) /* inner stride */},
negativestrides{rstride < 0 || cstride < 0} {}
// Vector type:
EigenConformable(EigenIndex r, EigenIndex c, EigenIndex stride)
: EigenConformable(r, c, r == 1 ? c*stride : stride, c == 1 ? r : r*stride) {}
: EigenConformable(r, c, r == 1 ? c * stride : stride, c == 1 ? r : r * stride) {}
template <typename props> bool stride_compatible() const {
template <typename props>
bool stride_compatible() const {
// To have compatible strides, we need (on both dimensions) one of fully dynamic strides,
// matching strides, or a dimension size of 1 (in which case the stride value is irrelevant)
return
!negativestrides &&
(props::inner_stride == Eigen::Dynamic || props::inner_stride == stride.inner() ||
(EigenRowMajor ? cols : rows) == 1) &&
(props::outer_stride == Eigen::Dynamic || props::outer_stride == stride.outer() ||
(EigenRowMajor ? rows : cols) == 1);
// matching strides, or a dimension size of 1 (in which case the stride value is
// irrelevant)
return !negativestrides
&& (props::inner_stride == Eigen::Dynamic || props::inner_stride == stride.inner()
|| (EigenRowMajor ? cols : rows) == 1)
&& (props::outer_stride == Eigen::Dynamic || props::outer_stride == stride.outer()
|| (EigenRowMajor ? rows : cols) == 1);
}
// NOLINTNEXTLINE(google-explicit-constructor)
operator bool() const { return conformable; }
};
template <typename Type> struct eigen_extract_stride { using type = Type; };
template <typename Type>
struct eigen_extract_stride {
using type = Type;
};
template <typename PlainObjectType, int MapOptions, typename StrideType>
struct eigen_extract_stride<Eigen::Map<PlainObjectType, MapOptions, StrideType>> { using type = StrideType; };
struct eigen_extract_stride<Eigen::Map<PlainObjectType, MapOptions, StrideType>> {
using type = StrideType;
};
template <typename PlainObjectType, int Options, typename StrideType>
struct eigen_extract_stride<Eigen::Ref<PlainObjectType, Options, StrideType>> { using type = StrideType; };
struct eigen_extract_stride<Eigen::Ref<PlainObjectType, Options, StrideType>> {
using type = StrideType;
};
// Helper struct for extracting information from an Eigen type
template <typename Type_> struct EigenProps {
template <typename Type_>
struct EigenProps {
using Type = Type_;
using Scalar = typename Type::Scalar;
using StrideType = typename eigen_extract_stride<Type>::type;
static constexpr EigenIndex
rows = Type::RowsAtCompileTime,
cols = Type::ColsAtCompileTime,
static constexpr EigenIndex rows = Type::RowsAtCompileTime, cols = Type::ColsAtCompileTime,
size = Type::SizeAtCompileTime;
static constexpr bool
row_major = Type::IsRowMajor,
vector = Type::IsVectorAtCompileTime, // At least one dimension has fixed size 1
fixed_rows = rows != Eigen::Dynamic,
fixed_cols = cols != Eigen::Dynamic,
static constexpr bool row_major = Type::IsRowMajor,
vector
= Type::IsVectorAtCompileTime, // At least one dimension has fixed size 1
fixed_rows = rows != Eigen::Dynamic, fixed_cols = cols != Eigen::Dynamic,
fixed = size != Eigen::Dynamic, // Fully-fixed size
dynamic = !fixed_rows && !fixed_cols; // Fully-dynamic size
template <EigenIndex i, EigenIndex ifzero> using if_zero = std::integral_constant<EigenIndex, i == 0 ? ifzero : i>;
static constexpr EigenIndex inner_stride = if_zero<StrideType::InnerStrideAtCompileTime, 1>::value,
outer_stride = if_zero<StrideType::OuterStrideAtCompileTime,
vector ? size : row_major ? cols : rows>::value;
static constexpr bool dynamic_stride = inner_stride == Eigen::Dynamic && outer_stride == Eigen::Dynamic;
static constexpr bool requires_row_major = !dynamic_stride && !vector && (row_major ? inner_stride : outer_stride) == 1;
static constexpr bool requires_col_major = !dynamic_stride && !vector && (row_major ? outer_stride : inner_stride) == 1;
template <EigenIndex i, EigenIndex ifzero>
using if_zero = std::integral_constant<EigenIndex, i == 0 ? ifzero : i>;
static constexpr EigenIndex inner_stride
= if_zero<StrideType::InnerStrideAtCompileTime, 1>::value,
outer_stride = if_zero < StrideType::OuterStrideAtCompileTime,
vector ? size
: row_major ? cols
: rows > ::value;
static constexpr bool dynamic_stride
= inner_stride == Eigen::Dynamic && outer_stride == Eigen::Dynamic;
static constexpr bool requires_row_major
= !dynamic_stride && !vector && (row_major ? inner_stride : outer_stride) == 1;
static constexpr bool requires_col_major
= !dynamic_stride && !vector && (row_major ? outer_stride : inner_stride) == 1;
// Takes an input array and determines whether we can make it fit into the Eigen type. If
// the array is a vector, we attempt to fit it into either an Eigen 1xN or Nx1 vector
......@@ -151,9 +174,7 @@ template <typename Type_> struct EigenProps {
if (dims == 2) { // Matrix type: require exact match (or dynamic)
EigenIndex
np_rows = a.shape(0),
np_cols = a.shape(1),
EigenIndex np_rows = a.shape(0), np_cols = a.shape(1),
np_rstride = a.strides(0) / static_cast<ssize_t>(sizeof(Scalar)),
np_cstride = a.strides(1) / static_cast<ssize_t>(sizeof(Scalar));
if ((PYBIND11_SILENCE_MSVC_C4127(fixed_rows) && np_rows != rows)
......@@ -164,8 +185,8 @@ template <typename Type_> struct EigenProps {
return {np_rows, np_cols, np_rstride, np_cstride};
}
// Otherwise we're storing an n-vector. Only one of the strides will be used, but whichever
// is used, we want the (single) numpy stride value.
// Otherwise we're storing an n-vector. Only one of the strides will be used, but
// whichever is used, we want the (single) numpy stride value.
const EigenIndex n = a.shape(0),
stride = a.strides(0) / static_cast<ssize_t>(sizeof(Scalar));
......@@ -193,35 +214,38 @@ template <typename Type_> struct EigenProps {
return {n, 1, stride};
}
static constexpr bool show_writeable = is_eigen_dense_map<Type>::value && is_eigen_mutable_map<Type>::value;
static constexpr bool show_writeable
= is_eigen_dense_map<Type>::value && is_eigen_mutable_map<Type>::value;
static constexpr bool show_order = is_eigen_dense_map<Type>::value;
static constexpr bool show_c_contiguous = show_order && requires_row_major;
static constexpr bool show_f_contiguous = !show_c_contiguous && show_order && requires_col_major;
static constexpr auto descriptor =
const_name("numpy.ndarray[") + npy_format_descriptor<Scalar>::name +
const_name("[") + const_name<fixed_rows>(const_name<(size_t) rows>(), const_name("m")) +
const_name(", ") + const_name<fixed_cols>(const_name<(size_t) cols>(), const_name("n")) +
const_name("]") +
// For a reference type (e.g. Ref<MatrixXd>) we have other constraints that might need to be
// satisfied: writeable=True (for a mutable reference), and, depending on the map's stride
// options, possibly f_contiguous or c_contiguous. We include them in the descriptor output
// to provide some hint as to why a TypeError is occurring (otherwise it can be confusing to
// see that a function accepts a 'numpy.ndarray[float64[3,2]]' and an error message that you
// *gave* a numpy.ndarray of the right type and dimensions.
const_name<show_writeable>(", flags.writeable", "") +
const_name<show_c_contiguous>(", flags.c_contiguous", "") +
const_name<show_f_contiguous>(", flags.f_contiguous", "") +
const_name("]");
static constexpr bool show_f_contiguous
= !show_c_contiguous && show_order && requires_col_major;
static constexpr auto descriptor
= const_name("numpy.ndarray[") + npy_format_descriptor<Scalar>::name + const_name("[")
+ const_name<fixed_rows>(const_name<(size_t) rows>(), const_name("m")) + const_name(", ")
+ const_name<fixed_cols>(const_name<(size_t) cols>(), const_name("n")) + const_name("]")
+
// For a reference type (e.g. Ref<MatrixXd>) we have other constraints that might need to
// be satisfied: writeable=True (for a mutable reference), and, depending on the map's
// stride options, possibly f_contiguous or c_contiguous. We include them in the
// descriptor output to provide some hint as to why a TypeError is occurring (otherwise
// it can be confusing to see that a function accepts a 'numpy.ndarray[float64[3,2]]' and
// an error message that you *gave* a numpy.ndarray of the right type and dimensions.
const_name<show_writeable>(", flags.writeable", "")
+ const_name<show_c_contiguous>(", flags.c_contiguous", "")
+ const_name<show_f_contiguous>(", flags.f_contiguous", "") + const_name("]");
};
// Casts an Eigen type to numpy array. If given a base, the numpy array references the src data,
// otherwise it'll make a copy. writeable lets you turn off the writeable flag for the array.
template <typename props> handle eigen_array_cast(typename props::Type const &src, handle base = handle(), bool writeable = true) {
template <typename props>
handle
eigen_array_cast(typename props::Type const &src, handle base = handle(), bool writeable = true) {
constexpr ssize_t elem_size = sizeof(typename props::Scalar);
array a;
if (props::vector) {
a = array({ src.size() }, { elem_size * src.innerStride() }, src.data(), base);
a = array({src.size()}, {elem_size * src.innerStride()}, src.data(), base);
} else {
a = array({src.rows(), src.cols()},
{elem_size * src.rowStride(), elem_size * src.colStride()},
......@@ -247,10 +271,10 @@ handle eigen_ref_array(Type &src, handle parent = none()) {
return eigen_array_cast<props>(src, parent, !std::is_const<Type>::value);
}
// Takes a pointer to some dense, plain Eigen type, builds a capsule around it, then returns a numpy
// array that references the encapsulated data with a python-side reference to the capsule to tie
// its destruction to that of any dependent python objects. Const-ness is determined by whether or
// not the Type of the pointer given is const.
// Takes a pointer to some dense, plain Eigen type, builds a capsule around it, then returns a
// numpy array that references the encapsulated data with a python-side reference to the capsule to
// tie its destruction to that of any dependent python objects. Const-ness is determined by
// whether or not the Type of the pointer given is const.
template <typename props, typename Type, typename = enable_if_t<is_eigen_dense_plain<Type>::value>>
handle eigen_encapsulate(Type *src) {
capsule base(src, [](void *o) { delete static_cast<Type *>(o); });
......@@ -259,7 +283,7 @@ handle eigen_encapsulate(Type *src) {
// Type caster for regular, dense matrix types (e.g. MatrixXd), but not maps/refs/etc. of dense
// types.
template<typename Type>
template <typename Type>
struct type_caster<Type, enable_if_t<is_eigen_dense_plain<Type>::value>> {
using Scalar = typename Type::Scalar;
using props = EigenProps<Type>;
......@@ -307,7 +331,6 @@ struct type_caster<Type, enable_if_t<is_eigen_dense_plain<Type>::value>> {
}
private:
// Cast implementation
template <typename CType>
static handle cast_impl(CType *src, return_value_policy policy, handle parent) {
......@@ -330,7 +353,6 @@ private:
}
public:
// Normal returned non-reference, non-const value:
static handle cast(Type &&src, return_value_policy /* policy */, handle parent) {
return cast_impl(&src, return_value_policy::move, parent);
......@@ -367,30 +389,31 @@ public:
static constexpr auto name = props::descriptor;
// NOLINTNEXTLINE(google-explicit-constructor)
operator Type*() { return &value; }
operator Type *() { return &value; }
// NOLINTNEXTLINE(google-explicit-constructor)
operator Type&() { return value; }
operator Type &() { return value; }
// NOLINTNEXTLINE(google-explicit-constructor)
operator Type&&() && { return std::move(value); }
template <typename T> using cast_op_type = movable_cast_op_type<T>;
operator Type &&() && { return std::move(value); }
template <typename T>
using cast_op_type = movable_cast_op_type<T>;
private:
Type value;
};
// Base class for casting reference/map/block/etc. objects back to python.
template <typename MapType> struct eigen_map_caster {
template <typename MapType>
struct eigen_map_caster {
private:
using props = EigenProps<MapType>;
public:
// Directly referencing a ref/map's data is a bit dangerous (whatever the map/ref points to has
// to stay around), but we'll allow it under the assumption that you know what you're doing (and
// have an appropriate keep_alive in place). We return a numpy array pointing directly at the
// ref's data (The numpy array ends up read-only if the ref was to a const matrix type.) Note
// that this means you need to ensure you don't destroy the object in some other way (e.g. with
// an appropriate keep_alive, or with a reference to a statically allocated matrix).
// to stay around), but we'll allow it under the assumption that you know what you're doing
// (and have an appropriate keep_alive in place). We return a numpy array pointing directly at
// the ref's data (The numpy array ends up read-only if the ref was to a const matrix type.)
// Note that this means you need to ensure you don't destroy the object in some other way (e.g.
// with an appropriate keep_alive, or with a reference to a statically allocated matrix).
static handle cast(const MapType &src, return_value_policy policy, handle parent) {
switch (policy) {
case return_value_policy::copy:
......@@ -414,43 +437,50 @@ public:
// you end up here if you try anyway.
bool load(handle, bool) = delete;
operator MapType() = delete;
template <typename> using cast_op_type = MapType;
template <typename>
using cast_op_type = MapType;
};
// We can return any map-like object (but can only load Refs, specialized next):
template <typename Type> struct type_caster<Type, enable_if_t<is_eigen_dense_map<Type>::value>>
: eigen_map_caster<Type> {};
template <typename Type>
struct type_caster<Type, enable_if_t<is_eigen_dense_map<Type>::value>> : eigen_map_caster<Type> {};
// Loader for Ref<...> arguments. See the documentation for info on how to make this work without
// copying (it requires some extra effort in many cases).
template <typename PlainObjectType, typename StrideType>
struct type_caster<
Eigen::Ref<PlainObjectType, 0, StrideType>,
enable_if_t<is_eigen_dense_map<Eigen::Ref<PlainObjectType, 0, StrideType>>::value>
> : public eigen_map_caster<Eigen::Ref<PlainObjectType, 0, StrideType>> {
enable_if_t<is_eigen_dense_map<Eigen::Ref<PlainObjectType, 0, StrideType>>::value>>
: public eigen_map_caster<Eigen::Ref<PlainObjectType, 0, StrideType>> {
private:
using Type = Eigen::Ref<PlainObjectType, 0, StrideType>;
using props = EigenProps<Type>;
using Scalar = typename props::Scalar;
using MapType = Eigen::Map<PlainObjectType, 0, StrideType>;
using Array = array_t<Scalar, array::forcecast |
((props::row_major ? props::inner_stride : props::outer_stride) == 1 ? array::c_style :
(props::row_major ? props::outer_stride : props::inner_stride) == 1 ? array::f_style : 0)>;
using Array
= array_t<Scalar,
array::forcecast
| ((props::row_major ? props::inner_stride : props::outer_stride) == 1
? array::c_style
: (props::row_major ? props::outer_stride : props::inner_stride) == 1
? array::f_style
: 0)>;
static constexpr bool need_writeable = is_eigen_mutable_map<Type>::value;
// Delay construction (these have no default constructor)
std::unique_ptr<MapType> map;
std::unique_ptr<Type> ref;
// Our array. When possible, this is just a numpy array pointing to the source data, but
// sometimes we can't avoid copying (e.g. input is not a numpy array at all, has an incompatible
// layout, or is an array of a type that needs to be converted). Using a numpy temporary
// (rather than an Eigen temporary) saves an extra copy when we need both type conversion and
// storage order conversion. (Note that we refuse to use this temporary copy when loading an
// argument for a Ref<M> with M non-const, i.e. a read-write reference).
// sometimes we can't avoid copying (e.g. input is not a numpy array at all, has an
// incompatible layout, or is an array of a type that needs to be converted). Using a numpy
// temporary (rather than an Eigen temporary) saves an extra copy when we need both type
// conversion and storage order conversion. (Note that we refuse to use this temporary copy
// when loading an argument for a Ref<M> with M non-const, i.e. a read-write reference).
Array copy_or_ref;
public:
bool load(handle src, bool convert) {
// First check whether what we have is already an array of the right type. If not, we can't
// avoid a copy (because the copy is also going to do type conversion).
// First check whether what we have is already an array of the right type. If not, we
// can't avoid a copy (because the copy is also going to do type conversion).
bool need_copy = !isinstance<Array>(src);
EigenConformable<props::row_major> fits;
......@@ -469,8 +499,7 @@ public:
} else {
copy_or_ref = std::move(aref);
}
}
else {
} else {
need_copy = true;
}
}
......@@ -496,54 +525,76 @@ public:
}
ref.reset();
map.reset(new MapType(data(copy_or_ref), fits.rows, fits.cols, make_stride(fits.stride.outer(), fits.stride.inner())));
map.reset(new MapType(data(copy_or_ref),
fits.rows,
fits.cols,
make_stride(fits.stride.outer(), fits.stride.inner())));
ref.reset(new Type(*map));
return true;
}
// NOLINTNEXTLINE(google-explicit-constructor)
operator Type*() { return ref.get(); }
operator Type *() { return ref.get(); }
// NOLINTNEXTLINE(google-explicit-constructor)
operator Type&() { return *ref; }
template <typename _T> using cast_op_type = pybind11::detail::cast_op_type<_T>;
operator Type &() { return *ref; }
template <typename _T>
using cast_op_type = pybind11::detail::cast_op_type<_T>;
private:
template <typename T = Type, enable_if_t<is_eigen_mutable_map<T>::value, int> = 0>
Scalar *data(Array &a) { return a.mutable_data(); }
Scalar *data(Array &a) {
return a.mutable_data();
}
template <typename T = Type, enable_if_t<!is_eigen_mutable_map<T>::value, int> = 0>
const Scalar *data(Array &a) { return a.data(); }
const Scalar *data(Array &a) {
return a.data();
}
// Attempt to figure out a constructor of `Stride` that will work.
// If both strides are fixed, use a default constructor:
template <typename S> using stride_ctor_default = bool_constant<
S::InnerStrideAtCompileTime != Eigen::Dynamic && S::OuterStrideAtCompileTime != Eigen::Dynamic &&
std::is_default_constructible<S>::value>;
template <typename S>
using stride_ctor_default = bool_constant<S::InnerStrideAtCompileTime != Eigen::Dynamic
&& S::OuterStrideAtCompileTime != Eigen::Dynamic
&& std::is_default_constructible<S>::value>;
// Otherwise, if there is a two-index constructor, assume it is (outer,inner) like
// Eigen::Stride, and use it:
template <typename S> using stride_ctor_dual = bool_constant<
!stride_ctor_default<S>::value && std::is_constructible<S, EigenIndex, EigenIndex>::value>;
template <typename S>
using stride_ctor_dual
= bool_constant<!stride_ctor_default<S>::value
&& std::is_constructible<S, EigenIndex, EigenIndex>::value>;
// Otherwise, if there is a one-index constructor, and just one of the strides is dynamic, use
// it (passing whichever stride is dynamic).
template <typename S> using stride_ctor_outer = bool_constant<
!any_of<stride_ctor_default<S>, stride_ctor_dual<S>>::value &&
S::OuterStrideAtCompileTime == Eigen::Dynamic && S::InnerStrideAtCompileTime != Eigen::Dynamic &&
std::is_constructible<S, EigenIndex>::value>;
template <typename S> using stride_ctor_inner = bool_constant<
!any_of<stride_ctor_default<S>, stride_ctor_dual<S>>::value &&
S::InnerStrideAtCompileTime == Eigen::Dynamic && S::OuterStrideAtCompileTime != Eigen::Dynamic &&
std::is_constructible<S, EigenIndex>::value>;
template <typename S>
using stride_ctor_outer
= bool_constant<!any_of<stride_ctor_default<S>, stride_ctor_dual<S>>::value
&& S::OuterStrideAtCompileTime == Eigen::Dynamic
&& S::InnerStrideAtCompileTime != Eigen::Dynamic
&& std::is_constructible<S, EigenIndex>::value>;
template <typename S>
using stride_ctor_inner
= bool_constant<!any_of<stride_ctor_default<S>, stride_ctor_dual<S>>::value
&& S::InnerStrideAtCompileTime == Eigen::Dynamic
&& S::OuterStrideAtCompileTime != Eigen::Dynamic
&& std::is_constructible<S, EigenIndex>::value>;
template <typename S = StrideType, enable_if_t<stride_ctor_default<S>::value, int> = 0>
static S make_stride(EigenIndex, EigenIndex) { return S(); }
static S make_stride(EigenIndex, EigenIndex) {
return S();
}
template <typename S = StrideType, enable_if_t<stride_ctor_dual<S>::value, int> = 0>
static S make_stride(EigenIndex outer, EigenIndex inner) { return S(outer, inner); }
static S make_stride(EigenIndex outer, EigenIndex inner) {
return S(outer, inner);
}
template <typename S = StrideType, enable_if_t<stride_ctor_outer<S>::value, int> = 0>
static S make_stride(EigenIndex outer, EigenIndex) { return S(outer); }
static S make_stride(EigenIndex outer, EigenIndex) {
return S(outer);
}
template <typename S = StrideType, enable_if_t<stride_ctor_inner<S>::value, int> = 0>
static S make_stride(EigenIndex, EigenIndex inner) { return S(inner); }
static S make_stride(EigenIndex, EigenIndex inner) {
return S(inner);
}
};
// type_caster for special matrix types (e.g. DiagonalMatrix), which are EigenBase, but not
......@@ -553,14 +604,18 @@ private:
template <typename Type>
struct type_caster<Type, enable_if_t<is_eigen_other<Type>::value>> {
protected:
using Matrix = Eigen::Matrix<typename Type::Scalar, Type::RowsAtCompileTime, Type::ColsAtCompileTime>;
using Matrix
= Eigen::Matrix<typename Type::Scalar, Type::RowsAtCompileTime, Type::ColsAtCompileTime>;
using props = EigenProps<Matrix>;
public:
static handle cast(const Type &src, return_value_policy /* policy */, handle /* parent */) {
handle h = eigen_encapsulate<props>(new Matrix(src));
return h;
}
static handle cast(const Type *src, return_value_policy policy, handle parent) { return cast(*src, policy, parent); }
static handle cast(const Type *src, return_value_policy policy, handle parent) {
return cast(*src, policy, parent);
}
static constexpr auto name = props::descriptor;
......@@ -569,10 +624,11 @@ public:
// you end up here if you try anyway.
bool load(handle, bool) = delete;
operator Type() = delete;
template <typename> using cast_op_type = Type;
template <typename>
using cast_op_type = Type;
};
template<typename Type>
template <typename Type>
struct type_caster<Type, enable_if_t<is_eigen_sparse<Type>::value>> {
using Scalar = typename Type::Scalar;
using StorageIndex = remove_reference_t<decltype(*std::declval<Type>().outerIndexPtr())>;
......@@ -586,8 +642,7 @@ struct type_caster<Type, enable_if_t<is_eigen_sparse<Type>::value>> {
auto obj = reinterpret_borrow<object>(src);
object sparse_module = module_::import("scipy.sparse");
object matrix_type = sparse_module.attr(
rowMajor ? "csr_matrix" : "csc_matrix");
object matrix_type = sparse_module.attr(rowMajor ? "csr_matrix" : "csc_matrix");
if (!type::handle_of(obj).is(matrix_type)) {
try {
......@@ -608,31 +663,35 @@ struct type_caster<Type, enable_if_t<is_eigen_sparse<Type>::value>> {
}
value = EigenMapSparseMatrix<Scalar,
Type::Flags & (Eigen::RowMajor | Eigen::ColMajor),
StorageIndex>(
shape[0].cast<Index>(), shape[1].cast<Index>(), nnz,
outerIndices.mutable_data(), innerIndices.mutable_data(), values.mutable_data());
Type::Flags &(Eigen::RowMajor | Eigen::ColMajor),
StorageIndex>(shape[0].cast<Index>(),
shape[1].cast<Index>(),
nnz,
outerIndices.mutable_data(),
innerIndices.mutable_data(),
values.mutable_data());
return true;
}
static handle cast(const Type &src, return_value_policy /* policy */, handle /* parent */) {
const_cast<Type&>(src).makeCompressed();
const_cast<Type &>(src).makeCompressed();
object matrix_type = module_::import("scipy.sparse").attr(
rowMajor ? "csr_matrix" : "csc_matrix");
object matrix_type
= module_::import("scipy.sparse").attr(rowMajor ? "csr_matrix" : "csc_matrix");
array data(src.nonZeros(), src.valuePtr());
array outerIndices((rowMajor ? src.rows() : src.cols()) + 1, src.outerIndexPtr());
array innerIndices(src.nonZeros(), src.innerIndexPtr());
return matrix_type(
std::make_tuple(data, innerIndices, outerIndices),
std::make_pair(src.rows(), src.cols())
).release();
return matrix_type(std::make_tuple(data, innerIndices, outerIndices),
std::make_pair(src.rows(), src.cols()))
.release();
}
PYBIND11_TYPE_CASTER(Type, const_name<(Type::IsRowMajor) != 0>("scipy.sparse.csr_matrix[", "scipy.sparse.csc_matrix[")
PYBIND11_TYPE_CASTER(Type,
const_name<(Type::IsRowMajor) != 0>("scipy.sparse.csr_matrix[",
"scipy.sparse.csc_matrix[")
+ npy_format_descriptor<Scalar>::name + const_name("]"));
};
......
......@@ -22,15 +22,11 @@
#if PY_MAJOR_VERSION >= 3
# define PYBIND11_EMBEDDED_MODULE_IMPL(name) \
extern "C" PyObject *pybind11_init_impl_##name(); \
extern "C" PyObject *pybind11_init_impl_##name() { \
return pybind11_init_wrapper_##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(); \
extern "C" void pybind11_init_impl_##name() { \
pybind11_init_wrapper_##name(); \
}
extern "C" void pybind11_init_impl_##name() { pybind11_init_wrapper_##name(); }
#endif
/** \rst
......@@ -72,7 +68,7 @@ PYBIND11_NAMESPACE_BEGIN(detail)
/// 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 (*)();
#endif
......@@ -106,10 +102,10 @@ inline wchar_t *widen_chars(const char *safe_arg) {
wchar_t *widened_arg = nullptr;
// warning C4996: 'mbstowcs': This function or variable may be unsafe.
#if defined(_MSC_VER)
#pragma warning(push)
#pragma warning(disable:4996)
#endif
# if defined(_MSC_VER)
# pragma warning(push)
# pragma warning(disable : 4996)
# endif
# if defined(HAVE_BROKEN_MBSTOWCS) && HAVE_BROKEN_MBSTOWCS
size_t count = std::strlen(safe_arg);
......@@ -121,9 +117,9 @@ inline wchar_t *widen_chars(const char *safe_arg) {
std::mbstowcs(widened_arg, safe_arg, count + 1);
}
#if defined(_MSC_VER)
#pragma warning(pop)
#endif
# if defined(_MSC_VER)
# pragma warning(pop)
# endif
#endif
return widened_arg;
......
......@@ -11,24 +11,24 @@
#pragma once
#include <utility>
#include "pybind11.h"
#include <utility>
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
PYBIND11_NAMESPACE_BEGIN(detail)
inline void ensure_builtins_in_globals(object &global) {
#if defined(PYPY_VERSION) || PY_VERSION_HEX < 0x03080000
#if defined(PYPY_VERSION) || PY_VERSION_HEX < 0x03080000
// Running exec and eval on Python 2 and 3 adds `builtins` module under
// `__builtins__` key to globals if not yet present.
// Python 3.8 made PyRun_String behave similarly. Let's also do that for
// older versions, for consistency. This was missing from PyPy3.8 7.3.7.
if (!global.contains("__builtins__"))
global["__builtins__"] = module_::import(PYBIND11_BUILTINS_MODULE);
#else
#else
(void) global;
#endif
#endif
}
PYBIND11_NAMESPACE_END(detail)
......@@ -58,10 +58,17 @@ object eval(const str &expr, object global = globals(), object local = object())
int start = 0;
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");
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());
......@@ -74,8 +81,7 @@ object eval(const str &expr, object global = globals(), object local = object())
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);
auto expr = (s[0] == '\n') ? str(module_::import("textwrap").attr("dedent")(s)) : str(s);
return eval<mode>(expr, global, local);
}
......@@ -112,28 +118,34 @@ object eval_file(str fname, object global = globals(), object local = object())
int start = 0;
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");
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;
#if PY_VERSION_HEX >= 0x03040000
# if PY_VERSION_HEX >= 0x03040000
FILE *f = _Py_fopen_obj(fname.ptr(), "r");
#elif PY_VERSION_HEX >= 0x03000000
# elif PY_VERSION_HEX >= 0x03000000
FILE *f = _Py_fopen(fname.ptr(), "r");
#else
# else
/* No unicode support in open() :( */
auto fobj = reinterpret_steal<object>(PyFile_FromString(
const_cast<char *>(fname_str.c_str()),
const_cast<char*>("r")));
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
# endif
if (!f) {
PyErr_Clear();
pybind11_fail("File \"" + fname_str + "\" could not be opened!");
......@@ -142,20 +154,19 @@ object eval_file(str fname, object global = globals(), object local = object())
// In Python2, this should be encoded by getfilesystemencoding.
// We don't boher setting it since Python2 is past EOL anyway.
// See PR#3233
#if PY_VERSION_HEX >= 0x03000000
# if PY_VERSION_HEX >= 0x03000000
if (!global.contains("__file__")) {
global["__file__"] = std::move(fname);
}
#endif
# endif
#if PY_VERSION_HEX < 0x03000000 && defined(PYPY_VERSION)
PyObject *result = PyRun_File(f, fname_str.c_str(), start, global.ptr(),
local.ptr());
# if PY_VERSION_HEX < 0x03000000 && defined(PYPY_VERSION)
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);
#endif
# else
PyObject *result
= PyRun_FileEx(f, fname_str.c_str(), start, global.ptr(), local.ptr(), closeFile);
# endif
if (!result) {
throw error_already_set();
......
......@@ -10,6 +10,7 @@
#pragma once
#include "pybind11.h"
#include <functional>
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
......@@ -19,7 +20,7 @@ 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 function_type = Return (*)(Args...);
public:
bool load(handle src, bool convert) {
......@@ -76,7 +77,9 @@ public:
// This triggers a syntax error under very special conditions (very weird indeed).
explicit
#endif
func_handle(function &&f_) noexcept : f(std::move(f_)) {}
func_handle(function &&f_) noexcept
: f(std::move(f_)) {
}
func_handle(const func_handle &f_) { operator=(f_); }
func_handle &operator=(const func_handle &f_) {
gil_scoped_acquire acq;
......@@ -118,8 +121,10 @@ public:
return cpp_function(std::forward<Func>(f_), policy).release();
}
PYBIND11_TYPE_CASTER(type, const_name("Callable[[") + concat(make_caster<Args>::name...) + const_name("], ")
+ make_caster<retval_type>::name + const_name("]"));
PYBIND11_TYPE_CASTER(type,
const_name("Callable[[") + concat(make_caster<Args>::name...)
+ const_name("], ") + make_caster<retval_type>::name
+ const_name("]"));
};
PYBIND11_NAMESPACE_END(detail)
......
......@@ -14,7 +14,6 @@
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
PYBIND11_NAMESPACE_BEGIN(detail)
// forward declarations
......@@ -22,7 +21,6 @@ PyThreadState *get_thread_state_unchecked();
PYBIND11_NAMESPACE_END(detail)
#if defined(WITH_THREAD) && !defined(PYPY_VERSION)
/* The functions below essentially reproduce the PyGILState_* API using a RAII
......@@ -64,11 +62,11 @@ public:
if (!tstate) {
tstate = PyThreadState_New(internals.istate);
#if !defined(NDEBUG)
# if !defined(NDEBUG)
if (!tstate) {
pybind11_fail("scoped_acquire: could not create thread state!");
}
#endif
# endif
tstate->gilstate_counter = 0;
PYBIND11_TLS_REPLACE_VALUE(internals.tstate, tstate);
} else {
......@@ -82,26 +80,24 @@ public:
inc_ref();
}
void inc_ref() {
++tstate->gilstate_counter;
}
void inc_ref() { ++tstate->gilstate_counter; }
PYBIND11_NOINLINE void dec_ref() {
--tstate->gilstate_counter;
#if !defined(NDEBUG)
# if !defined(NDEBUG)
if (detail::get_thread_state_unchecked() != tstate) {
pybind11_fail("scoped_acquire::dec_ref(): thread state must be current!");
}
if (tstate->gilstate_counter < 0) {
pybind11_fail("scoped_acquire::dec_ref(): reference count underflow!");
}
#endif
# endif
if (tstate->gilstate_counter == 0) {
#if !defined(NDEBUG)
# if !defined(NDEBUG)
if (!release) {
pybind11_fail("scoped_acquire::dec_ref(): internal error!");
}
#endif
# endif
PyThreadState_Clear(tstate);
if (active) {
PyThreadState_DeleteCurrent();
......@@ -116,9 +112,7 @@ public:
/// could be shutting down when this is called, as thread deletion is not
/// allowed during shutdown. Check _Py_IsFinalizing() on Python 3.7+, and
/// protect subsequent code.
PYBIND11_NOINLINE void disarm() {
active = false;
}
PYBIND11_NOINLINE void disarm() { active = false; }
PYBIND11_NOINLINE ~gil_scoped_acquire() {
dec_ref();
......@@ -126,6 +120,7 @@ public:
PyEval_SaveThread();
}
}
private:
PyThreadState *tstate = nullptr;
bool release = true;
......@@ -154,9 +149,7 @@ public:
/// could be shutting down when this is called, as thread deletion is not
/// allowed during shutdown. Check _Py_IsFinalizing() on Python 3.7+, and
/// protect subsequent code.
PYBIND11_NOINLINE void disarm() {
active = false;
}
PYBIND11_NOINLINE void disarm() { active = false; }
~gil_scoped_release() {
if (!tstate) {
......@@ -173,6 +166,7 @@ public:
PYBIND11_TLS_REPLACE_VALUE(key, tstate);
}
}
private:
PyThreadState *tstate;
bool disassoc;
......@@ -181,6 +175,7 @@ private:
#elif defined(PYPY_VERSION)
class gil_scoped_acquire {
PyGILState_STATE state;
public:
gil_scoped_acquire() { state = PyGILState_Ensure(); }
~gil_scoped_acquire() { PyGILState_Release(state); }
......@@ -189,6 +184,7 @@ public:
class gil_scoped_release {
PyThreadState *state;
public:
gil_scoped_release() { state = PyEval_SaveThread(); }
~gil_scoped_release() { PyEval_RestoreThread(state); }
......
......@@ -58,18 +58,10 @@ private:
size_t utf8_remainder() const {
const auto rbase = std::reverse_iterator<char *>(pbase());
const auto rpptr = std::reverse_iterator<char *>(pptr());
auto is_ascii = [](char c) {
return (static_cast<unsigned char>(c) & 0x80) == 0x00;
};
auto is_leading = [](char c) {
return (static_cast<unsigned char>(c) & 0xC0) == 0xC0;
};
auto is_leading_2b = [](char c) {
return static_cast<unsigned char>(c) <= 0xDF;
};
auto is_leading_3b = [](char c) {
return static_cast<unsigned char>(c) <= 0xEF;
};
auto is_ascii = [](char c) { return (static_cast<unsigned char>(c) & 0x80) == 0x00; };
auto is_leading = [](char c) { return (static_cast<unsigned char>(c) & 0xC0) == 0xC0; };
auto is_leading_2b = [](char c) { return static_cast<unsigned char>(c) <= 0xDF; };
auto is_leading_3b = [](char c) { return static_cast<unsigned char>(c) <= 0xEF; };
// If the last character is ASCII, there are no incomplete code points
if (is_ascii(*rpptr)) {
return 0;
......@@ -122,9 +114,7 @@ private:
return 0;
}
int sync() override {
return _sync();
}
int sync() override { return _sync(); }
public:
explicit pythonbuf(const object &pyostream, size_t buffer_size = 1024)
......@@ -133,17 +123,14 @@ public:
setp(d_buffer.get(), d_buffer.get() + buf_size - 1);
}
pythonbuf(pythonbuf&&) = default;
pythonbuf(pythonbuf &&) = default;
/// Sync before destroy
~pythonbuf() override {
_sync();
}
~pythonbuf() override { _sync(); }
};
PYBIND11_NAMESPACE_END(detail)
/** \rst
This a move-only guard that redirects output.
......@@ -183,9 +170,7 @@ public:
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;
......@@ -193,7 +178,6 @@ public:
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.
......@@ -213,7 +197,6 @@ public:
: scoped_ostream_redirect(costream, pyostream) {}
};
PYBIND11_NAMESPACE_BEGIN(detail)
// Class to redirect output as a context manager. C++ backend.
......
......@@ -11,19 +11,20 @@
#include "pybind11.h"
#include "complex.h"
#include <numeric>
#include <algorithm>
#include <array>
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <functional>
#include <numeric>
#include <sstream>
#include <string>
#include <functional>
#include <type_traits>
#include <typeindex>
#include <utility>
#include <vector>
#include <typeindex>
/* This will be true on all flat address space platforms and allows us to reduce the
whole npy_intp / ssize_t / Py_intptr_t business down to just ssize_t for all size
......@@ -39,9 +40,13 @@ class array; // Forward declaration
PYBIND11_NAMESPACE_BEGIN(detail)
template <> struct handle_type_name<array> { static constexpr auto name = const_name("numpy.ndarray"); };
template <>
struct handle_type_name<array> {
static constexpr auto name = const_name("numpy.ndarray");
};
template <typename type, typename SFINAE = void> struct npy_format_descriptor;
template <typename type, typename SFINAE = void>
struct npy_format_descriptor;
struct PyArrayDescr_Proxy {
PyObject_HEAD
......@@ -70,22 +75,21 @@ struct PyArray_Proxy {
};
struct PyVoidScalarObject_Proxy {
PyObject_VAR_HEAD
char *obval;
PyObject_VAR_HEAD char *obval;
PyArrayDescr_Proxy *descr;
int flags;
PyObject *base;
};
struct numpy_type_info {
PyObject* dtype_ptr;
PyObject *dtype_ptr;
std::string format_str;
};
struct numpy_internals {
std::unordered_map<std::type_index, numpy_type_info> registered_dtypes;
numpy_type_info *get_type_info(const std::type_info& tinfo, bool throw_if_missing = true) {
numpy_type_info *get_type_info(const std::type_info &tinfo, bool throw_if_missing = true) {
auto it = registered_dtypes.find(std::type_index(tinfo));
if (it != registered_dtypes.end()) {
return &(it->second);
......@@ -96,28 +100,34 @@ struct numpy_internals {
return nullptr;
}
template<typename T> numpy_type_info *get_type_info(bool throw_if_missing = true) {
template <typename T>
numpy_type_info *get_type_info(bool throw_if_missing = true) {
return get_type_info(typeid(typename std::remove_cv<T>::type), throw_if_missing);
}
};
PYBIND11_NOINLINE void load_numpy_internals(numpy_internals* &ptr) {
PYBIND11_NOINLINE void load_numpy_internals(numpy_internals *&ptr) {
ptr = &get_or_create_shared_data<numpy_internals>("_numpy_internals");
}
inline numpy_internals& get_numpy_internals() {
static numpy_internals* ptr = nullptr;
inline numpy_internals &get_numpy_internals() {
static numpy_internals *ptr = nullptr;
if (!ptr) {
load_numpy_internals(ptr);
}
return *ptr;
}
template <typename T> struct same_size {
template <typename U> using as = bool_constant<sizeof(T) == sizeof(U)>;
template <typename T>
struct same_size {
template <typename U>
using as = bool_constant<sizeof(T) == sizeof(U)>;
};
template <typename Concrete> constexpr int platform_lookup() { return -1; }
template <typename Concrete>
constexpr int platform_lookup() {
return -1;
}
// Lookup a type according to its size, and return a value corresponding to the NumPy typenum.
template <typename Concrete, typename T, typename... Ts, typename... Ints>
......@@ -135,15 +145,26 @@ struct npy_api {
NPY_ARRAY_ALIGNED_ = 0x0100,
NPY_ARRAY_WRITEABLE_ = 0x0400,
NPY_BOOL_ = 0,
NPY_BYTE_, NPY_UBYTE_,
NPY_SHORT_, NPY_USHORT_,
NPY_INT_, NPY_UINT_,
NPY_LONG_, NPY_ULONG_,
NPY_LONGLONG_, NPY_ULONGLONG_,
NPY_FLOAT_, NPY_DOUBLE_, NPY_LONGDOUBLE_,
NPY_CFLOAT_, NPY_CDOUBLE_, NPY_CLONGDOUBLE_,
NPY_BYTE_,
NPY_UBYTE_,
NPY_SHORT_,
NPY_USHORT_,
NPY_INT_,
NPY_UINT_,
NPY_LONG_,
NPY_ULONG_,
NPY_LONGLONG_,
NPY_ULONGLONG_,
NPY_FLOAT_,
NPY_DOUBLE_,
NPY_LONGDOUBLE_,
NPY_CFLOAT_,
NPY_CDOUBLE_,
NPY_CLONGDOUBLE_,
NPY_OBJECT_ = 17,
NPY_STRING_, NPY_UNICODE_, NPY_VOID_,
NPY_STRING_,
NPY_UNICODE_,
NPY_VOID_,
// Platform-dependent normalization
NPY_INT8_ = NPY_BYTE_,
NPY_UINT8_ = NPY_UBYTE_,
......@@ -152,13 +173,14 @@ struct npy_api {
// `npy_common.h` defines the integer aliases. In order, it checks:
// NPY_BITSOF_LONG, NPY_BITSOF_LONGLONG, NPY_BITSOF_INT, NPY_BITSOF_SHORT, NPY_BITSOF_CHAR
// and assigns the alias to the first matching size, so we should check in this order.
NPY_INT32_ = platform_lookup<std::int32_t, long, int, short>(
NPY_LONG_, NPY_INT_, NPY_SHORT_),
NPY_INT32_
= platform_lookup<std::int32_t, long, int, short>(NPY_LONG_, NPY_INT_, NPY_SHORT_),
NPY_UINT32_ = platform_lookup<std::uint32_t, unsigned long, unsigned int, unsigned short>(
NPY_ULONG_, NPY_UINT_, NPY_USHORT_),
NPY_INT64_ = platform_lookup<std::int64_t, long, long long, int>(
NPY_LONG_, NPY_LONGLONG_, NPY_INT_),
NPY_UINT64_ = platform_lookup<std::uint64_t, unsigned long, unsigned long long, unsigned int>(
NPY_INT64_
= platform_lookup<std::int64_t, long, long long, int>(NPY_LONG_, NPY_LONGLONG_, NPY_INT_),
NPY_UINT64_
= platform_lookup<std::uint64_t, unsigned long, unsigned long long, unsigned int>(
NPY_ULONG_, NPY_ULONGLONG_, NPY_UINT_),
};
......@@ -167,7 +189,7 @@ struct npy_api {
int len;
};
static npy_api& get() {
static npy_api &get() {
static npy_api api = lookup();
return api;
}
......@@ -181,9 +203,14 @@ struct npy_api {
unsigned int (*PyArray_GetNDArrayCFeatureVersion_)();
PyObject *(*PyArray_DescrFromType_)(int);
PyObject *(*PyArray_NewFromDescr_)
(PyTypeObject *, PyObject *, int, Py_intptr_t const *,
Py_intptr_t const *, void *, int, PyObject *);
PyObject *(*PyArray_NewFromDescr_)(PyTypeObject *,
PyObject *,
int,
Py_intptr_t const *,
Py_intptr_t const *,
void *,
int,
PyObject *);
// Unused. Not removed because that affects ABI of the class.
PyObject *(*PyArray_DescrNewFromType_)(int);
int (*PyArray_CopyInto_)(PyObject *, PyObject *);
......@@ -192,17 +219,23 @@ struct npy_api {
PyTypeObject *PyVoidArrType_Type_;
PyTypeObject *PyArrayDescr_Type_;
PyObject *(*PyArray_DescrFromScalar_)(PyObject *);
PyObject *(*PyArray_FromAny_) (PyObject *, PyObject *, int, int, int, PyObject *);
int (*PyArray_DescrConverter_) (PyObject *, PyObject **);
bool (*PyArray_EquivTypes_) (PyObject *, PyObject *);
int (*PyArray_GetArrayParamsFromObject_)(PyObject *, PyObject *, unsigned char, PyObject **, int *,
Py_intptr_t *, PyObject **, PyObject *);
PyObject *(*PyArray_FromAny_)(PyObject *, PyObject *, int, int, int, PyObject *);
int (*PyArray_DescrConverter_)(PyObject *, PyObject **);
bool (*PyArray_EquivTypes_)(PyObject *, PyObject *);
int (*PyArray_GetArrayParamsFromObject_)(PyObject *,
PyObject *,
unsigned char,
PyObject **,
int *,
Py_intptr_t *,
PyObject **,
PyObject *);
PyObject *(*PyArray_Squeeze_)(PyObject *);
// Unused. Not removed because that affects ABI of the class.
int (*PyArray_SetBaseObject_)(PyObject *, PyObject *);
PyObject* (*PyArray_Resize_)(PyObject*, PyArray_Dims*, int, int);
PyObject* (*PyArray_Newshape_)(PyObject*, PyArray_Dims*, int);
PyObject* (*PyArray_View_)(PyObject*, PyObject*, PyObject*);
PyObject *(*PyArray_Resize_)(PyObject *, PyArray_Dims *, int, int);
PyObject *(*PyArray_Newshape_)(PyObject *, PyArray_Dims *, int);
PyObject *(*PyArray_View_)(PyObject *, PyObject *, PyObject *);
private:
enum functions {
......@@ -265,86 +298,103 @@ private:
}
};
inline PyArray_Proxy* array_proxy(void* ptr) {
return reinterpret_cast<PyArray_Proxy*>(ptr);
}
inline PyArray_Proxy *array_proxy(void *ptr) { return reinterpret_cast<PyArray_Proxy *>(ptr); }
inline const PyArray_Proxy* array_proxy(const void* ptr) {
return reinterpret_cast<const PyArray_Proxy*>(ptr);
inline const PyArray_Proxy *array_proxy(const void *ptr) {
return reinterpret_cast<const PyArray_Proxy *>(ptr);
}
inline PyArrayDescr_Proxy* array_descriptor_proxy(PyObject* ptr) {
return reinterpret_cast<PyArrayDescr_Proxy*>(ptr);
inline PyArrayDescr_Proxy *array_descriptor_proxy(PyObject *ptr) {
return reinterpret_cast<PyArrayDescr_Proxy *>(ptr);
}
inline const PyArrayDescr_Proxy* array_descriptor_proxy(const PyObject* ptr) {
return reinterpret_cast<const PyArrayDescr_Proxy*>(ptr);
inline const PyArrayDescr_Proxy *array_descriptor_proxy(const PyObject *ptr) {
return reinterpret_cast<const PyArrayDescr_Proxy *>(ptr);
}
inline bool check_flags(const void* ptr, int flag) {
inline bool check_flags(const void *ptr, int flag) {
return (flag == (array_proxy(ptr)->flags & flag));
}
template <typename T> struct is_std_array : std::false_type { };
template <typename T, size_t N> struct is_std_array<std::array<T, N>> : std::true_type { };
template <typename T> struct is_complex : std::false_type { };
template <typename T> struct is_complex<std::complex<T>> : std::true_type { };
template <typename T>
struct is_std_array : std::false_type {};
template <typename T, size_t N>
struct is_std_array<std::array<T, N>> : std::true_type {};
template <typename T>
struct is_complex : std::false_type {};
template <typename T>
struct is_complex<std::complex<T>> : std::true_type {};
template <typename T> struct array_info_scalar {
template <typename T>
struct array_info_scalar {
using type = T;
static constexpr bool is_array = false;
static constexpr bool is_empty = false;
static constexpr auto extents = const_name("");
static void append_extents(list& /* shape */) { }
static void append_extents(list & /* shape */) {}
};
// Computes underlying type and a comma-separated list of extents for array
// types (any mix of std::array and built-in arrays). An array of char is
// treated as scalar because it gets special handling.
template <typename T> struct array_info : array_info_scalar<T> { };
template <typename T, size_t N> struct array_info<std::array<T, N>> {
template <typename T>
struct array_info : array_info_scalar<T> {};
template <typename T, size_t N>
struct array_info<std::array<T, N>> {
using type = typename array_info<T>::type;
static constexpr bool is_array = true;
static constexpr bool is_empty = (N == 0) || array_info<T>::is_empty;
static constexpr size_t extent = N;
// appends the extents to shape
static void append_extents(list& shape) {
static void append_extents(list &shape) {
shape.append(N);
array_info<T>::append_extents(shape);
}
static constexpr auto extents = const_name<array_info<T>::is_array>(
concat(const_name<N>(), array_info<T>::extents), const_name<N>()
);
concat(const_name<N>(), array_info<T>::extents), const_name<N>());
};
// For numpy we have special handling for arrays of characters, so we don't include
// the size in the array extents.
template <size_t N> struct array_info<char[N]> : array_info_scalar<char[N]> { };
template <size_t N> struct array_info<std::array<char, N>> : array_info_scalar<std::array<char, N>> { };
template <typename T, size_t N> struct array_info<T[N]> : array_info<std::array<T, N>> { };
template <typename T> using remove_all_extents_t = typename array_info<T>::type;
template <size_t N>
struct array_info<char[N]> : array_info_scalar<char[N]> {};
template <size_t N>
struct array_info<std::array<char, N>> : array_info_scalar<std::array<char, N>> {};
template <typename T, size_t N>
struct array_info<T[N]> : array_info<std::array<T, N>> {};
template <typename T>
using remove_all_extents_t = typename array_info<T>::type;
template <typename T> using is_pod_struct = all_of<
std::is_standard_layout<T>, // since we're accessing directly in memory
template <typename T>
using is_pod_struct
= all_of<std::is_standard_layout<T>, // since we're accessing directly in memory
// we need a standard layout type
#if defined(__GLIBCXX__) && (__GLIBCXX__ < 20150422 || __GLIBCXX__ == 20150426 || __GLIBCXX__ == 20150623 || __GLIBCXX__ == 20150626 || __GLIBCXX__ == 20160803)
// libstdc++ < 5 (including versions 4.8.5, 4.9.3 and 4.9.4 which were released after 5)
// don't implement is_trivially_copyable, so approximate it
#if defined(__GLIBCXX__) \
&& (__GLIBCXX__ < 20150422 || __GLIBCXX__ == 20150426 || __GLIBCXX__ == 20150623 \
|| __GLIBCXX__ == 20150626 || __GLIBCXX__ == 20160803)
// libstdc++ < 5 (including versions 4.8.5, 4.9.3 and 4.9.4 which were released after
// 5) don't implement is_trivially_copyable, so approximate it
std::is_trivially_destructible<T>,
satisfies_any_of<T, std::has_trivial_copy_constructor, std::has_trivial_copy_assign>,
#else
std::is_trivially_copyable<T>,
#endif
satisfies_none_of<T, std::is_reference, std::is_array, is_std_array, std::is_arithmetic, is_complex, std::is_enum>
>;
satisfies_none_of<T,
std::is_reference,
std::is_array,
is_std_array,
std::is_arithmetic,
is_complex,
std::is_enum>>;
// Replacement for std::is_pod (deprecated in C++20)
template <typename T> using is_pod = all_of<
std::is_standard_layout<T>,
std::is_trivial<T>
>;
template <typename T>
using is_pod = all_of<std::is_standard_layout<T>, std::is_trivial<T>>;
template <ssize_t Dim = 0, typename Strides> ssize_t byte_offset_unsafe(const Strides &) { return 0; }
template <ssize_t Dim = 0, typename Strides>
ssize_t byte_offset_unsafe(const Strides &) {
return 0;
}
template <ssize_t Dim = 0, typename Strides, typename... Ix>
ssize_t byte_offset_unsafe(const Strides &strides, ssize_t i, Ix... index) {
return i * strides[Dim] + byte_offset_unsafe<Dim + 1>(strides, index...);
......@@ -362,14 +412,16 @@ protected:
const unsigned char *data_;
// Storing the shape & strides in local variables (i.e. these arrays) allows the compiler to
// make large performance gains on big, nested loops, but requires compile-time dimensions
conditional_t<Dynamic, const ssize_t *, std::array<ssize_t, (size_t) Dims>>
shape_, strides_;
conditional_t<Dynamic, const ssize_t *, std::array<ssize_t, (size_t) Dims>> shape_, strides_;
const ssize_t dims_;
friend class pybind11::array;
// Constructor for compile-time dimensions:
template <bool Dyn = Dynamic>
unchecked_reference(const void *data, const ssize_t *shape, const ssize_t *strides, enable_if_t<!Dyn, ssize_t>)
unchecked_reference(const void *data,
const ssize_t *shape,
const ssize_t *strides,
enable_if_t<!Dyn, ssize_t>)
: data_{reinterpret_cast<const unsigned char *>(data)}, dims_{Dims} {
for (size_t i = 0; i < (size_t) dims_; i++) {
shape_[i] = shape[i];
......@@ -378,8 +430,12 @@ protected:
}
// Constructor for runtime dimensions:
template <bool Dyn = Dynamic>
unchecked_reference(const void *data, const ssize_t *shape, const ssize_t *strides, enable_if_t<Dyn, ssize_t> dims)
: data_{reinterpret_cast<const unsigned char *>(data)}, shape_{shape}, strides_{strides}, dims_{dims} {}
unchecked_reference(const void *data,
const ssize_t *shape,
const ssize_t *strides,
enable_if_t<Dyn, ssize_t> dims)
: data_{reinterpret_cast<const unsigned char *>(data)}, shape_{shape}, strides_{strides},
dims_{dims} {}
public:
/**
......@@ -387,20 +443,27 @@ public:
* number of dimensions, this requires the correct number of arguments; for run-time
* dimensionality, this is not checked (and so is up to the caller to use safely).
*/
template <typename... Ix> const T &operator()(Ix... index) const {
template <typename... Ix>
const T &operator()(Ix... index) const {
static_assert(ssize_t{sizeof...(Ix)} == Dims || Dynamic,
"Invalid number of indices for unchecked array reference");
return *reinterpret_cast<const T *>(data_ + byte_offset_unsafe(strides_, ssize_t(index)...));
return *reinterpret_cast<const T *>(data_
+ byte_offset_unsafe(strides_, ssize_t(index)...));
}
/**
* Unchecked const reference access to data; this operator only participates if the reference
* is to a 1-dimensional array. When present, this is exactly equivalent to `obj(index)`.
*/
template <ssize_t D = Dims, typename = enable_if_t<D == 1 || Dynamic>>
const T &operator[](ssize_t index) const { return operator()(index); }
const T &operator[](ssize_t index) const {
return operator()(index);
}
/// Pointer access to the data at the given indices.
template <typename... Ix> const T *data(Ix... ix) const { return &operator()(ssize_t(ix)...); }
template <typename... Ix>
const T *data(Ix... ix) const {
return &operator()(ssize_t(ix)...);
}
/// Returns the item size, i.e. sizeof(T)
constexpr static ssize_t itemsize() { return sizeof(T); }
......@@ -411,21 +474,22 @@ public:
/// Returns the number of dimensions of the array
ssize_t ndim() const { return dims_; }
/// Returns the total number of elements in the referenced array, i.e. the product of the shapes
/// Returns the total number of elements in the referenced array, i.e. the product of the
/// shapes
template <bool Dyn = Dynamic>
enable_if_t<!Dyn, ssize_t> size() const {
return std::accumulate(shape_.begin(), shape_.end(), (ssize_t) 1, std::multiplies<ssize_t>());
return std::accumulate(
shape_.begin(), shape_.end(), (ssize_t) 1, std::multiplies<ssize_t>());
}
template <bool Dyn = Dynamic>
enable_if_t<Dyn, ssize_t> size() const {
return std::accumulate(shape_, shape_ + ndim(), (ssize_t) 1, std::multiplies<ssize_t>());
}
/// Returns the total number of bytes used by the referenced data. Note that the actual span in
/// memory may be larger if the referenced array has non-contiguous strides (e.g. for a slice).
ssize_t nbytes() const {
return size() * itemsize();
}
/// Returns the total number of bytes used by the referenced data. Note that the actual span
/// in memory may be larger if the referenced array has non-contiguous strides (e.g. for a
/// slice).
ssize_t nbytes() const { return size() * itemsize(); }
};
template <typename T, ssize_t Dims>
......@@ -434,13 +498,15 @@ class unchecked_mutable_reference : public unchecked_reference<T, Dims> {
using ConstBase = unchecked_reference<T, Dims>;
using ConstBase::ConstBase;
using ConstBase::Dynamic;
public:
// Bring in const-qualified versions from base class
using ConstBase::operator();
using ConstBase::operator[];
/// Mutable, unchecked access to data at the given indices.
template <typename... Ix> T& operator()(Ix... index) {
template <typename... Ix>
T &operator()(Ix... index) {
static_assert(ssize_t{sizeof...(Ix)} == Dims || Dynamic,
"Invalid number of indices for unchecked array reference");
return const_cast<T &>(ConstBase::operator()(index...));
......@@ -451,18 +517,25 @@ public:
* exactly equivalent to `obj(index)`.
*/
template <ssize_t D = Dims, typename = enable_if_t<D == 1 || Dynamic>>
T &operator[](ssize_t index) { return operator()(index); }
T &operator[](ssize_t index) {
return operator()(index);
}
/// Mutable pointer access to the data at the given indices.
template <typename... Ix> T *mutable_data(Ix... ix) { return &operator()(ssize_t(ix)...); }
template <typename... Ix>
T *mutable_data(Ix... ix) {
return &operator()(ssize_t(ix)...);
}
};
template <typename T, ssize_t Dim>
struct type_caster<unchecked_reference<T, Dim>> {
static_assert(Dim == 0 && Dim > 0 /* always fail */, "unchecked array proxy object is not castable");
static_assert(Dim == 0 && Dim > 0 /* always fail */,
"unchecked array proxy object is not castable");
};
template <typename T, ssize_t Dim>
struct type_caster<unchecked_mutable_reference<T, Dim>> : type_caster<unchecked_reference<T, Dim>> {};
struct type_caster<unchecked_mutable_reference<T, Dim>>
: type_caster<unchecked_reference<T, Dim>> {};
PYBIND11_NAMESPACE_END(detail)
......@@ -503,25 +576,20 @@ public:
}
/// Return dtype associated with a C++ type.
template <typename T> static dtype of() {
template <typename T>
static dtype of() {
return detail::npy_format_descriptor<typename std::remove_cv<T>::type>::dtype();
}
/// Size of the data type in bytes.
ssize_t itemsize() const {
return detail::array_descriptor_proxy(m_ptr)->elsize;
}
ssize_t itemsize() const { return detail::array_descriptor_proxy(m_ptr)->elsize; }
/// Returns true for structured data types.
bool has_fields() const {
return detail::array_descriptor_proxy(m_ptr)->names != nullptr;
}
bool has_fields() const { return detail::array_descriptor_proxy(m_ptr)->names != nullptr; }
/// Single-character code for dtype's kind.
/// For example, floating point types are 'f' and integral types are 'i'.
char kind() const {
return detail::array_descriptor_proxy(m_ptr)->kind;
}
char kind() const { return detail::array_descriptor_proxy(m_ptr)->kind; }
/// Single-character for dtype's type.
/// For example, ``float`` is 'f', ``double`` 'd', ``int`` 'i', and ``long`` 'l'.
......@@ -535,7 +603,10 @@ public:
private:
static object _dtype_from_pep3118() {
static PyObject *obj = module_::import("numpy.core._internal")
.attr("_dtype_from_pep3118").cast<object>().release().ptr();
.attr("_dtype_from_pep3118")
.cast<object>()
.release()
.ptr();
return reinterpret_borrow<object>(obj);
}
......@@ -546,7 +617,11 @@ private:
return *this;
}
struct field_descr { PYBIND11_STR_TYPE name; object format; pybind11::int_ offset; };
struct field_descr {
PYBIND11_STR_TYPE name;
object format;
pybind11::int_ offset;
};
std::vector<field_descr> field_descriptors;
for (auto field : attr("fields").attr("items")()) {
......@@ -557,16 +632,18 @@ private:
if ((len(name) == 0u) && format.kind() == 'V') {
continue;
}
field_descriptors.push_back({(PYBIND11_STR_TYPE) name, format.strip_padding(format.itemsize()), offset});
field_descriptors.push_back(
{(PYBIND11_STR_TYPE) name, format.strip_padding(format.itemsize()), offset});
}
std::sort(field_descriptors.begin(), field_descriptors.end(),
[](const field_descr& a, const field_descr& b) {
std::sort(field_descriptors.begin(),
field_descriptors.end(),
[](const field_descr &a, const field_descr &b) {
return a.offset.cast<int>() < b.offset.cast<int>();
});
list names, formats, offsets;
for (auto& descr : field_descriptors) {
for (auto &descr : field_descriptors) {
names.append(descr.name);
formats.append(descr.format);
offsets.append(descr.offset);
......@@ -591,8 +668,11 @@ public:
using StridesContainer = detail::any_container<ssize_t>;
// Constructs an array taking shape/strides from arbitrary container types
array(const pybind11::dtype &dt, ShapeContainer shape, StridesContainer strides,
const void *ptr = nullptr, handle base = handle()) {
array(const pybind11::dtype &dt,
ShapeContainer shape,
StridesContainer strides,
const void *ptr = nullptr,
handle base = handle()) {
if (strides->empty()) {
*strides = detail::c_strides(*shape, dt.itemsize());
......@@ -608,7 +688,8 @@ public:
if (base && ptr) {
if (isinstance<array>(base)) {
/* Copy flags from base (except ownership bit) */
flags = reinterpret_borrow<array>(base).flags() & ~detail::npy_api::NPY_ARRAY_OWNDATA_;
flags = reinterpret_borrow<array>(base).flags()
& ~detail::npy_api::NPY_ARRAY_OWNDATA_;
} else {
/* Writable by default, easy to downgrade later on if needed */
flags = detail::npy_api::NPY_ARRAY_WRITEABLE_;
......@@ -617,11 +698,15 @@ public:
auto &api = detail::npy_api::get();
auto tmp = reinterpret_steal<object>(api.PyArray_NewFromDescr_(
api.PyArray_Type_, descr.release().ptr(), (int) ndim,
api.PyArray_Type_,
descr.release().ptr(),
(int) ndim,
// Use reinterpret_cast for PyPy on Windows (remove if fixed, checked on 7.3.1)
reinterpret_cast<Py_intptr_t*>(shape->data()),
reinterpret_cast<Py_intptr_t*>(strides->data()),
const_cast<void *>(ptr), flags, nullptr));
reinterpret_cast<Py_intptr_t *>(shape->data()),
reinterpret_cast<Py_intptr_t *>(strides->data()),
const_cast<void *>(ptr),
flags,
nullptr));
if (!tmp) {
throw error_already_set();
}
......@@ -629,32 +714,39 @@ public:
if (base) {
api.PyArray_SetBaseObject_(tmp.ptr(), base.inc_ref().ptr());
} else {
tmp = reinterpret_steal<object>(api.PyArray_NewCopy_(tmp.ptr(), -1 /* any order */));
tmp = reinterpret_steal<object>(
api.PyArray_NewCopy_(tmp.ptr(), -1 /* any order */));
}
}
m_ptr = tmp.release().ptr();
}
array(const pybind11::dtype &dt, ShapeContainer shape, const void *ptr = nullptr, handle base = handle())
: array(dt, std::move(shape), {}, ptr, base) { }
array(const pybind11::dtype &dt,
ShapeContainer shape,
const void *ptr = nullptr,
handle base = handle())
: array(dt, std::move(shape), {}, ptr, base) {}
template <typename T, typename = detail::enable_if_t<std::is_integral<T>::value && !std::is_same<bool, T>::value>>
template <typename T,
typename
= detail::enable_if_t<std::is_integral<T>::value && !std::is_same<bool, T>::value>>
array(const pybind11::dtype &dt, T count, const void *ptr = nullptr, handle base = handle())
: array(dt, {{count}}, ptr, base) { }
: array(dt, {{count}}, ptr, base) {}
template <typename T>
array(ShapeContainer shape, StridesContainer strides, const T *ptr, handle base = handle())
: array(pybind11::dtype::of<T>(), std::move(shape), std::move(strides), ptr, base) { }
: array(pybind11::dtype::of<T>(), std::move(shape), std::move(strides), ptr, base) {}
template <typename T>
array(ShapeContainer shape, const T *ptr, handle base = handle())
: array(std::move(shape), {}, ptr, base) { }
: array(std::move(shape), {}, ptr, base) {}
template <typename T>
explicit array(ssize_t count, const T *ptr, handle base = handle()) : array({count}, {}, ptr, base) { }
explicit array(ssize_t count, const T *ptr, handle base = handle())
: array({count}, {}, ptr, base) {}
explicit array(const buffer_info &info, handle base = handle())
: array(pybind11::dtype(info), info.shape, info.strides, info.ptr, base) { }
: array(pybind11::dtype(info), info.shape, info.strides, info.ptr, base) {}
/// Array descriptor (dtype)
pybind11::dtype dtype() const {
......@@ -672,24 +764,16 @@ public:
}
/// Total number of bytes
ssize_t nbytes() const {
return size() * itemsize();
}
ssize_t nbytes() const { return size() * itemsize(); }
/// Number of dimensions
ssize_t ndim() const {
return detail::array_proxy(m_ptr)->nd;
}
ssize_t ndim() const { return detail::array_proxy(m_ptr)->nd; }
/// Base object
object base() const {
return reinterpret_borrow<object>(detail::array_proxy(m_ptr)->base);
}
object base() const { return reinterpret_borrow<object>(detail::array_proxy(m_ptr)->base); }
/// Dimensions of the array
const ssize_t* shape() const {
return detail::array_proxy(m_ptr)->dimensions;
}
const ssize_t *shape() const { return detail::array_proxy(m_ptr)->dimensions; }
/// Dimension along a given axis
ssize_t shape(ssize_t dim) const {
......@@ -700,9 +784,7 @@ public:
}
/// Strides of the array
const ssize_t* strides() const {
return detail::array_proxy(m_ptr)->strides;
}
const ssize_t *strides() const { return detail::array_proxy(m_ptr)->strides; }
/// Stride along a given axis
ssize_t strides(ssize_t dim) const {
......@@ -713,9 +795,7 @@ public:
}
/// Return the NumPy array flags
int flags() const {
return detail::array_proxy(m_ptr)->flags;
}
int flags() const { return detail::array_proxy(m_ptr)->flags; }
/// If set, the array is writeable (otherwise the buffer is read-only)
bool writeable() const {
......@@ -729,21 +809,24 @@ public:
/// Pointer to the contained data. If index is not provided, points to the
/// beginning of the buffer. May throw if the index would lead to out of bounds access.
template<typename... Ix> const void* data(Ix... index) const {
template <typename... Ix>
const void *data(Ix... index) const {
return static_cast<const void *>(detail::array_proxy(m_ptr)->data + offset_at(index...));
}
/// Mutable pointer to the contained data. If index is not provided, points to the
/// beginning of the buffer. May throw if the index would lead to out of bounds access.
/// May throw if the array is not writeable.
template<typename... Ix> void* mutable_data(Ix... index) {
template <typename... Ix>
void *mutable_data(Ix... index) {
check_writeable();
return static_cast<void *>(detail::array_proxy(m_ptr)->data + offset_at(index...));
}
/// Byte offset from beginning of the array to a given index (full or partial).
/// May throw if the index would lead to out of bounds access.
template<typename... Ix> ssize_t offset_at(Ix... index) const {
template <typename... Ix>
ssize_t offset_at(Ix... index) const {
if ((ssize_t) sizeof...(index) > ndim()) {
fail_dim_check(sizeof...(index), "too many indices for an array");
}
......@@ -754,7 +837,8 @@ public:
/// Item count from beginning of the array to a given index (full or partial).
/// May throw if the index would lead to out of bounds access.
template<typename... Ix> ssize_t index_at(Ix... index) const {
template <typename... Ix>
ssize_t index_at(Ix... index) const {
return offset_at(index...) / itemsize();
}
......@@ -764,23 +848,26 @@ public:
* care: the array must not be destroyed or reshaped for the duration of the returned object,
* and the caller must take care not to access invalid dimensions or dimension indices.
*/
template <typename T, ssize_t Dims = -1> detail::unchecked_mutable_reference<T, Dims> mutable_unchecked() & {
template <typename T, ssize_t Dims = -1>
detail::unchecked_mutable_reference<T, Dims> mutable_unchecked() & {
if (PYBIND11_SILENCE_MSVC_C4127(Dims >= 0) && ndim() != Dims) {
throw std::domain_error("array has incorrect number of dimensions: "
+ std::to_string(ndim()) + "; expected "
+ std::to_string(Dims));
}
return detail::unchecked_mutable_reference<T, Dims>(mutable_data(), shape(), strides(), ndim());
return detail::unchecked_mutable_reference<T, Dims>(
mutable_data(), shape(), strides(), ndim());
}
/**
* Returns a proxy object that provides const access to the array's data without bounds or
* dimensionality checking. Unlike `mutable_unchecked()`, this does not require that the
* underlying array have the `writable` flag. Use with care: the array must not be destroyed or
* reshaped for the duration of the returned object, and the caller must take care not to access
* invalid dimensions or dimension indices.
* underlying array have the `writable` flag. Use with care: the array must not be destroyed
* or reshaped for the duration of the returned object, and the caller must take care not to
* access invalid dimensions or dimension indices.
*/
template <typename T, ssize_t Dims = -1> detail::unchecked_reference<T, Dims> unchecked() const & {
template <typename T, ssize_t Dims = -1>
detail::unchecked_reference<T, Dims> unchecked() const & {
if (PYBIND11_SILENCE_MSVC_C4127(Dims >= 0) && ndim() != Dims) {
throw std::domain_error("array has incorrect number of dimensions: "
+ std::to_string(ndim()) + "; expected "
......@@ -791,7 +878,7 @@ public:
/// Return a new view with all of the dimensions of length 1 removed
array squeeze() {
auto& api = detail::npy_api::get();
auto &api = detail::npy_api::get();
return reinterpret_steal<array>(api.PyArray_Squeeze_(m_ptr));
}
......@@ -799,19 +886,19 @@ public:
/// If refcheck is true and more that one reference exist to this array
/// then resize will succeed only if it makes a reshape, i.e. original size doesn't change
void resize(ShapeContainer new_shape, bool refcheck = true) {
detail::npy_api::PyArray_Dims d = {
// Use reinterpret_cast for PyPy on Windows (remove if fixed, checked on 7.3.1)
reinterpret_cast<Py_intptr_t*>(new_shape->data()),
int(new_shape->size())
};
detail::npy_api::PyArray_Dims d
= {// Use reinterpret_cast for PyPy on Windows (remove if fixed, checked on 7.3.1)
reinterpret_cast<Py_intptr_t *>(new_shape->data()),
int(new_shape->size())};
// try to resize, set ordering param to -1 cause it's not used anyway
auto new_array = reinterpret_steal<object>(
detail::npy_api::get().PyArray_Resize_(m_ptr, &d, int(refcheck), -1)
);
detail::npy_api::get().PyArray_Resize_(m_ptr, &d, int(refcheck), -1));
if (!new_array) {
throw error_already_set();
}
if (isinstance<array>(new_array)) { *this = std::move(new_array); }
if (isinstance<array>(new_array)) {
*this = std::move(new_array);
}
}
/// Optional `order` parameter omitted, to be added as needed.
......@@ -852,14 +939,16 @@ public:
}
protected:
template<typename, typename> friend struct detail::npy_format_descriptor;
template <typename, typename>
friend struct detail::npy_format_descriptor;
void fail_dim_check(ssize_t dim, const std::string& msg) const {
throw index_error(msg + ": " + std::to_string(dim) +
" (ndim = " + std::to_string(ndim()) + ")");
void fail_dim_check(ssize_t dim, const std::string &msg) const {
throw index_error(msg + ": " + std::to_string(dim) + " (ndim = " + std::to_string(ndim())
+ ")");
}
template<typename... Ix> ssize_t byte_offset(Ix... index) const {
template <typename... Ix>
ssize_t byte_offset(Ix... index) const {
check_dimensions(index...);
return detail::byte_offset_unsafe(strides(), ssize_t(index)...);
}
......@@ -870,17 +959,19 @@ protected:
}
}
template<typename... Ix> void check_dimensions(Ix... index) const {
template <typename... Ix>
void check_dimensions(Ix... index) const {
check_dimensions_impl(ssize_t(0), shape(), ssize_t(index)...);
}
void check_dimensions_impl(ssize_t, const ssize_t*) const { }
void check_dimensions_impl(ssize_t, const ssize_t *) const {}
template<typename... Ix> void check_dimensions_impl(ssize_t axis, const ssize_t* shape, ssize_t i, Ix... index) const {
template <typename... Ix>
void check_dimensions_impl(ssize_t axis, const ssize_t *shape, ssize_t i, Ix... index) const {
if (i >= *shape) {
throw index_error(std::string("index ") + std::to_string(i) +
" is out of bounds for axis " + std::to_string(axis) +
" with size " + std::to_string(*shape));
throw index_error(std::string("index ") + std::to_string(i)
+ " is out of bounds for axis " + std::to_string(axis)
+ " with size " + std::to_string(*shape));
}
check_dimensions_impl(axis + 1, shape + 1, index...);
}
......@@ -896,20 +987,26 @@ protected:
}
};
template <typename T, int ExtraFlags = array::forcecast> class array_t : public array {
template <typename T, int ExtraFlags = array::forcecast>
class array_t : public array {
private:
struct private_ctor {};
// Delegating constructor needed when both moving and accessing in the same constructor
array_t(private_ctor, ShapeContainer &&shape, StridesContainer &&strides, const T *ptr, handle base)
array_t(private_ctor,
ShapeContainer &&shape,
StridesContainer &&strides,
const T *ptr,
handle base)
: array(std::move(shape), std::move(strides), ptr, base) {}
public:
static_assert(!detail::array_info<T>::is_array, "Array types cannot be used with array_t");
using value_type = T;
array_t() : array(0, static_cast<const T *>(nullptr)) {}
array_t(handle h, borrowed_t) : array(h, borrowed_t{}) { }
array_t(handle h, stolen_t) : array(h, stolen_t{}) { }
array_t(handle h, borrowed_t) : array(h, borrowed_t{}) {}
array_t(handle h, stolen_t) : array(h, stolen_t{}) {}
PYBIND11_DEPRECATED("Use array_t<T>::ensure() instead")
array_t(handle h, bool is_borrowed) : array(raw_array_t(h.ptr()), stolen_t{}) {
......@@ -928,10 +1025,13 @@ public:
}
}
explicit array_t(const buffer_info& info, handle base = handle()) : array(info, base) { }
explicit array_t(const buffer_info &info, handle base = handle()) : array(info, base) {}
array_t(ShapeContainer shape, StridesContainer strides, const T *ptr = nullptr, handle base = handle())
: array(std::move(shape), std::move(strides), ptr, base) { }
array_t(ShapeContainer shape,
StridesContainer strides,
const T *ptr = nullptr,
handle base = handle())
: array(std::move(shape), std::move(strides), ptr, base) {}
explicit array_t(ShapeContainer shape, const T *ptr = nullptr, handle base = handle())
: array_t(private_ctor{},
......@@ -942,38 +1042,43 @@ public:
base) {}
explicit array_t(ssize_t count, const T *ptr = nullptr, handle base = handle())
: array({count}, {}, ptr, base) { }
: array({count}, {}, ptr, base) {}
constexpr ssize_t itemsize() const {
return sizeof(T);
}
constexpr ssize_t itemsize() const { return sizeof(T); }
template<typename... Ix> ssize_t index_at(Ix... index) const {
template <typename... Ix>
ssize_t index_at(Ix... index) const {
return offset_at(index...) / itemsize();
}
template<typename... Ix> const T* data(Ix... index) const {
return static_cast<const T*>(array::data(index...));
template <typename... Ix>
const T *data(Ix... index) const {
return static_cast<const T *>(array::data(index...));
}
template<typename... Ix> T* mutable_data(Ix... index) {
return static_cast<T*>(array::mutable_data(index...));
template <typename... Ix>
T *mutable_data(Ix... index) {
return static_cast<T *>(array::mutable_data(index...));
}
// Reference to element at a given index
template<typename... Ix> const T& at(Ix... index) const {
template <typename... Ix>
const T &at(Ix... index) const {
if ((ssize_t) sizeof...(index) != ndim()) {
fail_dim_check(sizeof...(index), "index dimension mismatch");
}
return *(static_cast<const T*>(array::data()) + byte_offset(ssize_t(index)...) / itemsize());
return *(static_cast<const T *>(array::data())
+ byte_offset(ssize_t(index)...) / itemsize());
}
// Mutable reference to element at a given index
template<typename... Ix> T& mutable_at(Ix... index) {
template <typename... Ix>
T &mutable_at(Ix... index) {
if ((ssize_t) sizeof...(index) != ndim()) {
fail_dim_check(sizeof...(index), "index dimension mismatch");
}
return *(static_cast<T*>(array::mutable_data()) + byte_offset(ssize_t(index)...) / itemsize());
return *(static_cast<T *>(array::mutable_data())
+ byte_offset(ssize_t(index)...) / itemsize());
}
/**
......@@ -982,7 +1087,8 @@ public:
* care: the array must not be destroyed or reshaped for the duration of the returned object,
* and the caller must take care not to access invalid dimensions or dimension indices.
*/
template <ssize_t Dims = -1> detail::unchecked_mutable_reference<T, Dims> mutable_unchecked() & {
template <ssize_t Dims = -1>
detail::unchecked_mutable_reference<T, Dims> mutable_unchecked() & {
return array::mutable_unchecked<T, Dims>();
}
......@@ -993,7 +1099,8 @@ public:
* for the duration of the returned object, and the caller must take care not to access invalid
* dimensions or dimension indices.
*/
template <ssize_t Dims = -1> detail::unchecked_reference<T, Dims> unchecked() const & {
template <ssize_t Dims = -1>
detail::unchecked_reference<T, Dims> unchecked() const & {
return array::unchecked<T, Dims>();
}
......@@ -1010,7 +1117,8 @@ public:
static bool check_(handle h) {
const auto &api = detail::npy_api::get();
return api.PyArray_Check_(h.ptr())
&& api.PyArray_EquivTypes_(detail::array_proxy(h.ptr())->descr, dtype::of<T>().ptr())
&& api.PyArray_EquivTypes_(detail::array_proxy(h.ptr())->descr,
dtype::of<T>().ptr())
&& detail::check_flags(h.ptr(), ExtraFlags & (array::c_style | array::f_style));
}
......@@ -1021,9 +1129,13 @@ protected:
PyErr_SetString(PyExc_ValueError, "cannot create a pybind11::array_t from a nullptr");
return nullptr;
}
return detail::npy_api::get().PyArray_FromAny_(
ptr, dtype::of<T>().release().ptr(), 0, 0,
detail::npy_api::NPY_ARRAY_ENSUREARRAY_ | ExtraFlags, nullptr);
return detail::npy_api::get().PyArray_FromAny_(ptr,
dtype::of<T>().release().ptr(),
0,
0,
detail::npy_api::NPY_ARRAY_ENSUREARRAY_
| ExtraFlags,
nullptr);
}
};
......@@ -1034,10 +1146,12 @@ struct format_descriptor<T, detail::enable_if_t<detail::is_pod_struct<T>::value>
}
};
template <size_t N> struct format_descriptor<char[N]> {
template <size_t N>
struct format_descriptor<char[N]> {
static std::string format() { return std::to_string(N) + "s"; }
};
template <size_t N> struct format_descriptor<std::array<char, N>> {
template <size_t N>
struct format_descriptor<std::array<char, N>> {
static std::string format() { return std::to_string(N) + "s"; }
};
......@@ -1079,7 +1193,7 @@ struct pyobject_caster<array_t<T, ExtraFlags>> {
template <typename T>
struct compare_buffer_info<T, detail::enable_if_t<detail::is_pod_struct<T>::value>> {
static bool compare(const buffer_info& b) {
static bool compare(const buffer_info &b) {
return npy_api::get().PyArray_EquivTypes_(dtype::of<T>().ptr(), dtype(b).ptr());
}
};
......@@ -1090,42 +1204,54 @@ struct npy_format_descriptor_name;
template <typename T>
struct npy_format_descriptor_name<T, enable_if_t<std::is_integral<T>::value>> {
static constexpr auto name = const_name<std::is_same<T, bool>::value>(
const_name("bool"), const_name<std::is_signed<T>::value>("numpy.int", "numpy.uint") + const_name<sizeof(T)*8>()
);
const_name("bool"),
const_name<std::is_signed<T>::value>("numpy.int", "numpy.uint")
+ const_name<sizeof(T) * 8>());
};
template <typename T>
struct npy_format_descriptor_name<T, enable_if_t<std::is_floating_point<T>::value>> {
static constexpr auto name = const_name<std::is_same<T, float>::value
static constexpr auto name = const_name < std::is_same<T, float>::value
|| std::is_same<T, const float>::value
|| std::is_same<T, double>::value
|| std::is_same<T, const double>::value>(
const_name("numpy.float") + const_name<sizeof(T)*8>(), const_name("numpy.longdouble")
);
|| std::is_same<T, const double>::value
> (const_name("numpy.float") + const_name<sizeof(T) * 8>(),
const_name("numpy.longdouble"));
};
template <typename T>
struct npy_format_descriptor_name<T, enable_if_t<is_complex<T>::value>> {
static constexpr auto name = const_name<std::is_same<typename T::value_type, float>::value
static constexpr auto name = const_name < std::is_same<typename T::value_type, float>::value
|| std::is_same<typename T::value_type, const float>::value
|| std::is_same<typename T::value_type, double>::value
|| std::is_same<typename T::value_type, const double>::value>(
const_name("numpy.complex") + const_name<sizeof(typename T::value_type)*16>(), const_name("numpy.longcomplex")
);
|| std::is_same<typename T::value_type, const double>::value
> (const_name("numpy.complex")
+ const_name<sizeof(typename T::value_type) * 16>(),
const_name("numpy.longcomplex"));
};
template <typename T>
struct npy_format_descriptor<T, enable_if_t<satisfies_any_of<T, std::is_arithmetic, is_complex>::value>>
struct npy_format_descriptor<
T,
enable_if_t<satisfies_any_of<T, std::is_arithmetic, is_complex>::value>>
: npy_format_descriptor_name<T> {
private:
// NB: the order here must match the one in common.h
constexpr static const int values[15] = {
npy_api::NPY_BOOL_,
npy_api::NPY_BYTE_, npy_api::NPY_UBYTE_, npy_api::NPY_INT16_, npy_api::NPY_UINT16_,
npy_api::NPY_INT32_, npy_api::NPY_UINT32_, npy_api::NPY_INT64_, npy_api::NPY_UINT64_,
npy_api::NPY_FLOAT_, npy_api::NPY_DOUBLE_, npy_api::NPY_LONGDOUBLE_,
npy_api::NPY_CFLOAT_, npy_api::NPY_CDOUBLE_, npy_api::NPY_CLONGDOUBLE_
};
constexpr static const int values[15] = {npy_api::NPY_BOOL_,
npy_api::NPY_BYTE_,
npy_api::NPY_UBYTE_,
npy_api::NPY_INT16_,
npy_api::NPY_UINT16_,
npy_api::NPY_INT32_,
npy_api::NPY_UINT32_,
npy_api::NPY_INT64_,
npy_api::NPY_UINT64_,
npy_api::NPY_FLOAT_,
npy_api::NPY_DOUBLE_,
npy_api::NPY_LONGDOUBLE_,
npy_api::NPY_CFLOAT_,
npy_api::NPY_CDOUBLE_,
npy_api::NPY_CLONGDOUBLE_};
public:
static constexpr int value = values[detail::is_fmt_numeric<T>::index];
......@@ -1140,18 +1266,29 @@ public:
#define PYBIND11_DECL_CHAR_FMT \
static constexpr auto name = const_name("S") + const_name<N>(); \
static pybind11::dtype dtype() { return pybind11::dtype(std::string("S") + std::to_string(N)); }
template <size_t N> struct npy_format_descriptor<char[N]> { PYBIND11_DECL_CHAR_FMT };
template <size_t N> struct npy_format_descriptor<std::array<char, N>> { PYBIND11_DECL_CHAR_FMT };
static pybind11::dtype dtype() { \
return pybind11::dtype(std::string("S") + std::to_string(N)); \
}
template <size_t N>
struct npy_format_descriptor<char[N]> {
PYBIND11_DECL_CHAR_FMT
};
template <size_t N>
struct npy_format_descriptor<std::array<char, N>> {
PYBIND11_DECL_CHAR_FMT
};
#undef PYBIND11_DECL_CHAR_FMT
template<typename T> struct npy_format_descriptor<T, enable_if_t<array_info<T>::is_array>> {
template <typename T>
struct npy_format_descriptor<T, enable_if_t<array_info<T>::is_array>> {
private:
using base_descr = npy_format_descriptor<typename array_info<T>::type>;
public:
static_assert(!array_info<T>::is_empty, "Zero-sized arrays are not supported");
static constexpr auto name = const_name("(") + array_info<T>::extents + const_name(")") + base_descr::name;
static constexpr auto name
= const_name("(") + array_info<T>::extents + const_name(")") + base_descr::name;
static pybind11::dtype dtype() {
list shape;
array_info<T>::append_extents(shape);
......@@ -1159,9 +1296,11 @@ public:
}
};
template<typename T> struct npy_format_descriptor<T, enable_if_t<std::is_enum<T>::value>> {
template <typename T>
struct npy_format_descriptor<T, enable_if_t<std::is_enum<T>::value>> {
private:
using base_descr = npy_format_descriptor<typename std::underlying_type<T>::type>;
public:
static constexpr auto name = base_descr::name;
static pybind11::dtype dtype() { return base_descr::dtype(); }
......@@ -1175,12 +1314,12 @@ struct field_descriptor {
dtype descr;
};
PYBIND11_NOINLINE void register_structured_dtype(
any_container<field_descriptor> fields,
const std::type_info& tinfo, ssize_t itemsize,
PYBIND11_NOINLINE void register_structured_dtype(any_container<field_descriptor> fields,
const std::type_info &tinfo,
ssize_t itemsize,
bool (*direct_converter)(PyObject *, void *&)) {
auto& numpy_internals = get_numpy_internals();
auto &numpy_internals = get_numpy_internals();
if (numpy_internals.get_type_info(tinfo, false)) {
pybind11_fail("NumPy: dtype is already registered");
}
......@@ -1188,11 +1327,13 @@ PYBIND11_NOINLINE void register_structured_dtype(
// Use ordered fields because order matters as of NumPy 1.14:
// https://docs.scipy.org/doc/numpy/release.html#multiple-field-indexing-assignment-of-structured-arrays
std::vector<field_descriptor> ordered_fields(std::move(fields));
std::sort(ordered_fields.begin(), ordered_fields.end(),
std::sort(
ordered_fields.begin(),
ordered_fields.end(),
[](const field_descriptor &a, const field_descriptor &b) { return a.offset < b.offset; });
list names, formats, offsets;
for (auto& field : ordered_fields) {
for (auto &field : ordered_fields) {
if (!field.descr) {
pybind11_fail(std::string("NumPy: unsupported field dtype: `") + field.name + "` @ "
+ tinfo.name());
......@@ -1221,7 +1362,7 @@ PYBIND11_NOINLINE void register_structured_dtype(
// overriding the endianness. Putting the ^ in front of individual fields
// isn't guaranteed to work due to https://github.com/numpy/numpy/issues/9049
oss << "^T{";
for (auto& field : ordered_fields) {
for (auto &field : ordered_fields) {
if (field.offset > offset) {
oss << (field.offset - offset) << 'x';
}
......@@ -1235,25 +1376,25 @@ PYBIND11_NOINLINE void register_structured_dtype(
auto format_str = oss.str();
// Sanity check: verify that NumPy properly parses our buffer format string
auto& api = npy_api::get();
auto &api = npy_api::get();
auto arr = array(buffer_info(nullptr, itemsize, format_str, 1));
if (!api.PyArray_EquivTypes_(dtype_ptr, arr.dtype().ptr())) {
pybind11_fail("NumPy: invalid buffer descriptor!");
}
auto tindex = std::type_index(tinfo);
numpy_internals.registered_dtypes[tindex] = { dtype_ptr, format_str };
numpy_internals.registered_dtypes[tindex] = {dtype_ptr, format_str};
get_internals().direct_conversions[tindex].push_back(direct_converter);
}
template <typename T, typename SFINAE> struct npy_format_descriptor {
static_assert(is_pod_struct<T>::value, "Attempt to use a non-POD or unimplemented POD type as a numpy dtype");
template <typename T, typename SFINAE>
struct npy_format_descriptor {
static_assert(is_pod_struct<T>::value,
"Attempt to use a non-POD or unimplemented POD type as a numpy dtype");
static constexpr auto name = make_caster<T>::name;
static pybind11::dtype dtype() {
return reinterpret_borrow<pybind11::dtype>(dtype_ptr());
}
static pybind11::dtype dtype() { return reinterpret_borrow<pybind11::dtype>(dtype_ptr()); }
static std::string format() {
static auto format_str = get_numpy_internals().get_type_info<T>(true)->format_str;
......@@ -1261,18 +1402,20 @@ template <typename T, typename SFINAE> struct npy_format_descriptor {
}
static void register_dtype(any_container<field_descriptor> fields) {
register_structured_dtype(std::move(fields), typeid(typename std::remove_cv<T>::type),
sizeof(T), &direct_converter);
register_structured_dtype(std::move(fields),
typeid(typename std::remove_cv<T>::type),
sizeof(T),
&direct_converter);
}
private:
static PyObject* dtype_ptr() {
static PyObject* ptr = get_numpy_internals().get_type_info<T>(true)->dtype_ptr;
static PyObject *dtype_ptr() {
static PyObject *ptr = get_numpy_internals().get_type_info<T>(true)->dtype_ptr;
return ptr;
}
static bool direct_converter(PyObject *obj, void*& value) {
auto& api = npy_api::get();
static bool direct_converter(PyObject *obj, void *&value) {
auto &api = npy_api::get();
if (!PyObject_TypeCheck(obj, api.PyVoidArrType_Type_)) {
return false;
}
......@@ -1287,78 +1430,80 @@ private:
};
#ifdef __CLION_IDE__ // replace heavy macro with dummy code for the IDE (doesn't affect code)
# define PYBIND11_NUMPY_DTYPE(Type, ...) ((void)0)
# define PYBIND11_NUMPY_DTYPE_EX(Type, ...) ((void)0)
# define PYBIND11_NUMPY_DTYPE(Type, ...) ((void) 0)
# define PYBIND11_NUMPY_DTYPE_EX(Type, ...) ((void) 0)
#else
#define PYBIND11_FIELD_DESCRIPTOR_EX(T, Field, Name) \
# define PYBIND11_FIELD_DESCRIPTOR_EX(T, Field, Name) \
::pybind11::detail::field_descriptor { \
Name, offsetof(T, Field), sizeof(decltype(std::declval<T>().Field)), \
::pybind11::format_descriptor<decltype(std::declval<T>().Field)>::format(), \
::pybind11::detail::npy_format_descriptor<decltype(std::declval<T>().Field)>::dtype() \
::pybind11::detail::npy_format_descriptor< \
decltype(std::declval<T>().Field)>::dtype() \
}
// Extract name, offset and format descriptor for a struct field
#define PYBIND11_FIELD_DESCRIPTOR(T, Field) PYBIND11_FIELD_DESCRIPTOR_EX(T, Field, #Field)
# define PYBIND11_FIELD_DESCRIPTOR(T, Field) PYBIND11_FIELD_DESCRIPTOR_EX(T, Field, # Field)
// The main idea of this macro is borrowed from https://github.com/swansontec/map-macro
// (C) William Swanson, Paul Fultz
#define PYBIND11_EVAL0(...) __VA_ARGS__
#define PYBIND11_EVAL1(...) PYBIND11_EVAL0 (PYBIND11_EVAL0 (PYBIND11_EVAL0 (__VA_ARGS__)))
#define PYBIND11_EVAL2(...) PYBIND11_EVAL1 (PYBIND11_EVAL1 (PYBIND11_EVAL1 (__VA_ARGS__)))
#define PYBIND11_EVAL3(...) PYBIND11_EVAL2 (PYBIND11_EVAL2 (PYBIND11_EVAL2 (__VA_ARGS__)))
#define PYBIND11_EVAL4(...) PYBIND11_EVAL3 (PYBIND11_EVAL3 (PYBIND11_EVAL3 (__VA_ARGS__)))
#define PYBIND11_EVAL(...) PYBIND11_EVAL4 (PYBIND11_EVAL4 (PYBIND11_EVAL4 (__VA_ARGS__)))
#define PYBIND11_MAP_END(...)
#define PYBIND11_MAP_OUT
#define PYBIND11_MAP_COMMA ,
#define PYBIND11_MAP_GET_END() 0, PYBIND11_MAP_END
#define PYBIND11_MAP_NEXT0(test, next, ...) next PYBIND11_MAP_OUT
#define PYBIND11_MAP_NEXT1(test, next) PYBIND11_MAP_NEXT0 (test, next, 0)
#define PYBIND11_MAP_NEXT(test, next) PYBIND11_MAP_NEXT1 (PYBIND11_MAP_GET_END test, next)
#if defined(_MSC_VER) && !defined(__clang__) // MSVC is not as eager to expand macros, hence this workaround
#define PYBIND11_MAP_LIST_NEXT1(test, next) \
PYBIND11_EVAL0 (PYBIND11_MAP_NEXT0 (test, PYBIND11_MAP_COMMA next, 0))
#else
#define PYBIND11_MAP_LIST_NEXT1(test, next) \
PYBIND11_MAP_NEXT0 (test, PYBIND11_MAP_COMMA next, 0)
#endif
#define PYBIND11_MAP_LIST_NEXT(test, next) \
PYBIND11_MAP_LIST_NEXT1 (PYBIND11_MAP_GET_END test, next)
#define PYBIND11_MAP_LIST0(f, t, x, peek, ...) \
f(t, x) PYBIND11_MAP_LIST_NEXT (peek, PYBIND11_MAP_LIST1) (f, t, peek, __VA_ARGS__)
#define PYBIND11_MAP_LIST1(f, t, x, peek, ...) \
f(t, x) PYBIND11_MAP_LIST_NEXT (peek, PYBIND11_MAP_LIST0) (f, t, peek, __VA_ARGS__)
# define PYBIND11_EVAL0(...) __VA_ARGS__
# define PYBIND11_EVAL1(...) PYBIND11_EVAL0(PYBIND11_EVAL0(PYBIND11_EVAL0(__VA_ARGS__)))
# define PYBIND11_EVAL2(...) PYBIND11_EVAL1(PYBIND11_EVAL1(PYBIND11_EVAL1(__VA_ARGS__)))
# define PYBIND11_EVAL3(...) PYBIND11_EVAL2(PYBIND11_EVAL2(PYBIND11_EVAL2(__VA_ARGS__)))
# define PYBIND11_EVAL4(...) PYBIND11_EVAL3(PYBIND11_EVAL3(PYBIND11_EVAL3(__VA_ARGS__)))
# define PYBIND11_EVAL(...) PYBIND11_EVAL4(PYBIND11_EVAL4(PYBIND11_EVAL4(__VA_ARGS__)))
# define PYBIND11_MAP_END(...)
# define PYBIND11_MAP_OUT
# define PYBIND11_MAP_COMMA ,
# define PYBIND11_MAP_GET_END() 0, PYBIND11_MAP_END
# define PYBIND11_MAP_NEXT0(test, next, ...) next PYBIND11_MAP_OUT
# define PYBIND11_MAP_NEXT1(test, next) PYBIND11_MAP_NEXT0(test, next, 0)
# define PYBIND11_MAP_NEXT(test, next) PYBIND11_MAP_NEXT1(PYBIND11_MAP_GET_END test, next)
# if defined(_MSC_VER) \
&& !defined(__clang__) // MSVC is not as eager to expand macros, hence this workaround
# define PYBIND11_MAP_LIST_NEXT1(test, next) \
PYBIND11_EVAL0(PYBIND11_MAP_NEXT0(test, PYBIND11_MAP_COMMA next, 0))
# else
# define PYBIND11_MAP_LIST_NEXT1(test, next) \
PYBIND11_MAP_NEXT0(test, PYBIND11_MAP_COMMA next, 0)
# endif
# define PYBIND11_MAP_LIST_NEXT(test, next) \
PYBIND11_MAP_LIST_NEXT1(PYBIND11_MAP_GET_END test, next)
# define PYBIND11_MAP_LIST0(f, t, x, peek, ...) \
f(t, x) PYBIND11_MAP_LIST_NEXT(peek, PYBIND11_MAP_LIST1)(f, t, peek, __VA_ARGS__)
# define PYBIND11_MAP_LIST1(f, t, x, peek, ...) \
f(t, x) PYBIND11_MAP_LIST_NEXT(peek, PYBIND11_MAP_LIST0)(f, t, peek, __VA_ARGS__)
// PYBIND11_MAP_LIST(f, t, a1, a2, ...) expands to f(t, a1), f(t, a2), ...
#define PYBIND11_MAP_LIST(f, t, ...) \
PYBIND11_EVAL (PYBIND11_MAP_LIST1 (f, t, __VA_ARGS__, (), 0))
#define PYBIND11_NUMPY_DTYPE(Type, ...) \
::pybind11::detail::npy_format_descriptor<Type>::register_dtype \
(::std::vector<::pybind11::detail::field_descriptor> \
{PYBIND11_MAP_LIST (PYBIND11_FIELD_DESCRIPTOR, Type, __VA_ARGS__)})
#if defined(_MSC_VER) && !defined(__clang__)
#define PYBIND11_MAP2_LIST_NEXT1(test, next) \
PYBIND11_EVAL0 (PYBIND11_MAP_NEXT0 (test, PYBIND11_MAP_COMMA next, 0))
#else
#define PYBIND11_MAP2_LIST_NEXT1(test, next) \
PYBIND11_MAP_NEXT0 (test, PYBIND11_MAP_COMMA next, 0)
#endif
#define PYBIND11_MAP2_LIST_NEXT(test, next) \
PYBIND11_MAP2_LIST_NEXT1 (PYBIND11_MAP_GET_END test, next)
#define PYBIND11_MAP2_LIST0(f, t, x1, x2, peek, ...) \
f(t, x1, x2) PYBIND11_MAP2_LIST_NEXT (peek, PYBIND11_MAP2_LIST1) (f, t, peek, __VA_ARGS__)
#define PYBIND11_MAP2_LIST1(f, t, x1, x2, peek, ...) \
f(t, x1, x2) PYBIND11_MAP2_LIST_NEXT (peek, PYBIND11_MAP2_LIST0) (f, t, peek, __VA_ARGS__)
# define PYBIND11_MAP_LIST(f, t, ...) \
PYBIND11_EVAL(PYBIND11_MAP_LIST1(f, t, __VA_ARGS__, (), 0))
# define PYBIND11_NUMPY_DTYPE(Type, ...) \
::pybind11::detail::npy_format_descriptor<Type>::register_dtype( \
::std::vector<::pybind11::detail::field_descriptor>{ \
PYBIND11_MAP_LIST(PYBIND11_FIELD_DESCRIPTOR, Type, __VA_ARGS__)})
# if defined(_MSC_VER) && !defined(__clang__)
# define PYBIND11_MAP2_LIST_NEXT1(test, next) \
PYBIND11_EVAL0(PYBIND11_MAP_NEXT0(test, PYBIND11_MAP_COMMA next, 0))
# else
# define PYBIND11_MAP2_LIST_NEXT1(test, next) \
PYBIND11_MAP_NEXT0(test, PYBIND11_MAP_COMMA next, 0)
# endif
# define PYBIND11_MAP2_LIST_NEXT(test, next) \
PYBIND11_MAP2_LIST_NEXT1(PYBIND11_MAP_GET_END test, next)
# define PYBIND11_MAP2_LIST0(f, t, x1, x2, peek, ...) \
f(t, x1, x2) PYBIND11_MAP2_LIST_NEXT(peek, PYBIND11_MAP2_LIST1)(f, t, peek, __VA_ARGS__)
# define PYBIND11_MAP2_LIST1(f, t, x1, x2, peek, ...) \
f(t, x1, x2) PYBIND11_MAP2_LIST_NEXT(peek, PYBIND11_MAP2_LIST0)(f, t, peek, __VA_ARGS__)
// PYBIND11_MAP2_LIST(f, t, a1, a2, ...) expands to f(t, a1, a2), f(t, a3, a4), ...
#define PYBIND11_MAP2_LIST(f, t, ...) \
PYBIND11_EVAL (PYBIND11_MAP2_LIST1 (f, t, __VA_ARGS__, (), 0))
# define PYBIND11_MAP2_LIST(f, t, ...) \
PYBIND11_EVAL(PYBIND11_MAP2_LIST1(f, t, __VA_ARGS__, (), 0))
#define PYBIND11_NUMPY_DTYPE_EX(Type, ...) \
::pybind11::detail::npy_format_descriptor<Type>::register_dtype \
(::std::vector<::pybind11::detail::field_descriptor> \
{PYBIND11_MAP2_LIST (PYBIND11_FIELD_DESCRIPTOR_EX, Type, __VA_ARGS__)})
# define PYBIND11_NUMPY_DTYPE_EX(Type, ...) \
::pybind11::detail::npy_format_descriptor<Type>::register_dtype( \
::std::vector<::pybind11::detail::field_descriptor>{ \
PYBIND11_MAP2_LIST(PYBIND11_FIELD_DESCRIPTOR_EX, Type, __VA_ARGS__)})
#endif // __CLION_IDE__
......@@ -1370,8 +1515,8 @@ public:
common_iterator() : m_strides() {}
common_iterator(void* ptr, const container_type& strides, const container_type& shape)
: p_ptr(reinterpret_cast<char*>(ptr)), m_strides(strides.size()) {
common_iterator(void *ptr, const container_type &strides, const container_type &shape)
: p_ptr(reinterpret_cast<char *>(ptr)), m_strides(strides.size()) {
m_strides.back() = static_cast<value_type>(strides.back());
for (size_type i = m_strides.size() - 1; i != 0; --i) {
size_type j = i - 1;
......@@ -1380,27 +1525,22 @@ public:
}
}
void increment(size_type dim) {
p_ptr += m_strides[dim];
}
void increment(size_type dim) { p_ptr += m_strides[dim]; }
void* data() const {
return p_ptr;
}
void *data() const { return p_ptr; }
private:
char *p_ptr{0};
container_type m_strides;
};
template <size_t N> class multi_array_iterator {
template <size_t N>
class multi_array_iterator {
public:
using container_type = std::vector<ssize_t>;
multi_array_iterator(const std::array<buffer_info, N> &buffers,
const container_type &shape)
: m_shape(shape.size()), m_index(shape.size(), 0),
m_common_iterator() {
multi_array_iterator(const std::array<buffer_info, N> &buffers, const container_type &shape)
: m_shape(shape.size()), m_index(shape.size(), 0), m_common_iterator() {
// Manual copy to avoid conversion warning if using std::copy
for (size_t i = 0; i < shape.size(); ++i) {
......@@ -1413,7 +1553,7 @@ public:
}
}
multi_array_iterator& operator++() {
multi_array_iterator &operator++() {
for (size_t j = m_index.size(); j != 0; --j) {
size_t i = j - 1;
if (++m_index[i] != m_shape[i]) {
......@@ -1425,12 +1565,12 @@ public:
return *this;
}
template <size_t K, class T = void> T* data() const {
return reinterpret_cast<T*>(m_common_iterator[K].data());
template <size_t K, class T = void>
T *data() const {
return reinterpret_cast<T *>(m_common_iterator[K].data());
}
private:
using common_iter = common_iterator;
void init_common_iterator(const buffer_info &buffer,
......@@ -1472,29 +1612,33 @@ private:
enum class broadcast_trivial { non_trivial, c_trivial, f_trivial };
// Populates the shape and number of dimensions for the set of buffers. Returns a broadcast_trivial
// enum value indicating whether the broadcast is "trivial"--that is, has each buffer being either a
// singleton or a full-size, C-contiguous (`c_trivial`) or Fortran-contiguous (`f_trivial`) storage
// buffer; returns `non_trivial` otherwise.
// Populates the shape and number of dimensions for the set of buffers. Returns a
// broadcast_trivial enum value indicating whether the broadcast is "trivial"--that is, has each
// buffer being either a singleton or a full-size, C-contiguous (`c_trivial`) or Fortran-contiguous
// (`f_trivial`) storage buffer; returns `non_trivial` otherwise.
template <size_t N>
broadcast_trivial broadcast(const std::array<buffer_info, N> &buffers, ssize_t &ndim, std::vector<ssize_t> &shape) {
ndim = std::accumulate(buffers.begin(), buffers.end(), ssize_t(0), [](ssize_t res, const buffer_info &buf) {
broadcast_trivial
broadcast(const std::array<buffer_info, N> &buffers, ssize_t &ndim, std::vector<ssize_t> &shape) {
ndim = std::accumulate(
buffers.begin(), buffers.end(), ssize_t(0), [](ssize_t res, const buffer_info &buf) {
return std::max(res, buf.ndim);
});
shape.clear();
shape.resize((size_t) ndim, 1);
// Figure out the output size, and make sure all input arrays conform (i.e. are either size 1 or
// the full size).
// Figure out the output size, and make sure all input arrays conform (i.e. are either size 1
// or the full size).
for (size_t i = 0; i < N; ++i) {
auto res_iter = shape.rbegin();
auto end = buffers[i].shape.rend();
for (auto shape_iter = buffers[i].shape.rbegin(); shape_iter != end; ++shape_iter, ++res_iter) {
for (auto shape_iter = buffers[i].shape.rbegin(); shape_iter != end;
++shape_iter, ++res_iter) {
const auto &dim_size_in = *shape_iter;
auto &dim_size_out = *res_iter;
// Each input dimension can either be 1 or `n`, but `n` values must match across buffers
// Each input dimension can either be 1 or `n`, but `n` values must match across
// buffers
if (dim_size_out == 1) {
dim_size_out = dim_size_in;
} else if (dim_size_in != 1 && dim_size_in != dim_size_out) {
......@@ -1524,8 +1668,10 @@ broadcast_trivial broadcast(const std::array<buffer_info, N> &buffers, ssize_t &
if (trivial_broadcast_c) {
ssize_t expect_stride = buffers[i].itemsize;
auto end = buffers[i].shape.crend();
for (auto shape_iter = buffers[i].shape.crbegin(), stride_iter = buffers[i].strides.crbegin();
trivial_broadcast_c && shape_iter != end; ++shape_iter, ++stride_iter) {
for (auto shape_iter = buffers[i].shape.crbegin(),
stride_iter = buffers[i].strides.crbegin();
trivial_broadcast_c && shape_iter != end;
++shape_iter, ++stride_iter) {
if (expect_stride == *stride_iter) {
expect_stride *= *shape_iter;
} else {
......@@ -1538,8 +1684,10 @@ broadcast_trivial broadcast(const std::array<buffer_info, N> &buffers, ssize_t &
if (trivial_broadcast_f) {
ssize_t expect_stride = buffers[i].itemsize;
auto end = buffers[i].shape.cend();
for (auto shape_iter = buffers[i].shape.cbegin(), stride_iter = buffers[i].strides.cbegin();
trivial_broadcast_f && shape_iter != end; ++shape_iter, ++stride_iter) {
for (auto shape_iter = buffers[i].shape.cbegin(),
stride_iter = buffers[i].strides.cbegin();
trivial_broadcast_f && shape_iter != end;
++shape_iter, ++stride_iter) {
if (expect_stride == *stride_iter) {
expect_stride *= *shape_iter;
} else {
......@@ -1549,28 +1697,31 @@ broadcast_trivial broadcast(const std::array<buffer_info, N> &buffers, ssize_t &
}
}
return
trivial_broadcast_c ? broadcast_trivial::c_trivial :
trivial_broadcast_f ? broadcast_trivial::f_trivial :
broadcast_trivial::non_trivial;
return trivial_broadcast_c ? broadcast_trivial::c_trivial
: trivial_broadcast_f ? broadcast_trivial::f_trivial
: broadcast_trivial::non_trivial;
}
template <typename T>
struct vectorize_arg {
static_assert(!std::is_rvalue_reference<T>::value, "Functions with rvalue reference arguments cannot be vectorized");
static_assert(!std::is_rvalue_reference<T>::value,
"Functions with rvalue reference arguments cannot be vectorized");
// The wrapped function gets called with this type:
using call_type = remove_reference_t<T>;
// Is this a vectorized argument?
static constexpr bool vectorize =
satisfies_any_of<call_type, std::is_arithmetic, is_complex, is_pod>::value &&
satisfies_none_of<call_type, std::is_pointer, std::is_array, is_std_array, std::is_enum>::value &&
(!std::is_reference<T>::value ||
(std::is_lvalue_reference<T>::value && std::is_const<call_type>::value));
static constexpr bool vectorize
= satisfies_any_of<call_type, std::is_arithmetic, is_complex, is_pod>::value
&& satisfies_none_of<call_type,
std::is_pointer,
std::is_array,
is_std_array,
std::is_enum>::value
&& (!std::is_reference<T>::value
|| (std::is_lvalue_reference<T>::value && std::is_const<call_type>::value));
// Accept this type: an array for vectorized types, otherwise the type as-is:
using type = conditional_t<vectorize, array_t<remove_cv_t<call_type>, array::forcecast>, T>;
};
// py::vectorize when a return type is present
template <typename Func, typename Return, typename... Args>
struct vectorize_returned_array {
......@@ -1583,17 +1734,11 @@ struct vectorize_returned_array {
return array_t<Return>(shape);
}
static Return *mutable_data(Type &array) {
return array.mutable_data();
}
static Return *mutable_data(Type &array) { return array.mutable_data(); }
static Return call(Func &f, Args &... args) {
return f(args...);
}
static Return call(Func &f, Args &...args) { return f(args...); }
static void call(Return *out, size_t i, Func &f, Args &... args) {
out[i] = f(args...);
}
static void call(Return *out, size_t i, Func &f, Args &...args) { out[i] = f(args...); }
};
// py::vectorize when a return type is not present
......@@ -1601,25 +1746,18 @@ template <typename Func, typename... Args>
struct vectorize_returned_array<Func, void, Args...> {
using Type = none;
static Type create(broadcast_trivial, const std::vector<ssize_t> &) {
return none();
}
static Type create(broadcast_trivial, const std::vector<ssize_t> &) { return none(); }
static void *mutable_data(Type &) {
return nullptr;
}
static void *mutable_data(Type &) { return nullptr; }
static detail::void_type call(Func &f, Args &... args) {
static detail::void_type call(Func &f, Args &...args) {
f(args...);
return {};
}
static void call(void *, size_t, Func &f, Args &... args) {
f(args...);
}
static void call(void *, size_t, Func &f, Args &...args) { f(args...); }
};
template <typename Func, typename Return, typename... Args>
struct vectorize_helper {
......@@ -1632,7 +1770,8 @@ private:
static constexpr size_t N = sizeof...(Args);
static constexpr size_t NVectorized = constexpr_sum(vectorize_arg<Args>::vectorize...);
static_assert(NVectorized >= 1,
static_assert(
NVectorized >= 1,
"pybind11::vectorize(...) requires a function with at least one vectorizable argument");
public:
......@@ -1652,10 +1791,11 @@ public:
private:
remove_reference_t<Func> f;
// Internal compiler error in MSVC 19.16.27025.1 (Visual Studio 2017 15.9.4), when compiling with "/permissive-" flag
// when arg_call_types is manually inlined.
// Internal compiler error in MSVC 19.16.27025.1 (Visual Studio 2017 15.9.4), when compiling
// with "/permissive-" flag when arg_call_types is manually inlined.
using arg_call_types = std::tuple<typename vectorize_arg<Args>::call_type...>;
template <size_t Index> using param_n_t = typename std::tuple_element<Index, arg_call_types>::type;
template <size_t Index>
using param_n_t = typename std::tuple_element<Index, arg_call_types>::type;
using returned_array = vectorize_returned_array<Func, Return, Args...>;
......@@ -1666,17 +1806,20 @@ private:
// - BIndex is a incremental sequence (beginning at 0) of the same size as VIndex, so that
// we can store vectorized buffer_infos in an array (argument VIndex has its buffer at
// index BIndex in the array).
template <size_t... Index, size_t... VIndex, size_t... BIndex> object run(
typename vectorize_arg<Args>::type &...args,
index_sequence<Index...> i_seq, index_sequence<VIndex...> vi_seq, index_sequence<BIndex...> bi_seq) {
template <size_t... Index, size_t... VIndex, size_t... BIndex>
object run(typename vectorize_arg<Args>::type &...args,
index_sequence<Index...> i_seq,
index_sequence<VIndex...> vi_seq,
index_sequence<BIndex...> bi_seq) {
// Pointers to values the function was called with; the vectorized ones set here will start
// out as array_t<T> pointers, but they will be changed them to T pointers before we make
// call the wrapped function. Non-vectorized pointers are left as-is.
std::array<void *, N> params{{ &args... }};
std::array<void *, N> params{{&args...}};
// The array of `buffer_info`s of vectorized arguments:
std::array<buffer_info, NVectorized> buffers{{ reinterpret_cast<array *>(params[VIndex])->request()... }};
std::array<buffer_info, NVectorized> buffers{
{reinterpret_cast<array *>(params[VIndex])->request()...}};
/* Determine dimensions parameters of output array */
ssize_t nd = 0;
......@@ -1684,13 +1827,15 @@ private:
auto trivial = broadcast(buffers, nd, shape);
auto ndim = (size_t) nd;
size_t size = std::accumulate(shape.begin(), shape.end(), (size_t) 1, std::multiplies<size_t>());
size_t size
= std::accumulate(shape.begin(), shape.end(), (size_t) 1, std::multiplies<size_t>());
// If all arguments are 0-dimension arrays (i.e. single values) return a plain value (i.e.
// not wrapped in an array).
if (size == 1 && ndim == 0) {
PYBIND11_EXPAND_SIDE_EFFECTS(params[VIndex] = buffers[BIndex].ptr);
return cast(returned_array::call(f, *reinterpret_cast<param_n_t<Index> *>(params[Index])...));
return cast(
returned_array::call(f, *reinterpret_cast<param_n_t<Index> *>(params[Index])...));
}
auto result = returned_array::create(trivial, shape);
......@@ -1715,20 +1860,21 @@ private:
std::array<void *, N> &params,
Return *out,
size_t size,
index_sequence<Index...>, index_sequence<VIndex...>, index_sequence<BIndex...>) {
index_sequence<Index...>,
index_sequence<VIndex...>,
index_sequence<BIndex...>) {
// Initialize an array of mutable byte references and sizes with references set to the
// appropriate pointer in `params`; as we iterate, we'll increment each pointer by its size
// (except for singletons, which get an increment of 0).
std::array<std::pair<unsigned char *&, const size_t>, NVectorized> vecparams{{
std::pair<unsigned char *&, const size_t>(
std::array<std::pair<unsigned char *&, const size_t>, NVectorized> vecparams{
{std::pair<unsigned char *&, const size_t>(
reinterpret_cast<unsigned char *&>(params[VIndex] = buffers[BIndex].ptr),
buffers[BIndex].size == 1 ? 0 : sizeof(param_n_t<VIndex>)
)...
}};
buffers[BIndex].size == 1 ? 0 : sizeof(param_n_t<VIndex>))...}};
for (size_t i = 0; i < size; ++i) {
returned_array::call(out, i, f, *reinterpret_cast<param_n_t<Index> *>(params[Index])...);
returned_array::call(
out, i, f, *reinterpret_cast<param_n_t<Index> *>(params[Index])...);
for (auto &x : vecparams) {
x.first += x.second;
}
......@@ -1741,55 +1887,70 @@ private:
Return *out,
size_t size,
const std::vector<ssize_t> &output_shape,
index_sequence<Index...>, index_sequence<VIndex...>, index_sequence<BIndex...>) {
index_sequence<Index...>,
index_sequence<VIndex...>,
index_sequence<BIndex...>) {
multi_array_iterator<NVectorized> input_iter(buffers, output_shape);
for (size_t i = 0; i < size; ++i, ++input_iter) {
PYBIND11_EXPAND_SIDE_EFFECTS((
params[VIndex] = input_iter.template data<BIndex>()
));
returned_array::call(out, i, f, *reinterpret_cast<param_n_t<Index> *>(std::get<Index>(params))...);
PYBIND11_EXPAND_SIDE_EFFECTS((params[VIndex] = input_iter.template data<BIndex>()));
returned_array::call(
out, i, f, *reinterpret_cast<param_n_t<Index> *>(std::get<Index>(params))...);
}
}
};
template <typename Func, typename Return, typename... Args>
vectorize_helper<Func, Return, Args...>
vectorize_extractor(const Func &f, Return (*) (Args ...)) {
vectorize_helper<Func, Return, Args...> vectorize_extractor(const Func &f, Return (*)(Args...)) {
return detail::vectorize_helper<Func, Return, Args...>(f);
}
template <typename T, int Flags> struct handle_type_name<array_t<T, Flags>> {
static constexpr auto name = const_name("numpy.ndarray[") + npy_format_descriptor<T>::name + const_name("]");
template <typename T, int Flags>
struct handle_type_name<array_t<T, Flags>> {
static constexpr auto name
= const_name("numpy.ndarray[") + npy_format_descriptor<T>::name + const_name("]");
};
PYBIND11_NAMESPACE_END(detail)
// Vanilla pointer vectorizer:
template <typename Return, typename... Args>
detail::vectorize_helper<Return (*)(Args...), Return, Args...>
vectorize(Return (*f) (Args ...)) {
detail::vectorize_helper<Return (*)(Args...), Return, Args...> vectorize(Return (*f)(Args...)) {
return detail::vectorize_helper<Return (*)(Args...), Return, Args...>(f);
}
// lambda vectorizer:
template <typename Func, detail::enable_if_t<detail::is_lambda<Func>::value, int> = 0>
auto vectorize(Func &&f) -> decltype(
detail::vectorize_extractor(std::forward<Func>(f), (detail::function_signature_t<Func> *) nullptr)) {
return detail::vectorize_extractor(std::forward<Func>(f), (detail::function_signature_t<Func> *) nullptr);
auto vectorize(Func &&f)
-> decltype(detail::vectorize_extractor(std::forward<Func>(f),
(detail::function_signature_t<Func> *) nullptr)) {
return detail::vectorize_extractor(std::forward<Func>(f),
(detail::function_signature_t<Func> *) nullptr);
}
// Vectorize a class method (non-const):
template <typename Return, typename Class, typename... Args,
typename Helper = detail::vectorize_helper<decltype(std::mem_fn(std::declval<Return (Class::*)(Args...)>())), Return, Class *, Args...>>
template <typename Return,
typename Class,
typename... Args,
typename Helper = detail::vectorize_helper<
decltype(std::mem_fn(std::declval<Return (Class::*)(Args...)>())),
Return,
Class *,
Args...>>
Helper vectorize(Return (Class::*f)(Args...)) {
return Helper(std::mem_fn(f));
}
// Vectorize a class method (const):
template <typename Return, typename Class, typename... Args,
typename Helper = detail::vectorize_helper<decltype(std::mem_fn(std::declval<Return (Class::*)(Args...) const>())), Return, const Class *, Args...>>
template <typename Return,
typename Class,
typename... Args,
typename Helper = detail::vectorize_helper<
decltype(std::mem_fn(std::declval<Return (Class::*)(Args...) const>())),
Return,
const Class *,
Args...>>
Helper vectorize(Return (Class::*f)(Args...) const) {
return Helper(std::mem_fn(f));
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment