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: ...@@ -141,11 +141,7 @@ repos:
entry: PyBind|Numpy|Cmake|CCache|PyTest entry: PyBind|Numpy|Cmake|CCache|PyTest
exclude: .pre-commit-config.yaml exclude: .pre-commit-config.yaml
- repo: local - repo: https://github.com/pre-commit/mirrors-clang-format
rev: "v13.0.0"
hooks: hooks:
- id: check-style - id: clang-format
name: Classic check-style
language: system
types:
- c++
entry: ./tools/check-style.sh
This diff is collapsed.
...@@ -44,8 +44,8 @@ struct buffer_info { ...@@ -44,8 +44,8 @@ struct buffer_info {
void *ptr = nullptr; // Pointer to the underlying storage void *ptr = nullptr; // Pointer to the underlying storage
ssize_t itemsize = 0; // Size of individual items in bytes ssize_t itemsize = 0; // Size of individual items in bytes
ssize_t size = 0; // Total number of entries ssize_t size = 0; // Total number of entries
std::string format; // For homogeneous buffers, this should be set to std::string format; // For homogeneous buffers, this should be set to
// format_descriptor<T>::format() // format_descriptor<T>::format()
ssize_t ndim = 0; // Number of dimensions ssize_t ndim = 0; // Number of dimensions
std::vector<ssize_t> shape; // Shape of the tensor (1 entry per dimension) std::vector<ssize_t> shape; // Shape of the tensor (1 entry per dimension)
std::vector<ssize_t> strides; // Number of bytes between adjacent entries std::vector<ssize_t> strides; // Number of bytes between adjacent entries
...@@ -54,10 +54,15 @@ struct buffer_info { ...@@ -54,10 +54,15 @@ struct buffer_info {
buffer_info() = default; buffer_info() = default;
buffer_info(void *ptr, ssize_t itemsize, const std::string &format, ssize_t ndim, buffer_info(void *ptr,
detail::any_container<ssize_t> shape_in, detail::any_container<ssize_t> strides_in, bool readonly=false) ssize_t itemsize,
: ptr(ptr), itemsize(itemsize), size(1), format(format), ndim(ndim), const std::string &format,
shape(std::move(shape_in)), strides(std::move(strides_in)), readonly(readonly) { 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()) { if (ndim != (ssize_t) shape.size() || ndim != (ssize_t) strides.size()) {
pybind11_fail("buffer_info: ndim doesn't match shape and/or strides length"); pybind11_fail("buffer_info: ndim doesn't match shape and/or strides length");
} }
...@@ -67,29 +72,48 @@ struct buffer_info { ...@@ -67,29 +72,48 @@ struct buffer_info {
} }
template <typename T> 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(T *ptr,
: 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) { } detail::any_container<ssize_t> shape_in,
detail::any_container<ssize_t> strides_in,
buffer_info(void *ptr, ssize_t itemsize, const std::string &format, ssize_t size, bool readonly=false) bool readonly = false)
: buffer_info(ptr, itemsize, format, 1, {size}, {itemsize}, readonly) { } : 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> template <typename T>
buffer_info(T *ptr, ssize_t size, bool readonly=false) buffer_info(T *ptr, ssize_t size, bool readonly = false)
: buffer_info(ptr, sizeof(T), format_descriptor<T>::format(), size, readonly) { } : buffer_info(ptr, sizeof(T), format_descriptor<T>::format(), size, readonly) {}
template <typename T> template <typename T>
buffer_info(const T *ptr, ssize_t size, bool readonly=true) 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_cast<T *>(ptr), sizeof(T), format_descriptor<T>::format(), size, readonly) {}
explicit buffer_info(Py_buffer *view, bool ownview = true) 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}, {view->shape, view->shape + view->ndim},
/* Though buffer::request() requests PyBUF_STRIDES, ctypes objects /* Though buffer::request() requests PyBUF_STRIDES, ctypes objects
* ignore this flag and return a view with NULL strides. * ignore this flag and return a view with NULL strides.
* When strides are NULL, build them manually. */ * When strides are NULL, build them manually. */
view->strides view->strides
? std::vector<ssize_t>(view->strides, view->strides + view->ndim) ? std::vector<ssize_t>(view->strides, view->strides + view->ndim)
: detail::c_strides({view->shape, view->shape + view->ndim}, view->itemsize), : detail::c_strides({view->shape, view->shape + view->ndim}, view->itemsize),
(view->readonly != 0)) { (view->readonly != 0)) {
// NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer) // NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer)
this->m_view = view; this->m_view = view;
...@@ -98,7 +122,7 @@ struct buffer_info { ...@@ -98,7 +122,7 @@ struct buffer_info {
} }
buffer_info(const buffer_info &) = delete; 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); } buffer_info(buffer_info &&other) noexcept { (*this) = std::move(other); }
...@@ -117,17 +141,28 @@ struct buffer_info { ...@@ -117,17 +141,28 @@ struct buffer_info {
} }
~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() const { return m_view; }
Py_buffer *&view() { 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, private:
detail::any_container<ssize_t> &&shape_in, detail::any_container<ssize_t> &&strides_in, bool readonly) struct private_ctr_tag {};
: buffer_info(ptr, itemsize, format, ndim, std::move(shape_in), std::move(strides_in), readonly) { }
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; Py_buffer *m_view = nullptr;
bool ownview = false; bool ownview = false;
...@@ -135,17 +170,22 @@ private: ...@@ -135,17 +170,22 @@ private:
PYBIND11_NAMESPACE_BEGIN(detail) PYBIND11_NAMESPACE_BEGIN(detail)
template <typename T, typename SFINAE = void> struct compare_buffer_info { template <typename T, typename SFINAE = void>
static bool compare(const buffer_info& b) { struct compare_buffer_info {
static bool compare(const buffer_info &b) {
return b.format == format_descriptor<T>::format() && b.itemsize == (ssize_t) sizeof(T); 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>> { template <typename T>
static bool compare(const buffer_info& b) { struct compare_buffer_info<T, detail::enable_if_t<std::is_integral<T>::value>> {
return (size_t) b.itemsize == sizeof(T) && (b.format == format_descriptor<T>::value || static bool compare(const buffer_info &b) {
((sizeof(T) == sizeof(long)) && b.format == (std::is_unsigned<T>::value ? "L" : "l")) || return (size_t) b.itemsize == sizeof(T)
((sizeof(T) == sizeof(size_t)) && b.format == (std::is_unsigned<T>::value ? "N" : "n"))); && (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")));
} }
}; };
......
This diff is collapsed.
...@@ -15,25 +15,25 @@ ...@@ -15,25 +15,25 @@
#include <chrono> #include <chrono>
#include <cmath> #include <cmath>
#include <ctime> #include <ctime>
#include <mutex>
#include <datetime.h> #include <datetime.h>
#include <mutex>
// Backport the PyDateTime_DELTA functions from Python3.3 if required // Backport the PyDateTime_DELTA functions from Python3.3 if required
#ifndef PyDateTime_DELTA_GET_DAYS #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 #endif
#ifndef PyDateTime_DELTA_GET_SECONDS #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 #endif
#ifndef PyDateTime_DELTA_GET_MICROSECONDS #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 #endif
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
PYBIND11_NAMESPACE_BEGIN(detail) PYBIND11_NAMESPACE_BEGIN(detail)
template <typename type> class duration_caster { template <typename type>
class duration_caster {
public: public:
using rep = typename type::rep; using rep = typename type::rep;
using period = typename type::period; using period = typename type::period;
...@@ -45,7 +45,9 @@ public: ...@@ -45,7 +45,9 @@ public:
using namespace std::chrono; using namespace std::chrono;
// Lazy initialise the PyDateTime import // Lazy initialise the PyDateTime import
if (!PyDateTimeAPI) { PyDateTime_IMPORT; } if (!PyDateTimeAPI) {
PyDateTime_IMPORT;
}
if (!src) { if (!src) {
return false; return false;
...@@ -53,26 +55,30 @@ public: ...@@ -53,26 +55,30 @@ public:
// If invoked with datetime.delta object // If invoked with datetime.delta object
if (PyDelta_Check(src.ptr())) { if (PyDelta_Check(src.ptr())) {
value = type(duration_cast<duration<rep, period>>( value = type(duration_cast<duration<rep, period>>(
days(PyDateTime_DELTA_GET_DAYS(src.ptr())) days(PyDateTime_DELTA_GET_DAYS(src.ptr()))
+ seconds(PyDateTime_DELTA_GET_SECONDS(src.ptr())) + seconds(PyDateTime_DELTA_GET_SECONDS(src.ptr()))
+ microseconds(PyDateTime_DELTA_GET_MICROSECONDS(src.ptr())))); + microseconds(PyDateTime_DELTA_GET_MICROSECONDS(src.ptr()))));
return true; return true;
} }
// If invoked with a float we assume it is seconds and convert // If invoked with a float we assume it is seconds and convert
if (PyFloat_Check(src.ptr())) { 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 true;
} }
return false; return false;
} }
// If this is a duration just return it back // 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; return src;
} }
// If this is a time_point get the time_since_epoch // 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(); return src.time_since_epoch();
} }
...@@ -84,9 +90,12 @@ public: ...@@ -84,9 +90,12 @@ public:
auto d = get_duration(src); auto d = get_duration(src);
// Lazy initialise the PyDateTime import // 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 dd_t = duration<int, std::ratio<86400>>;
using ss_t = duration<int, std::ratio<1>>; using ss_t = duration<int, std::ratio<1>>;
using us_t = duration<int, std::micro>; 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) { ...@@ -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 // 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: public:
using type = std::chrono::time_point<std::chrono::system_clock, Duration>; using type = std::chrono::time_point<std::chrono::system_clock, Duration>;
bool load(handle src, bool) { bool load(handle src, bool) {
using namespace std::chrono; using namespace std::chrono;
// Lazy initialise the PyDateTime import // Lazy initialise the PyDateTime import
if (!PyDateTimeAPI) { PyDateTime_IMPORT; } if (!PyDateTimeAPI) {
PyDateTime_IMPORT;
}
if (!src) { if (!src) {
return false; return false;
...@@ -135,32 +147,32 @@ public: ...@@ -135,32 +147,32 @@ public:
microseconds msecs; microseconds msecs;
if (PyDateTime_Check(src.ptr())) { if (PyDateTime_Check(src.ptr())) {
cal.tm_sec = PyDateTime_DATE_GET_SECOND(src.ptr()); cal.tm_sec = PyDateTime_DATE_GET_SECOND(src.ptr());
cal.tm_min = PyDateTime_DATE_GET_MINUTE(src.ptr()); cal.tm_min = PyDateTime_DATE_GET_MINUTE(src.ptr());
cal.tm_hour = PyDateTime_DATE_GET_HOUR(src.ptr()); cal.tm_hour = PyDateTime_DATE_GET_HOUR(src.ptr());
cal.tm_mday = PyDateTime_GET_DAY(src.ptr()); cal.tm_mday = PyDateTime_GET_DAY(src.ptr());
cal.tm_mon = PyDateTime_GET_MONTH(src.ptr()) - 1; cal.tm_mon = PyDateTime_GET_MONTH(src.ptr()) - 1;
cal.tm_year = PyDateTime_GET_YEAR(src.ptr()) - 1900; cal.tm_year = PyDateTime_GET_YEAR(src.ptr()) - 1900;
cal.tm_isdst = -1; cal.tm_isdst = -1;
msecs = microseconds(PyDateTime_DATE_GET_MICROSECOND(src.ptr())); msecs = microseconds(PyDateTime_DATE_GET_MICROSECOND(src.ptr()));
} else if (PyDate_Check(src.ptr())) { } else if (PyDate_Check(src.ptr())) {
cal.tm_sec = 0; cal.tm_sec = 0;
cal.tm_min = 0; cal.tm_min = 0;
cal.tm_hour = 0; cal.tm_hour = 0;
cal.tm_mday = PyDateTime_GET_DAY(src.ptr()); cal.tm_mday = PyDateTime_GET_DAY(src.ptr());
cal.tm_mon = PyDateTime_GET_MONTH(src.ptr()) - 1; cal.tm_mon = PyDateTime_GET_MONTH(src.ptr()) - 1;
cal.tm_year = PyDateTime_GET_YEAR(src.ptr()) - 1900; cal.tm_year = PyDateTime_GET_YEAR(src.ptr()) - 1900;
cal.tm_isdst = -1; cal.tm_isdst = -1;
msecs = microseconds(0); msecs = microseconds(0);
} else if (PyTime_Check(src.ptr())) { } else if (PyTime_Check(src.ptr())) {
cal.tm_sec = PyDateTime_TIME_GET_SECOND(src.ptr()); cal.tm_sec = PyDateTime_TIME_GET_SECOND(src.ptr());
cal.tm_min = PyDateTime_TIME_GET_MINUTE(src.ptr()); cal.tm_min = PyDateTime_TIME_GET_MINUTE(src.ptr());
cal.tm_hour = PyDateTime_TIME_GET_HOUR(src.ptr()); cal.tm_hour = PyDateTime_TIME_GET_HOUR(src.ptr());
cal.tm_mday = 1; // This date (day, month, year) = (1, 0, 70) cal.tm_mday = 1; // This date (day, month, year) = (1, 0, 70)
cal.tm_mon = 0; // represents 1-Jan-1970, which is the first cal.tm_mon = 0; // represents 1-Jan-1970, which is the first
cal.tm_year = 70; // earliest available date for Python's datetime cal.tm_year = 70; // earliest available date for Python's datetime
cal.tm_isdst = -1; cal.tm_isdst = -1;
msecs = microseconds(PyDateTime_TIME_GET_MICROSECOND(src.ptr())); msecs = microseconds(PyDateTime_TIME_GET_MICROSECOND(src.ptr()));
} else { } else {
return false; return false;
} }
...@@ -169,14 +181,18 @@ public: ...@@ -169,14 +181,18 @@ public:
return true; 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; using namespace std::chrono;
// Lazy initialise the PyDateTime import // 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 // Get out microseconds, and make sure they are positive, to avoid bug in eastern
// (cfr. https://github.com/pybind/pybind11/issues/2417) // hemisphere time zones (cfr. https://github.com/pybind/pybind11/issues/2417)
using us_t = duration<int, std::micro>; using us_t = duration<int, std::micro>;
auto us = duration_cast<us_t>(src.time_since_epoch() % seconds(1)); auto us = duration_cast<us_t>(src.time_since_epoch() % seconds(1));
if (us.count() < 0) { if (us.count() < 0) {
...@@ -184,9 +200,10 @@ public: ...@@ -184,9 +200,10 @@ public:
} }
// Subtract microseconds BEFORE `system_clock::to_time_t`, because: // 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. // > If std::time_t has lower precision, it is implementation-defined whether the value is
// (https://en.cppreference.com/w/cpp/chrono/system_clock/to_time_t) // 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::time_t tt
= system_clock::to_time_t(time_point_cast<system_clock::duration>(src - us));
std::tm localtime; std::tm localtime;
std::tm *localtime_ptr = localtime_thread_safe(&tt, &localtime); std::tm *localtime_ptr = localtime_thread_safe(&tt, &localtime);
...@@ -207,13 +224,13 @@ public: ...@@ -207,13 +224,13 @@ public:
// Other clocks that are not the system clock are not measured as datetime.datetime objects // 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 // 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 // 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>> template <typename Clock, typename Duration>
: public duration_caster<std::chrono::time_point<Clock, 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>> template <typename Rep, typename Period>
: public duration_caster<std::chrono::duration<Rep, Period>> { class type_caster<std::chrono::duration<Rep, Period>>
}; : public duration_caster<std::chrono::duration<Rep, Period>> {};
PYBIND11_NAMESPACE_END(detail) PYBIND11_NAMESPACE_END(detail)
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE) PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
...@@ -10,36 +10,42 @@ ...@@ -10,36 +10,42 @@
#pragma once #pragma once
#include "pybind11.h" #include "pybind11.h"
#include <complex> #include <complex>
/// glibc defines I as a macro which breaks things, e.g., boost template names /// glibc defines I as a macro which breaks things, e.g., boost template names
#ifdef I #ifdef I
# undef I # undef I
#endif #endif
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) 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 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); } static std::string format() { return std::string(value); }
}; };
#ifndef PYBIND11_CPP17 #ifndef PYBIND11_CPP17
template <typename T> constexpr const char format_descriptor< template <typename T>
std::complex<T>, detail::enable_if_t<std::is_floating_point<T>::value>>::value[3]; constexpr const char
format_descriptor<std::complex<T>,
detail::enable_if_t<std::is_floating_point<T>::value>>::value[3];
#endif #endif
PYBIND11_NAMESPACE_BEGIN(detail) 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 bool value = true;
static constexpr int index = is_fmt_numeric<T>::index + 3; 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: public:
bool load(handle src, bool convert) { bool load(handle src, bool convert) {
if (!src) { if (!src) {
...@@ -57,7 +63,8 @@ public: ...@@ -57,7 +63,8 @@ public:
return true; 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()); return PyComplex_FromDoubles((double) src.real(), (double) src.imag());
} }
......
...@@ -16,12 +16,13 @@ PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) ...@@ -16,12 +16,13 @@ PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
PYBIND11_NAMESPACE_BEGIN(detail) PYBIND11_NAMESPACE_BEGIN(detail)
#if PY_VERSION_HEX >= 0x03030000 && !defined(PYPY_VERSION) #if PY_VERSION_HEX >= 0x03030000 && !defined(PYPY_VERSION)
# define PYBIND11_BUILTIN_QUALNAME # define PYBIND11_BUILTIN_QUALNAME
# define PYBIND11_SET_OLDPY_QUALNAME(obj, nameobj) # define PYBIND11_SET_OLDPY_QUALNAME(obj, nameobj)
#else #else
// In pre-3.3 Python, we still set __qualname__ so that we can produce reliable function type // 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: // 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 #endif
inline std::string get_fully_qualified_tp_name(PyTypeObject *type) { inline std::string get_fully_qualified_tp_name(PyTypeObject *type) {
...@@ -71,9 +72,9 @@ inline PyTypeObject *make_static_property_type() { ...@@ -71,9 +72,9 @@ inline PyTypeObject *make_static_property_type() {
} }
heap_type->ht_name = name_obj.inc_ref().ptr(); 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(); heap_type->ht_qualname = name_obj.inc_ref().ptr();
#endif # endif
auto *type = &heap_type->ht_type; auto *type = &heap_type->ht_type;
type->tp_name = name; type->tp_name = name;
...@@ -107,8 +108,10 @@ inline PyTypeObject *make_static_property_type() { ...@@ -107,8 +108,10 @@ inline PyTypeObject *make_static_property_type() {
def __set__(self, obj, value): def __set__(self, obj, value):
cls = obj if isinstance(obj, type) else type(obj) cls = obj if isinstance(obj, type) else type(obj)
property.__set__(self, cls, value) property.__set__(self, cls, value)
)", Py_file_input, d.ptr(), d.ptr() )",
); Py_file_input,
d.ptr(),
d.ptr());
if (result == nullptr) if (result == nullptr)
throw error_already_set(); throw error_already_set();
Py_DECREF(result); Py_DECREF(result);
...@@ -121,7 +124,7 @@ inline PyTypeObject *make_static_property_type() { ...@@ -121,7 +124,7 @@ inline PyTypeObject *make_static_property_type() {
By default, Python replaces the `static_property` itself, but for wrapped C++ types 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 we need to call `static_property.__set__()` in order to propagate the new value to
the underlying C++ data structure. */ 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 // Use `_PyType_Lookup()` instead of `PyObject_GetAttr()` in order to get the raw
// descriptor (`property`) instead of calling `tp_descr_get` (`property.__get__()`). // descriptor (`property`) instead of calling `tp_descr_get` (`property.__get__()`).
PyObject *descr = _PyType_Lookup((PyTypeObject *) obj, name); PyObject *descr = _PyType_Lookup((PyTypeObject *) obj, name);
...@@ -184,7 +187,8 @@ extern "C" inline PyObject *pybind11_meta_call(PyObject *type, PyObject *args, P ...@@ -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 // Ensure that the base __init__ function(s) were called
for (const auto &vh : values_and_holders(instance)) { for (const auto &vh : values_and_holders(instance)) {
if (!vh.holder_constructed()) { 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()); get_fully_qualified_tp_name(vh.type->type).c_str());
Py_DECREF(self); Py_DECREF(self);
return nullptr; return nullptr;
...@@ -203,9 +207,8 @@ extern "C" inline void pybind11_meta_dealloc(PyObject *obj) { ...@@ -203,9 +207,8 @@ extern "C" inline void pybind11_meta_dealloc(PyObject *obj) {
// 1) be found in internals.registered_types_py // 1) be found in internals.registered_types_py
// 2) have exactly one associated `detail::type_info` // 2) have exactly one associated `detail::type_info`
auto found_type = internals.registered_types_py.find(type); auto found_type = internals.registered_types_py.find(type);
if (found_type != internals.registered_types_py.end() && if (found_type != internals.registered_types_py.end() && found_type->second.size() == 1
found_type->second.size() == 1 && && found_type->second[0]->type == type) {
found_type->second[0]->type == type) {
auto *tinfo = found_type->second[0]; auto *tinfo = found_type->second[0];
auto tindex = std::type_index(*tinfo->cpptype); auto tindex = std::type_index(*tinfo->cpptype);
...@@ -220,7 +223,7 @@ extern "C" inline void pybind11_meta_dealloc(PyObject *obj) { ...@@ -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 // Actually just `std::erase_if`, but that's only available in C++20
auto &cache = internals.inactive_override_cache; 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) { if (it->first == (PyObject *) tinfo->type) {
it = cache.erase(it); it = cache.erase(it);
} else { } else {
...@@ -237,7 +240,7 @@ extern "C" inline void pybind11_meta_dealloc(PyObject *obj) { ...@@ -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 /** 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`. for static properties to function correctly. Users may override this using `py::metaclass`.
Return value: New reference. */ Return value: New reference. */
inline PyTypeObject* make_default_metaclass() { inline PyTypeObject *make_default_metaclass() {
constexpr auto *name = "pybind11_type"; constexpr auto *name = "pybind11_type";
auto name_obj = reinterpret_steal<object>(PYBIND11_FROM_STRING(name)); auto name_obj = reinterpret_steal<object>(PYBIND11_FROM_STRING(name));
...@@ -281,9 +284,12 @@ inline PyTypeObject* make_default_metaclass() { ...@@ -281,9 +284,12 @@ inline PyTypeObject* make_default_metaclass() {
/// For multiple inheritance types we need to recursively register/deregister base pointers for any /// 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 /// 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. /// correctly recognize an offset base class pointer. This calls a function with any offset base
inline void traverse_offset_bases(void *valueptr, const detail::type_info *tinfo, instance *self, /// ptrs.
bool (*f)(void * /*parentptr*/, instance * /*self*/)) { 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)) { for (handle h : reinterpret_borrow<tuple>(tinfo->type->tp_bases)) {
if (auto *parent_tinfo = get_type_info((PyTypeObject *) h.ptr())) { if (auto *parent_tinfo = get_type_info((PyTypeObject *) h.ptr())) {
for (auto &c : parent_tinfo->implicit_casts) { for (auto &c : parent_tinfo->implicit_casts) {
...@@ -331,13 +337,13 @@ inline bool deregister_instance(instance *self, void *valptr, const type_info *t ...@@ -331,13 +337,13 @@ inline bool deregister_instance(instance *self, void *valptr, const type_info *t
return ret; return ret;
} }
/// Instance creation function for all pybind11 types. It allocates the internal instance layout for /// Instance creation function for all pybind11 types. It allocates the internal instance layout
/// holding C++ objects and holders. Allocation is done lazily (the first time the instance is cast /// for holding C++ objects and holders. Allocation is done lazily (the first time the instance is
/// to a reference or pointer), and initialization is done by an `__init__` function. /// cast to a reference or pointer), and initialization is done by an `__init__` function.
inline PyObject *make_new_instance(PyTypeObject *type) { inline PyObject *make_new_instance(PyTypeObject *type) {
#if defined(PYPY_VERSION) #if defined(PYPY_VERSION)
// PyPy gets tp_basicsize wrong (issue 2482) under multiple inheritance when the first inherited // PyPy gets tp_basicsize wrong (issue 2482) under multiple inheritance when the first
// object is a plain Python type (i.e. not derived from an extension type). Fix it. // 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)); ssize_t instance_size = static_cast<ssize_t>(sizeof(instance));
if (type->tp_basicsize < instance_size) { if (type->tp_basicsize < instance_size) {
type->tp_basicsize = instance_size; type->tp_basicsize = instance_size;
...@@ -511,7 +517,8 @@ extern "C" inline PyObject *pybind11_get_dict(PyObject *self, void *) { ...@@ -511,7 +517,8 @@ extern "C" inline PyObject *pybind11_get_dict(PyObject *self, void *) {
/// dynamic_attr: Support for `instance.__dict__ = dict()`. /// dynamic_attr: Support for `instance.__dict__ = dict()`.
extern "C" inline int pybind11_set_dict(PyObject *self, PyObject *new_dict, void *) { extern "C" inline int pybind11_set_dict(PyObject *self, PyObject *new_dict, void *) {
if (!PyDict_Check(new_dict)) { 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()); get_fully_qualified_tp_name(Py_TYPE(new_dict)).c_str());
return -1; return -1;
} }
...@@ -540,15 +547,14 @@ extern "C" inline int pybind11_clear(PyObject *self) { ...@@ -540,15 +547,14 @@ extern "C" inline int pybind11_clear(PyObject *self) {
inline void enable_dynamic_attributes(PyHeapTypeObject *heap_type) { inline void enable_dynamic_attributes(PyHeapTypeObject *heap_type) {
auto *type = &heap_type->ht_type; auto *type = &heap_type->ht_type;
type->tp_flags |= Py_TPFLAGS_HAVE_GC; type->tp_flags |= Py_TPFLAGS_HAVE_GC;
type->tp_dictoffset = type->tp_basicsize; // place dict at the end 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_traverse = pybind11_traverse;
type->tp_clear = pybind11_clear; type->tp_clear = pybind11_clear;
static PyGetSetDef getset[] = { static PyGetSetDef getset[] = {
{const_cast<char*>("__dict__"), pybind11_get_dict, pybind11_set_dict, nullptr, nullptr}, {const_cast<char *>("__dict__"), pybind11_get_dict, pybind11_set_dict, nullptr, nullptr},
{nullptr, nullptr, nullptr, nullptr, nullptr} {nullptr, nullptr, nullptr, nullptr, nullptr}};
};
type->tp_getset = getset; type->tp_getset = getset;
} }
...@@ -617,7 +623,7 @@ inline void enable_buffer_protocol(PyHeapTypeObject *heap_type) { ...@@ -617,7 +623,7 @@ inline void enable_buffer_protocol(PyHeapTypeObject *heap_type) {
/** Create a brand new Python type according to the `type_record` specification. /** Create a brand new Python type according to the `type_record` specification.
Return value: New reference. */ 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 name = reinterpret_steal<object>(PYBIND11_FROM_STRING(rec.name));
auto qualname = name; auto qualname = name;
...@@ -678,7 +684,7 @@ inline PyObject* make_new_python_type(const type_record &rec) { ...@@ -678,7 +684,7 @@ inline PyObject* make_new_python_type(const type_record &rec) {
auto *type = &heap_type->ht_type; auto *type = &heap_type->ht_type;
type->tp_name = full_name; type->tp_name = full_name;
type->tp_doc = tp_doc; 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)); type->tp_basicsize = static_cast<ssize_t>(sizeof(instance));
if (!bases.empty()) { if (!bases.empty()) {
type->tp_bases = bases.release().ptr(); type->tp_bases = bases.release().ptr();
......
This diff is collapsed.
...@@ -15,9 +15,9 @@ PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) ...@@ -15,9 +15,9 @@ PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
PYBIND11_NAMESPACE_BEGIN(detail) PYBIND11_NAMESPACE_BEGIN(detail)
#if !defined(_MSC_VER) #if !defined(_MSC_VER)
# define PYBIND11_DESCR_CONSTEXPR static constexpr # define PYBIND11_DESCR_CONSTEXPR static constexpr
#else #else
# define PYBIND11_DESCR_CONSTEXPR const # define PYBIND11_DESCR_CONSTEXPR const
#endif #endif
/* Concatenate type signatures at compile time */ /* Concatenate type signatures at compile time */
...@@ -27,14 +27,14 @@ struct descr { ...@@ -27,14 +27,14 @@ struct descr {
constexpr descr() = default; constexpr descr() = default;
// NOLINTNEXTLINE(google-explicit-constructor) // 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> 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> template <typename... Chars>
// NOLINTNEXTLINE(google-explicit-constructor) // 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() { static constexpr std::array<const std::type_info *, sizeof...(Ts) + 1> types() {
return {{&typeid(Ts)..., nullptr}}; return {{&typeid(Ts)..., nullptr}};
...@@ -42,81 +42,106 @@ struct descr { ...@@ -42,81 +42,106 @@ struct descr {
}; };
template <size_t N1, size_t N2, typename... Ts1, typename... Ts2, size_t... Is1, size_t... Is2> template <size_t N1, size_t N2, typename... Ts1, typename... Ts2, size_t... Is1, size_t... Is2>
constexpr descr<N1 + N2, Ts1..., Ts2...> plus_impl(const descr<N1, Ts1...> &a, const descr<N2, Ts2...> &b, constexpr descr<N1 + N2, Ts1..., Ts2...> plus_impl(const descr<N1, Ts1...> &a,
index_sequence<Is1...>, index_sequence<Is2...>) { const descr<N2, Ts2...> &b,
index_sequence<Is1...>,
index_sequence<Is2...>) {
PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(b); PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(b);
return {a.text[Is1]..., b.text[Is2]...}; return {a.text[Is1]..., b.text[Is2]...};
} }
template <size_t N1, size_t N2, typename... Ts1, typename... Ts2> 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>()); return plus_impl(a, b, make_index_sequence<N1>(), make_index_sequence<N2>());
} }
template <size_t N> template <size_t N>
constexpr descr<N - 1> const_name(char const(&text)[N]) { return descr<N - 1>(text); } constexpr descr<N - 1> const_name(char const (&text)[N]) {
constexpr descr<0> const_name(char const(&)[1]) { return {}; } 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 Rem, size_t... Digits>
template <size_t...Digits> struct int_to_str<0, 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. // WARNING: This only works with C++17 or higher.
static constexpr auto digits = descr<sizeof...(Digits)>(('0' + Digits)...); static constexpr auto digits = descr<sizeof...(Digits)>(('0' + Digits)...);
}; };
// Ternary description (like std::conditional) // Ternary description (like std::conditional)
template <bool B, size_t N1, size_t N2> 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); return const_name(text1);
} }
template <bool B, size_t N1, size_t N2> 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); return const_name(text2);
} }
template <bool B, typename T1, typename T2> 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> 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> template <size_t Size>
auto constexpr const_name() -> remove_cv_t<decltype(int_to_str<Size / 10, Size % 10>::digits)> { 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; 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. // If "_" is defined as a macro, py::detail::_ cannot be provided.
// It is therefore best to use py::detail::const_name universally. // It is therefore best to use py::detail::const_name universally.
// This block is for backward compatibility only. // This block is for backward compatibility only.
// (The const_name code is repeated to avoid introducing a "_" #define ourselves.) // (The const_name code is repeated to avoid introducing a "_" #define ourselves.)
#ifndef _ #ifndef _
#define PYBIND11_DETAIL_UNDERSCORE_BACKWARD_COMPATIBILITY # define PYBIND11_DETAIL_UNDERSCORE_BACKWARD_COMPATIBILITY
template <size_t N> 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> 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]) { constexpr enable_if_t<B, descr<N1 - 1>> _(char const (&text1)[N1], char const (&text2)[N2]) {
return const_name<B,N1,N2>(text1, text2); return const_name<B, N1, N2>(text1, text2);
} }
template <bool B, size_t N1, size_t N2> 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]) { constexpr enable_if_t<!B, descr<N2 - 1>> _(char const (&text1)[N1], char const (&text2)[N2]) {
return const_name<B,N1,N2>(text1, text2); return const_name<B, N1, N2>(text1, text2);
} }
template <bool B, typename T1, typename T2> 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> 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> template <size_t Size>
auto constexpr _() -> remove_cv_t<decltype(int_to_str<Size / 10, Size % 10>::digits)> { auto constexpr _() -> remove_cv_t<decltype(int_to_str<Size / 10, Size % 10>::digits)> {
return const_name<Size>(); return const_name<Size>();
} }
template <typename Type> constexpr descr<1, Type> _() { return const_name<Type>(); } template <typename Type>
#endif // #ifndef _ constexpr descr<1, Type> _() {
return const_name<Type>();
}
#endif // #ifndef _
constexpr descr<0> concat() { return {}; } constexpr descr<0> concat() { return {}; }
template <size_t N, typename... Ts> 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> template <size_t N, typename... Ts, typename... Args>
constexpr auto concat(const descr<N, Ts...> &d, const Args &...args) constexpr auto concat(const descr<N, Ts...> &d, const Args &...args)
......
...@@ -22,7 +22,8 @@ public: ...@@ -22,7 +22,8 @@ public:
return true; 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; } explicit operator value_and_holder &() { return *value; }
static constexpr auto name = const_name<value_and_holder>(); static constexpr auto name = const_name<value_and_holder>();
...@@ -39,11 +40,15 @@ inline void no_nullptr(void *ptr) { ...@@ -39,11 +40,15 @@ inline void no_nullptr(void *ptr) {
} }
// Implementing functions for all forms of py::init<...> and py::init(...) // Implementing functions for all forms of py::init<...> and py::init(...)
template <typename Class> using Cpp = typename Class::type; template <typename Class>
template <typename Class> using Alias = typename Class::type_alias; using Cpp = typename Class::type;
template <typename Class> using Holder = typename Class::holder_type; template <typename Class>
using Alias = typename Class::type_alias;
template <typename Class>
using Holder = typename Class::holder_type;
template <typename Class> using is_alias_constructible = std::is_constructible<Alias<Class>, Cpp<Class> &&>; template <typename Class>
using is_alias_constructible = std::is_constructible<Alias<Class>, Cpp<Class> &&>;
// Takes a Cpp pointer and returns true if it actually is a polymorphic Alias instance. // Takes a Cpp pointer and returns true if it actually is a polymorphic Alias instance.
template <typename Class, enable_if_t<Class::has_alias, int> = 0> template <typename Class, enable_if_t<Class::has_alias, int> = 0>
...@@ -52,17 +57,27 @@ bool is_alias(Cpp<Class> *ptr) { ...@@ -52,17 +57,27 @@ bool is_alias(Cpp<Class> *ptr) {
} }
// Failing fallback version of the above for a no-alias class (always returns false) // Failing fallback version of the above for a no-alias class (always returns false)
template <typename /*Class*/> 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 // 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 // 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 // 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 // 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). // 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> template <typename Class,
inline Class *construct_or_initialize(Args &&...args) { return new Class(std::forward<Args>(args)...); } typename... Args,
template <typename Class, typename... Args, detail::enable_if_t<!std::is_constructible<Class, Args...>::value, int> = 0> 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)...}; } 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 // 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 // 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 ...@@ -71,12 +86,14 @@ inline Class *construct_or_initialize(Args &&...args) { return new Class{std::fo
// inherit all the base class constructors. // inherit all the base class constructors.
template <typename Class> template <typename Class>
void construct_alias_from_cpp(std::true_type /*is_alias_constructible*/, 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)); v_h.value_ptr() = new Alias<Class>(std::move(base));
} }
template <typename Class> template <typename Class>
[[noreturn]] void construct_alias_from_cpp(std::false_type /*!is_alias_constructible*/, [[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 " throw type_error("pybind11::init(): unable to convert returned instance to required "
"alias class: no `Alias<Class>(Class &&)` constructor available"); "alias class: no `Alias<Class>(Class &&)` constructor available");
} }
...@@ -86,8 +103,8 @@ template <typename Class> ...@@ -86,8 +103,8 @@ template <typename Class>
template <typename Class> template <typename Class>
void construct(...) { void construct(...) {
static_assert(!std::is_same<Class, Class>::value /* always false */, static_assert(!std::is_same<Class, Class>::value /* always false */,
"pybind11::init(): init function must return a compatible pointer, " "pybind11::init(): init function must return a compatible pointer, "
"holder, or value"); "holder, or value");
} }
// Pointer return v1: the factory function returns a class pointer for a registered class. // Pointer return v1: the factory function returns a class pointer for a registered class.
...@@ -108,7 +125,7 @@ void construct(value_and_holder &v_h, Cpp<Class> *ptr, bool need_alias) { ...@@ -108,7 +125,7 @@ void construct(value_and_holder &v_h, Cpp<Class> *ptr, bool need_alias) {
// the holder and destruction happens when we leave the C++ scope, and the holder // the holder and destruction happens when we leave the C++ scope, and the holder
// class gets to handle the destruction however it likes. // class gets to handle the destruction however it likes.
v_h.value_ptr() = ptr; v_h.value_ptr() = ptr;
v_h.set_instance_registered(true); // To prevent init_instance from registering it v_h.set_instance_registered(true); // To prevent init_instance from registering it
v_h.type->init_instance(v_h.inst, nullptr); // Set up the holder v_h.type->init_instance(v_h.inst, nullptr); // Set up the holder
Holder<Class> temp_holder(std::move(v_h.holder<Holder<Class>>())); // Steal the holder Holder<Class> temp_holder(std::move(v_h.holder<Holder<Class>>())); // Steal the holder
v_h.type->dealloc(v_h); // Destroys the moved-out holder remains, resets value ptr to null v_h.type->dealloc(v_h); // Destroys the moved-out holder remains, resets value ptr to null
...@@ -131,7 +148,8 @@ void construct(value_and_holder &v_h, Alias<Class> *alias_ptr, bool) { ...@@ -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 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 // 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> template <typename Class>
void construct(value_and_holder &v_h, Holder<Class> holder, bool need_alias) { void construct(value_and_holder &v_h, Holder<Class> holder, bool need_alias) {
PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(need_alias); PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(need_alias);
...@@ -155,7 +173,7 @@ template <typename Class> ...@@ -155,7 +173,7 @@ template <typename Class>
void construct(value_and_holder &v_h, Cpp<Class> &&result, bool need_alias) { void construct(value_and_holder &v_h, Cpp<Class> &&result, bool need_alias) {
PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(need_alias); PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(need_alias);
static_assert(std::is_move_constructible<Cpp<Class>>::value, static_assert(std::is_move_constructible<Cpp<Class>>::value,
"pybind11::init() return-by-value factory function requires a movable class"); "pybind11::init() return-by-value factory function requires a movable class");
if (PYBIND11_SILENCE_MSVC_C4127(Class::has_alias) && need_alias) { if (PYBIND11_SILENCE_MSVC_C4127(Class::has_alias) && need_alias) {
construct_alias_from_cpp<Class>(is_alias_constructible<Class>{}, v_h, std::move(result)); construct_alias_from_cpp<Class>(is_alias_constructible<Class>{}, v_h, std::move(result));
} else { } else {
...@@ -168,7 +186,8 @@ void construct(value_and_holder &v_h, Cpp<Class> &&result, bool 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. // cases where Alias initialization is always desired.
template <typename Class> template <typename Class>
void construct(value_and_holder &v_h, Alias<Class> &&result, bool) { 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"); "pybind11::init() return-by-alias-value factory function requires a movable alias class");
v_h.value_ptr() = new Alias<Class>(std::move(result)); 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) { ...@@ -177,16 +196,21 @@ void construct(value_and_holder &v_h, Alias<Class> &&result, bool) {
template <typename... Args> template <typename... Args>
struct constructor { struct constructor {
template <typename Class, typename... Extra, enable_if_t<!Class::has_alias, int> = 0> template <typename Class, typename... Extra, enable_if_t<!Class::has_alias, int> = 0>
static void execute(Class &cl, const Extra&... extra) { static void execute(Class &cl, const Extra &...extra) {
cl.def("__init__", [](value_and_holder &v_h, Args... args) { cl.def(
v_h.value_ptr() = construct_or_initialize<Cpp<Class>>(std::forward<Args>(args)...); "__init__",
}, is_new_style_constructor(), extra...); [](value_and_holder &v_h, Args... args) {
v_h.value_ptr() = construct_or_initialize<Cpp<Class>>(std::forward<Args>(args)...);
},
is_new_style_constructor(),
extra...);
} }
template <typename Class, typename... Extra, template <typename Class,
enable_if_t<Class::has_alias && typename... Extra,
std::is_constructible<Cpp<Class>, Args...>::value, int> = 0> enable_if_t<Class::has_alias && std::is_constructible<Cpp<Class>, Args...>::value,
static void execute(Class &cl, const Extra&... extra) { int> = 0>
static void execute(Class &cl, const Extra &...extra) {
cl.def( cl.def(
"__init__", "__init__",
[](value_and_holder &v_h, Args... args) { [](value_and_holder &v_h, Args... args) {
...@@ -202,30 +226,46 @@ struct constructor { ...@@ -202,30 +226,46 @@ struct constructor {
extra...); extra...);
} }
template <typename Class, typename... Extra, template <typename Class,
enable_if_t<Class::has_alias && typename... Extra,
!std::is_constructible<Cpp<Class>, Args...>::value, int> = 0> enable_if_t<Class::has_alias && !std::is_constructible<Cpp<Class>, Args...>::value,
static void execute(Class &cl, const Extra&... extra) { int> = 0>
cl.def("__init__", [](value_and_holder &v_h, Args... args) { static void execute(Class &cl, const Extra &...extra) {
v_h.value_ptr() = construct_or_initialize<Alias<Class>>(std::forward<Args>(args)...); cl.def(
}, is_new_style_constructor(), extra...); "__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<...>() // Implementing class for py::init_alias<...>()
template <typename... Args> struct alias_constructor { template <typename... Args>
template <typename Class, typename... Extra, struct alias_constructor {
enable_if_t<Class::has_alias && std::is_constructible<Alias<Class>, Args...>::value, int> = 0> template <typename Class,
static void execute(Class &cl, const Extra&... extra) { typename... Extra,
cl.def("__init__", [](value_and_holder &v_h, Args... args) { enable_if_t<Class::has_alias && std::is_constructible<Alias<Class>, Args...>::value,
v_h.value_ptr() = construct_or_initialize<Alias<Class>>(std::forward<Args>(args)...); int> = 0>
}, is_new_style_constructor(), extra...); 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) // Implementation class for py::init(Func) and py::init(Func, AliasFunc)
template <typename CFunc, typename AFunc = void_type (*)(), template <typename CFunc,
typename = function_signature_t<CFunc>, typename = function_signature_t<AFunc>> typename AFunc = void_type (*)(),
typename = function_signature_t<CFunc>,
typename = function_signature_t<AFunc>>
struct factory; struct factory;
// Specialization for py::init(Func) // Specialization for py::init(Func)
...@@ -243,22 +283,32 @@ struct factory<Func, void_type (*)(), Return(Args...)> { ...@@ -243,22 +283,32 @@ struct factory<Func, void_type (*)(), Return(Args...)> {
// instance, or the alias needs to be constructible from a `Class &&` argument. // instance, or the alias needs to be constructible from a `Class &&` argument.
template <typename Class, typename... Extra> template <typename Class, typename... Extra>
void execute(Class &cl, const Extra &...extra) && { void execute(Class &cl, const Extra &...extra) && {
#if defined(PYBIND11_CPP14) #if defined(PYBIND11_CPP14)
cl.def("__init__", [func = std::move(class_factory)] cl.def(
#else "__init__",
[func = std::move(class_factory)]
#else
auto &func = class_factory; auto &func = class_factory;
cl.def("__init__", [func] cl.def(
#endif "__init__",
(value_and_holder &v_h, Args... args) { [func]
construct<Class>(v_h, func(std::forward<Args>(args)...), #endif
Py_TYPE(v_h.inst) != v_h.type->type); (value_and_holder &v_h, Args... args) {
}, 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) // Specialization for py::init(Func, AliasFunc)
template <typename CFunc, typename AFunc, template <typename CFunc,
typename CReturn, typename... CArgs, typename AReturn, typename... AArgs> typename AFunc,
typename CReturn,
typename... CArgs,
typename AReturn,
typename... AArgs>
struct factory<CFunc, AFunc, CReturn(CArgs...), AReturn(AArgs...)> { struct factory<CFunc, AFunc, CReturn(CArgs...), AReturn(AArgs...)> {
static_assert(sizeof...(CArgs) == sizeof...(AArgs), static_assert(sizeof...(CArgs) == sizeof...(AArgs),
"pybind11::init(class_factory, alias_factory): class and alias factories " "pybind11::init(class_factory, alias_factory): class and alias factories "
...@@ -271,30 +321,37 @@ struct factory<CFunc, AFunc, CReturn(CArgs...), AReturn(AArgs...)> { ...@@ -271,30 +321,37 @@ struct factory<CFunc, AFunc, CReturn(CArgs...), AReturn(AArgs...)> {
remove_reference_t<AFunc> alias_factory; remove_reference_t<AFunc> alias_factory;
factory(CFunc &&c, AFunc &&a) 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 // 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. // class (i.e. not inherited), the alias factory when `self` is a Python-side subtype.
template <typename Class, typename... Extra> template <typename Class, typename... Extra>
void execute(Class &cl, const Extra&... extra) && { void execute(Class &cl, const Extra &...extra) && {
static_assert(Class::has_alias, "The two-argument version of `py::init()` can " static_assert(Class::has_alias,
"only be used if the class has an alias"); "The two-argument version of `py::init()` can "
#if defined(PYBIND11_CPP14) "only be used if the class has an alias");
cl.def("__init__", [class_func = std::move(class_factory), alias_func = std::move(alias_factory)] #if defined(PYBIND11_CPP14)
#else cl.def(
"__init__",
[class_func = std::move(class_factory), alias_func = std::move(alias_factory)]
#else
auto &class_func = class_factory; auto &class_func = class_factory;
auto &alias_func = alias_factory; auto &alias_func = alias_factory;
cl.def("__init__", [class_func, alias_func] cl.def(
#endif "__init__",
(value_and_holder &v_h, CArgs... args) { [class_func, alias_func]
if (Py_TYPE(v_h.inst) == v_h.type->type) { #endif
// If the instance type equals the registered type we don't have inheritance, so (value_and_holder &v_h, CArgs... args) {
// don't need the alias and can construct using the class function: if (Py_TYPE(v_h.inst) == v_h.type->type) {
construct<Class>(v_h, class_func(std::forward<CArgs>(args)...), false); // If the instance type equals the registered type we don't have inheritance,
} else { // so don't need the alias and can construct using the class function:
construct<Class>(v_h, alias_func(std::forward<CArgs>(args)...), true); construct<Class>(v_h, class_func(std::forward<CArgs>(args)...), false);
} } else {
}, is_new_style_constructor(), extra...); construct<Class>(v_h, alias_func(std::forward<CArgs>(args)...), true);
}
},
is_new_style_constructor(),
extra...);
} }
}; };
...@@ -305,7 +362,9 @@ void setstate(value_and_holder &v_h, T &&result, bool need_alias) { ...@@ -305,7 +362,9 @@ void setstate(value_and_holder &v_h, T &&result, bool need_alias) {
} }
/// Set both the C++ and Python states /// 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> 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) { 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); 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) ...@@ -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) /// Implementation for py::pickle(GetState, SetState)
template <typename Get, typename Set, template <typename Get,
typename = function_signature_t<Get>, typename = function_signature_t<Set>> typename Set,
typename = function_signature_t<Get>,
typename = function_signature_t<Set>>
struct pickle_factory; struct pickle_factory;
template <typename Get, typename Set, template <typename Get,
typename RetState, typename Self, typename NewInstance, typename ArgState> typename Set,
typename RetState,
typename Self,
typename NewInstance,
typename ArgState>
struct pickle_factory<Get, Set, RetState(Self), NewInstance(ArgState)> { struct pickle_factory<Get, Set, RetState(Self), NewInstance(ArgState)> {
static_assert(std::is_same<intrinsic_t<RetState>, intrinsic_t<ArgState>>::value, static_assert(std::is_same<intrinsic_t<RetState>, intrinsic_t<ArgState>>::value,
"The type returned by `__getstate__` must be the same " "The type returned by `__getstate__` must be the same "
...@@ -333,23 +398,28 @@ struct pickle_factory<Get, Set, RetState(Self), NewInstance(ArgState)> { ...@@ -333,23 +398,28 @@ struct pickle_factory<Get, Set, RetState(Self), NewInstance(ArgState)> {
remove_reference_t<Get> get; remove_reference_t<Get> get;
remove_reference_t<Set> set; remove_reference_t<Set> set;
pickle_factory(Get get, Set set) pickle_factory(Get get, Set set) : get(std::forward<Get>(get)), set(std::forward<Set>(set)) {}
: get(std::forward<Get>(get)), set(std::forward<Set>(set)) { }
template <typename Class, typename... Extra> template <typename Class, typename... Extra>
void execute(Class &cl, const Extra &...extra) && { void execute(Class &cl, const Extra &...extra) && {
cl.def("__getstate__", std::move(get)); cl.def("__getstate__", std::move(get));
#if defined(PYBIND11_CPP14) #if defined(PYBIND11_CPP14)
cl.def("__setstate__", [func = std::move(set)] cl.def(
"__setstate__",
[func = std::move(set)]
#else #else
auto &func = set; auto &func = set;
cl.def("__setstate__", [func] cl.def(
"__setstate__",
[func]
#endif #endif
(value_and_holder &v_h, ArgState state) { (value_and_holder &v_h, ArgState state) {
setstate<Class>(v_h, func(std::forward<ArgState>(state)), setstate<Class>(
Py_TYPE(v_h.inst) != v_h.type->type); v_h, func(std::forward<ArgState>(state)), Py_TYPE(v_h.inst) != v_h.type->type);
}, is_new_style_constructor(), extra...); },
is_new_style_constructor(),
extra...);
} }
}; };
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#pragma once #pragma once
#include "../pytypes.h" #include "../pytypes.h"
#include <exception> #include <exception>
/// Tracks the `internals` and `type_info` ABI version independent of the main library version. /// Tracks the `internals` and `type_info` ABI version independent of the main library version.
...@@ -136,9 +137,9 @@ template <typename value_type> ...@@ -136,9 +137,9 @@ template <typename value_type>
using type_map = std::unordered_map<std::type_index, value_type, type_hash, type_equal_to>; using type_map = std::unordered_map<std::type_index, value_type, type_hash, type_equal_to>;
struct override_hash { 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); 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; return value;
} }
}; };
...@@ -151,8 +152,9 @@ struct internals { ...@@ -151,8 +152,9 @@ struct internals {
type_map<type_info *> registered_types_cpp; type_map<type_info *> registered_types_cpp;
// PyTypeObject* -> base type_info(s) // PyTypeObject* -> base type_info(s)
std::unordered_map<PyTypeObject *, std::vector<type_info *>> registered_types_py; std::unordered_map<PyTypeObject *, std::vector<type_info *>> registered_types_py;
std::unordered_multimap<const void *, instance*> registered_instances; // void * -> instance* 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_set<std::pair<const PyObject *, const char *>, override_hash>
inactive_override_cache;
type_map<std::vector<bool (*)(PyObject *, void *&)>> direct_conversions; type_map<std::vector<bool (*)(PyObject *, void *&)>> direct_conversions;
std::unordered_map<const PyObject *, std::vector<PyObject *>> patients; std::unordered_map<const PyObject *, std::vector<PyObject *>> patients;
std::forward_list<ExceptionTranslator> registered_exception_translators; std::forward_list<ExceptionTranslator> registered_exception_translators;
...@@ -198,8 +200,8 @@ struct type_info { ...@@ -198,8 +200,8 @@ struct type_info {
void *(*operator_new)(size_t); void *(*operator_new)(size_t);
void (*init_instance)(instance *, const void *); void (*init_instance)(instance *, const void *);
void (*dealloc)(value_and_holder &v_h); void (*dealloc)(value_and_holder &v_h);
std::vector<PyObject *(*)(PyObject *, PyTypeObject *)> implicit_conversions; std::vector<PyObject *(*) (PyObject *, PyTypeObject *)> implicit_conversions;
std::vector<std::pair<const std::type_info *, void *(*)(void *)>> implicit_casts; std::vector<std::pair<const std::type_info *, void *(*) (void *)>> implicit_casts;
std::vector<bool (*)(PyObject *, void *&)> *direct_conversions; std::vector<bool (*)(PyObject *, void *&)> *direct_conversions;
buffer_info *(*get_buffer)(PyObject *, void *) = nullptr; buffer_info *(*get_buffer)(PyObject *, void *) = nullptr;
void *get_buffer_data = nullptr; void *get_buffer_data = nullptr;
...@@ -219,67 +221,71 @@ struct type_info { ...@@ -219,67 +221,71 @@ struct type_info {
/// On MSVC, debug and release builds are not ABI-compatible! /// On MSVC, debug and release builds are not ABI-compatible!
#if defined(_MSC_VER) && defined(_DEBUG) #if defined(_MSC_VER) && defined(_DEBUG)
# define PYBIND11_BUILD_TYPE "_debug" # define PYBIND11_BUILD_TYPE "_debug"
#else #else
# define PYBIND11_BUILD_TYPE "" # define PYBIND11_BUILD_TYPE ""
#endif #endif
/// Let's assume that different compilers are ABI-incompatible. /// Let's assume that different compilers are ABI-incompatible.
/// A user can manually set this string if they know their /// A user can manually set this string if they know their
/// compiler is compatible. /// compiler is compatible.
#ifndef PYBIND11_COMPILER_TYPE #ifndef PYBIND11_COMPILER_TYPE
# if defined(_MSC_VER) # if defined(_MSC_VER)
# define PYBIND11_COMPILER_TYPE "_msvc" # define PYBIND11_COMPILER_TYPE "_msvc"
# elif defined(__INTEL_COMPILER) # elif defined(__INTEL_COMPILER)
# define PYBIND11_COMPILER_TYPE "_icc" # define PYBIND11_COMPILER_TYPE "_icc"
# elif defined(__clang__) # elif defined(__clang__)
# define PYBIND11_COMPILER_TYPE "_clang" # define PYBIND11_COMPILER_TYPE "_clang"
# elif defined(__PGI) # elif defined(__PGI)
# define PYBIND11_COMPILER_TYPE "_pgi" # define PYBIND11_COMPILER_TYPE "_pgi"
# elif defined(__MINGW32__) # elif defined(__MINGW32__)
# define PYBIND11_COMPILER_TYPE "_mingw" # define PYBIND11_COMPILER_TYPE "_mingw"
# elif defined(__CYGWIN__) # elif defined(__CYGWIN__)
# define PYBIND11_COMPILER_TYPE "_gcc_cygwin" # define PYBIND11_COMPILER_TYPE "_gcc_cygwin"
# elif defined(__GNUC__) # elif defined(__GNUC__)
# define PYBIND11_COMPILER_TYPE "_gcc" # define PYBIND11_COMPILER_TYPE "_gcc"
# else # else
# define PYBIND11_COMPILER_TYPE "_unknown" # define PYBIND11_COMPILER_TYPE "_unknown"
# endif # endif
#endif #endif
/// Also standard libs /// Also standard libs
#ifndef PYBIND11_STDLIB #ifndef PYBIND11_STDLIB
# if defined(_LIBCPP_VERSION) # if defined(_LIBCPP_VERSION)
# define PYBIND11_STDLIB "_libcpp" # define PYBIND11_STDLIB "_libcpp"
# elif defined(__GLIBCXX__) || defined(__GLIBCPP__) # elif defined(__GLIBCXX__) || defined(__GLIBCPP__)
# define PYBIND11_STDLIB "_libstdcpp" # define PYBIND11_STDLIB "_libstdcpp"
# else # else
# define PYBIND11_STDLIB "" # define PYBIND11_STDLIB ""
# endif # endif
#endif #endif
/// On Linux/OSX, changes in __GXX_ABI_VERSION__ indicate ABI incompatibility. /// On Linux/OSX, changes in __GXX_ABI_VERSION__ indicate ABI incompatibility.
#ifndef PYBIND11_BUILD_ABI #ifndef PYBIND11_BUILD_ABI
# if defined(__GXX_ABI_VERSION) # if defined(__GXX_ABI_VERSION)
# define PYBIND11_BUILD_ABI "_cxxabi" PYBIND11_TOSTRING(__GXX_ABI_VERSION) # define PYBIND11_BUILD_ABI "_cxxabi" PYBIND11_TOSTRING(__GXX_ABI_VERSION)
# else # else
# define PYBIND11_BUILD_ABI "" # define PYBIND11_BUILD_ABI ""
# endif # endif
#endif #endif
#ifndef PYBIND11_INTERNALS_KIND #ifndef PYBIND11_INTERNALS_KIND
# if defined(WITH_THREAD) # if defined(WITH_THREAD)
# define PYBIND11_INTERNALS_KIND "" # define PYBIND11_INTERNALS_KIND ""
# else # else
# define PYBIND11_INTERNALS_KIND "_without_thread" # define PYBIND11_INTERNALS_KIND "_without_thread"
# endif # endif
#endif #endif
#define PYBIND11_INTERNALS_ID "__pybind11_internals_v" \ #define PYBIND11_INTERNALS_ID \
PYBIND11_TOSTRING(PYBIND11_INTERNALS_VERSION) PYBIND11_INTERNALS_KIND PYBIND11_COMPILER_TYPE PYBIND11_STDLIB PYBIND11_BUILD_ABI PYBIND11_BUILD_TYPE "__" "__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" \ #define PYBIND11_MODULE_LOCAL_ID \
PYBIND11_TOSTRING(PYBIND11_INTERNALS_VERSION) PYBIND11_INTERNALS_KIND PYBIND11_COMPILER_TYPE PYBIND11_STDLIB PYBIND11_BUILD_ABI PYBIND11_BUILD_TYPE "__" "__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 /// Each module locally stores a pointer to the `internals` data. The data
/// itself is shared among modules with the same `PYBIND11_INTERNALS_ID`. /// itself is shared among modules with the same `PYBIND11_INTERNALS_ID`.
...@@ -396,8 +402,12 @@ inline void translate_local_exception(std::exception_ptr p) { ...@@ -396,8 +402,12 @@ inline void translate_local_exception(std::exception_ptr p) {
if (p) { if (p) {
std::rethrow_exception(p); std::rethrow_exception(p);
} }
} catch (error_already_set &e) { e.restore(); return; } catch (error_already_set &e) {
} catch (const builtin_exception &e) { e.set_error(); return; e.restore();
return;
} catch (const builtin_exception &e) {
e.set_error();
return;
} }
} }
#endif #endif
...@@ -412,7 +422,7 @@ PYBIND11_NOINLINE internals &get_internals() { ...@@ -412,7 +422,7 @@ PYBIND11_NOINLINE internals &get_internals() {
// Ensure that the GIL is held since we will need to make Python calls. // 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. // Cannot use py::gil_scoped_acquire here since that constructor calls get_internals.
struct gil_scoped_acquire_local { 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); } ~gil_scoped_acquire_local() { PyGILState_Release(state); }
const PyGILState_STATE state; const PyGILState_STATE state;
} gil; } gil;
...@@ -512,11 +522,10 @@ struct local_internals { ...@@ -512,11 +522,10 @@ struct local_internals {
/// Works like `get_internals`, but for things which are locally registered. /// Works like `get_internals`, but for things which are locally registered.
inline local_internals &get_local_internals() { inline local_internals &get_local_internals() {
static local_internals locals; static local_internals locals;
return locals; return locals;
} }
/// Constructs a std::string with the given arguments, stores it in `internals`, and returns its /// 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 /// `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 /// 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) { ...@@ -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 /// 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 /// 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. /// 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) { T &get_or_create_shared_data(const std::string &name) {
auto &internals = detail::get_internals(); auto &internals = detail::get_internals();
auto it = internals.shared_data.find(name); auto it = internals.shared_data.find(name);
......
This diff is collapsed.
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
#include <cstdlib> #include <cstdlib>
#if defined(__GNUG__) #if defined(__GNUG__)
#include <cxxabi.h> # include <cxxabi.h>
#endif #endif
#include "common.h" #include "common.h"
...@@ -34,8 +34,8 @@ inline void erase_all(std::string &string, const std::string &search) { ...@@ -34,8 +34,8 @@ inline void erase_all(std::string &string, const std::string &search) {
PYBIND11_NOINLINE void clean_type_id(std::string &name) { PYBIND11_NOINLINE void clean_type_id(std::string &name) {
#if defined(__GNUG__) #if defined(__GNUG__)
int status = 0; int status = 0;
std::unique_ptr<char, void (*)(void *)> res { std::unique_ptr<char, void (*)(void *)> res{
abi::__cxa_demangle(name.c_str(), nullptr, nullptr, &status), std::free }; abi::__cxa_demangle(name.c_str(), nullptr, nullptr, &status), std::free};
if (status == 0) { if (status == 0) {
name = res.get(); name = res.get();
} }
...@@ -49,7 +49,8 @@ PYBIND11_NOINLINE void clean_type_id(std::string &name) { ...@@ -49,7 +49,8 @@ PYBIND11_NOINLINE void clean_type_id(std::string &name) {
PYBIND11_NAMESPACE_END(detail) PYBIND11_NAMESPACE_END(detail)
/// Return a string representation of a C++ type /// 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()); std::string name(typeid(T).name());
detail::clean_type_id(name); detail::clean_type_id(name);
return name; return name;
......
This diff is collapsed.
...@@ -16,21 +16,17 @@ ...@@ -16,21 +16,17 @@
#include <vector> #include <vector>
#if defined(PYPY_VERSION) #if defined(PYPY_VERSION)
# error Embedding the interpreter is not supported with PyPy # error Embedding the interpreter is not supported with PyPy
#endif #endif
#if PY_MAJOR_VERSION >= 3 #if PY_MAJOR_VERSION >= 3
# define PYBIND11_EMBEDDED_MODULE_IMPL(name) \ # define PYBIND11_EMBEDDED_MODULE_IMPL(name) \
extern "C" PyObject *pybind11_init_impl_##name(); \ extern "C" PyObject *pybind11_init_impl_##name(); \
extern "C" PyObject *pybind11_init_impl_##name() { \ extern "C" PyObject *pybind11_init_impl_##name() { return pybind11_init_wrapper_##name(); }
return pybind11_init_wrapper_##name(); \
}
#else #else
# define PYBIND11_EMBEDDED_MODULE_IMPL(name) \ # define PYBIND11_EMBEDDED_MODULE_IMPL(name) \
extern "C" void pybind11_init_impl_##name(); \ extern "C" void pybind11_init_impl_##name(); \
extern "C" void pybind11_init_impl_##name() { \ extern "C" void pybind11_init_impl_##name() { pybind11_init_wrapper_##name(); }
pybind11_init_wrapper_##name(); \
}
#endif #endif
/** \rst /** \rst
...@@ -72,7 +68,7 @@ PYBIND11_NAMESPACE_BEGIN(detail) ...@@ -72,7 +68,7 @@ PYBIND11_NAMESPACE_BEGIN(detail)
/// Python 2.7/3.x compatible version of `PyImport_AppendInittab` and error checks. /// Python 2.7/3.x compatible version of `PyImport_AppendInittab` and error checks.
struct embedded_module { struct embedded_module {
#if PY_MAJOR_VERSION >= 3 #if PY_MAJOR_VERSION >= 3
using init_t = PyObject *(*)(); using init_t = PyObject *(*) ();
#else #else
using init_t = void (*)(); using init_t = void (*)();
#endif #endif
...@@ -106,10 +102,10 @@ inline wchar_t *widen_chars(const char *safe_arg) { ...@@ -106,10 +102,10 @@ inline wchar_t *widen_chars(const char *safe_arg) {
wchar_t *widened_arg = nullptr; wchar_t *widened_arg = nullptr;
// warning C4996: 'mbstowcs': This function or variable may be unsafe. // warning C4996: 'mbstowcs': This function or variable may be unsafe.
#if defined(_MSC_VER) # if defined(_MSC_VER)
#pragma warning(push) # pragma warning(push)
#pragma warning(disable:4996) # pragma warning(disable : 4996)
#endif # endif
# if defined(HAVE_BROKEN_MBSTOWCS) && HAVE_BROKEN_MBSTOWCS # if defined(HAVE_BROKEN_MBSTOWCS) && HAVE_BROKEN_MBSTOWCS
size_t count = std::strlen(safe_arg); size_t count = std::strlen(safe_arg);
...@@ -121,9 +117,9 @@ inline wchar_t *widen_chars(const char *safe_arg) { ...@@ -121,9 +117,9 @@ inline wchar_t *widen_chars(const char *safe_arg) {
std::mbstowcs(widened_arg, safe_arg, count + 1); std::mbstowcs(widened_arg, safe_arg, count + 1);
} }
#if defined(_MSC_VER) # if defined(_MSC_VER)
#pragma warning(pop) # pragma warning(pop)
#endif # endif
#endif #endif
return widened_arg; return widened_arg;
......
...@@ -11,24 +11,24 @@ ...@@ -11,24 +11,24 @@
#pragma once #pragma once
#include <utility>
#include "pybind11.h" #include "pybind11.h"
#include <utility>
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
PYBIND11_NAMESPACE_BEGIN(detail) PYBIND11_NAMESPACE_BEGIN(detail)
inline void ensure_builtins_in_globals(object &global) { 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 // Running exec and eval on Python 2 and 3 adds `builtins` module under
// `__builtins__` key to globals if not yet present. // `__builtins__` key to globals if not yet present.
// Python 3.8 made PyRun_String behave similarly. Let's also do that for // 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. // older versions, for consistency. This was missing from PyPy3.8 7.3.7.
if (!global.contains("__builtins__")) if (!global.contains("__builtins__"))
global["__builtins__"] = module_::import(PYBIND11_BUILTINS_MODULE); global["__builtins__"] = module_::import(PYBIND11_BUILTINS_MODULE);
#else #else
(void) global; (void) global;
#endif #endif
} }
PYBIND11_NAMESPACE_END(detail) PYBIND11_NAMESPACE_END(detail)
...@@ -58,10 +58,17 @@ object eval(const str &expr, object global = globals(), object local = object()) ...@@ -58,10 +58,17 @@ object eval(const str &expr, object global = globals(), object local = object())
int start = 0; int start = 0;
switch (mode) { switch (mode) {
case eval_expr: start = Py_eval_input; break; case eval_expr:
case eval_single_statement: start = Py_single_input; break; start = Py_eval_input;
case eval_statements: start = Py_file_input; break; break;
default: pybind11_fail("invalid evaluation mode"); 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()); 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()) ...@@ -74,8 +81,7 @@ object eval(const str &expr, object global = globals(), object local = object())
template <eval_mode mode = eval_expr, size_t N> template <eval_mode mode = eval_expr, size_t N>
object eval(const char (&s)[N], object global = globals(), object local = object()) { object eval(const char (&s)[N], object global = globals(), object local = object()) {
/* Support raw string literals by removing common leading whitespace */ /* Support raw string literals by removing common leading whitespace */
auto expr = (s[0] == '\n') ? str(module_::import("textwrap").attr("dedent")(s)) auto expr = (s[0] == '\n') ? str(module_::import("textwrap").attr("dedent")(s)) : str(s);
: str(s);
return eval<mode>(expr, global, local); return eval<mode>(expr, global, local);
} }
...@@ -112,28 +118,34 @@ object eval_file(str fname, object global = globals(), object local = object()) ...@@ -112,28 +118,34 @@ object eval_file(str fname, object global = globals(), object local = object())
int start = 0; int start = 0;
switch (mode) { switch (mode) {
case eval_expr: start = Py_eval_input; break; case eval_expr:
case eval_single_statement: start = Py_single_input; break; start = Py_eval_input;
case eval_statements: start = Py_file_input; break; break;
default: pybind11_fail("invalid evaluation mode"); 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; int closeFile = 1;
std::string fname_str = (std::string) fname; 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"); 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"); FILE *f = _Py_fopen(fname.ptr(), "r");
#else # else
/* No unicode support in open() :( */ /* No unicode support in open() :( */
auto fobj = reinterpret_steal<object>(PyFile_FromString( auto fobj = reinterpret_steal<object>(
const_cast<char *>(fname_str.c_str()), PyFile_FromString(const_cast<char *>(fname_str.c_str()), const_cast<char *>("r")));
const_cast<char*>("r")));
FILE *f = nullptr; FILE *f = nullptr;
if (fobj) if (fobj)
f = PyFile_AsFile(fobj.ptr()); f = PyFile_AsFile(fobj.ptr());
closeFile = 0; closeFile = 0;
#endif # endif
if (!f) { if (!f) {
PyErr_Clear(); PyErr_Clear();
pybind11_fail("File \"" + fname_str + "\" could not be opened!"); pybind11_fail("File \"" + fname_str + "\" could not be opened!");
...@@ -142,20 +154,19 @@ object eval_file(str fname, object global = globals(), object local = object()) ...@@ -142,20 +154,19 @@ object eval_file(str fname, object global = globals(), object local = object())
// In Python2, this should be encoded by getfilesystemencoding. // In Python2, this should be encoded by getfilesystemencoding.
// We don't boher setting it since Python2 is past EOL anyway. // We don't boher setting it since Python2 is past EOL anyway.
// See PR#3233 // See PR#3233
#if PY_VERSION_HEX >= 0x03000000 # if PY_VERSION_HEX >= 0x03000000
if (!global.contains("__file__")) { if (!global.contains("__file__")) {
global["__file__"] = std::move(fname); global["__file__"] = std::move(fname);
} }
#endif # endif
#if PY_VERSION_HEX < 0x03000000 && defined(PYPY_VERSION) # if PY_VERSION_HEX < 0x03000000 && defined(PYPY_VERSION)
PyObject *result = PyRun_File(f, fname_str.c_str(), start, global.ptr(), PyObject *result = PyRun_File(f, fname_str.c_str(), start, global.ptr(), local.ptr());
local.ptr());
(void) closeFile; (void) closeFile;
#else # else
PyObject *result = PyRun_FileEx(f, fname_str.c_str(), start, global.ptr(), PyObject *result
local.ptr(), closeFile); = PyRun_FileEx(f, fname_str.c_str(), start, global.ptr(), local.ptr(), closeFile);
#endif # endif
if (!result) { if (!result) {
throw error_already_set(); throw error_already_set();
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#pragma once #pragma once
#include "pybind11.h" #include "pybind11.h"
#include <functional> #include <functional>
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
...@@ -19,7 +20,7 @@ template <typename Return, typename... Args> ...@@ -19,7 +20,7 @@ template <typename Return, typename... Args>
struct type_caster<std::function<Return(Args...)>> { struct type_caster<std::function<Return(Args...)>> {
using type = 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 retval_type = conditional_t<std::is_same<Return, void>::value, void_type, Return>;
using function_type = Return (*) (Args...); using function_type = Return (*)(Args...);
public: public:
bool load(handle src, bool convert) { bool load(handle src, bool convert) {
...@@ -76,7 +77,9 @@ public: ...@@ -76,7 +77,9 @@ public:
// This triggers a syntax error under very special conditions (very weird indeed). // This triggers a syntax error under very special conditions (very weird indeed).
explicit explicit
#endif #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(const func_handle &f_) { operator=(f_); }
func_handle &operator=(const func_handle &f_) { func_handle &operator=(const func_handle &f_) {
gil_scoped_acquire acq; gil_scoped_acquire acq;
...@@ -118,8 +121,10 @@ public: ...@@ -118,8 +121,10 @@ public:
return cpp_function(std::forward<Func>(f_), policy).release(); return cpp_function(std::forward<Func>(f_), policy).release();
} }
PYBIND11_TYPE_CASTER(type, const_name("Callable[[") + concat(make_caster<Args>::name...) + const_name("], ") PYBIND11_TYPE_CASTER(type,
+ make_caster<retval_type>::name + const_name("]")); const_name("Callable[[") + concat(make_caster<Args>::name...)
+ const_name("], ") + make_caster<retval_type>::name
+ const_name("]"));
}; };
PYBIND11_NAMESPACE_END(detail) PYBIND11_NAMESPACE_END(detail)
......
...@@ -14,7 +14,6 @@ ...@@ -14,7 +14,6 @@
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
PYBIND11_NAMESPACE_BEGIN(detail) PYBIND11_NAMESPACE_BEGIN(detail)
// forward declarations // forward declarations
...@@ -22,7 +21,6 @@ PyThreadState *get_thread_state_unchecked(); ...@@ -22,7 +21,6 @@ PyThreadState *get_thread_state_unchecked();
PYBIND11_NAMESPACE_END(detail) PYBIND11_NAMESPACE_END(detail)
#if defined(WITH_THREAD) && !defined(PYPY_VERSION) #if defined(WITH_THREAD) && !defined(PYPY_VERSION)
/* The functions below essentially reproduce the PyGILState_* API using a RAII /* The functions below essentially reproduce the PyGILState_* API using a RAII
...@@ -64,11 +62,11 @@ public: ...@@ -64,11 +62,11 @@ public:
if (!tstate) { if (!tstate) {
tstate = PyThreadState_New(internals.istate); tstate = PyThreadState_New(internals.istate);
#if !defined(NDEBUG) # if !defined(NDEBUG)
if (!tstate) { if (!tstate) {
pybind11_fail("scoped_acquire: could not create thread state!"); pybind11_fail("scoped_acquire: could not create thread state!");
} }
#endif # endif
tstate->gilstate_counter = 0; tstate->gilstate_counter = 0;
PYBIND11_TLS_REPLACE_VALUE(internals.tstate, tstate); PYBIND11_TLS_REPLACE_VALUE(internals.tstate, tstate);
} else { } else {
...@@ -82,26 +80,24 @@ public: ...@@ -82,26 +80,24 @@ public:
inc_ref(); inc_ref();
} }
void inc_ref() { void inc_ref() { ++tstate->gilstate_counter; }
++tstate->gilstate_counter;
}
PYBIND11_NOINLINE void dec_ref() { PYBIND11_NOINLINE void dec_ref() {
--tstate->gilstate_counter; --tstate->gilstate_counter;
#if !defined(NDEBUG) # if !defined(NDEBUG)
if (detail::get_thread_state_unchecked() != tstate) { if (detail::get_thread_state_unchecked() != tstate) {
pybind11_fail("scoped_acquire::dec_ref(): thread state must be current!"); pybind11_fail("scoped_acquire::dec_ref(): thread state must be current!");
} }
if (tstate->gilstate_counter < 0) { if (tstate->gilstate_counter < 0) {
pybind11_fail("scoped_acquire::dec_ref(): reference count underflow!"); pybind11_fail("scoped_acquire::dec_ref(): reference count underflow!");
} }
#endif # endif
if (tstate->gilstate_counter == 0) { if (tstate->gilstate_counter == 0) {
#if !defined(NDEBUG) # if !defined(NDEBUG)
if (!release) { if (!release) {
pybind11_fail("scoped_acquire::dec_ref(): internal error!"); pybind11_fail("scoped_acquire::dec_ref(): internal error!");
} }
#endif # endif
PyThreadState_Clear(tstate); PyThreadState_Clear(tstate);
if (active) { if (active) {
PyThreadState_DeleteCurrent(); PyThreadState_DeleteCurrent();
...@@ -116,9 +112,7 @@ public: ...@@ -116,9 +112,7 @@ public:
/// could be shutting down when this is called, as thread deletion is not /// could be shutting down when this is called, as thread deletion is not
/// allowed during shutdown. Check _Py_IsFinalizing() on Python 3.7+, and /// allowed during shutdown. Check _Py_IsFinalizing() on Python 3.7+, and
/// protect subsequent code. /// protect subsequent code.
PYBIND11_NOINLINE void disarm() { PYBIND11_NOINLINE void disarm() { active = false; }
active = false;
}
PYBIND11_NOINLINE ~gil_scoped_acquire() { PYBIND11_NOINLINE ~gil_scoped_acquire() {
dec_ref(); dec_ref();
...@@ -126,6 +120,7 @@ public: ...@@ -126,6 +120,7 @@ public:
PyEval_SaveThread(); PyEval_SaveThread();
} }
} }
private: private:
PyThreadState *tstate = nullptr; PyThreadState *tstate = nullptr;
bool release = true; bool release = true;
...@@ -154,9 +149,7 @@ public: ...@@ -154,9 +149,7 @@ public:
/// could be shutting down when this is called, as thread deletion is not /// could be shutting down when this is called, as thread deletion is not
/// allowed during shutdown. Check _Py_IsFinalizing() on Python 3.7+, and /// allowed during shutdown. Check _Py_IsFinalizing() on Python 3.7+, and
/// protect subsequent code. /// protect subsequent code.
PYBIND11_NOINLINE void disarm() { PYBIND11_NOINLINE void disarm() { active = false; }
active = false;
}
~gil_scoped_release() { ~gil_scoped_release() {
if (!tstate) { if (!tstate) {
...@@ -173,6 +166,7 @@ public: ...@@ -173,6 +166,7 @@ public:
PYBIND11_TLS_REPLACE_VALUE(key, tstate); PYBIND11_TLS_REPLACE_VALUE(key, tstate);
} }
} }
private: private:
PyThreadState *tstate; PyThreadState *tstate;
bool disassoc; bool disassoc;
...@@ -181,6 +175,7 @@ private: ...@@ -181,6 +175,7 @@ private:
#elif defined(PYPY_VERSION) #elif defined(PYPY_VERSION)
class gil_scoped_acquire { class gil_scoped_acquire {
PyGILState_STATE state; PyGILState_STATE state;
public: public:
gil_scoped_acquire() { state = PyGILState_Ensure(); } gil_scoped_acquire() { state = PyGILState_Ensure(); }
~gil_scoped_acquire() { PyGILState_Release(state); } ~gil_scoped_acquire() { PyGILState_Release(state); }
...@@ -189,6 +184,7 @@ public: ...@@ -189,6 +184,7 @@ public:
class gil_scoped_release { class gil_scoped_release {
PyThreadState *state; PyThreadState *state;
public: public:
gil_scoped_release() { state = PyEval_SaveThread(); } gil_scoped_release() { state = PyEval_SaveThread(); }
~gil_scoped_release() { PyEval_RestoreThread(state); } ~gil_scoped_release() { PyEval_RestoreThread(state); }
......
...@@ -58,31 +58,23 @@ private: ...@@ -58,31 +58,23 @@ private:
size_t utf8_remainder() const { size_t utf8_remainder() const {
const auto rbase = std::reverse_iterator<char *>(pbase()); const auto rbase = std::reverse_iterator<char *>(pbase());
const auto rpptr = std::reverse_iterator<char *>(pptr()); const auto rpptr = std::reverse_iterator<char *>(pptr());
auto is_ascii = [](char c) { auto is_ascii = [](char c) { return (static_cast<unsigned char>(c) & 0x80) == 0x00; };
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 = [](char c) { auto is_leading_3b = [](char c) { return static_cast<unsigned char>(c) <= 0xEF; };
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 the last character is ASCII, there are no incomplete code points
if (is_ascii(*rpptr)) { if (is_ascii(*rpptr)) {
return 0; return 0;
} }
// Otherwise, work back from the end of the buffer and find the first // Otherwise, work back from the end of the buffer and find the first
// UTF-8 leading byte // UTF-8 leading byte
const auto rpend = rbase - rpptr >= 3 ? rpptr + 3 : rbase; const auto rpend = rbase - rpptr >= 3 ? rpptr + 3 : rbase;
const auto leading = std::find_if(rpptr, rpend, is_leading); const auto leading = std::find_if(rpptr, rpend, is_leading);
if (leading == rbase) { if (leading == rbase) {
return 0; return 0;
} }
const auto dist = static_cast<size_t>(leading - rpptr); const auto dist = static_cast<size_t>(leading - rpptr);
size_t remainder = 0; size_t remainder = 0;
if (dist == 0) { if (dist == 0) {
remainder = 1; // 1-byte code point is impossible remainder = 1; // 1-byte code point is impossible
...@@ -103,7 +95,7 @@ private: ...@@ -103,7 +95,7 @@ private:
if (pbase() != pptr()) { // If buffer is not empty if (pbase() != pptr()) { // If buffer is not empty
gil_scoped_acquire tmp; gil_scoped_acquire tmp;
// This subtraction cannot be negative, so dropping the sign. // This subtraction cannot be negative, so dropping the sign.
auto size = static_cast<size_t>(pptr() - pbase()); auto size = static_cast<size_t>(pptr() - pbase());
size_t remainder = utf8_remainder(); size_t remainder = utf8_remainder();
if (size > remainder) { if (size > remainder) {
...@@ -122,9 +114,7 @@ private: ...@@ -122,9 +114,7 @@ private:
return 0; return 0;
} }
int sync() override { int sync() override { return _sync(); }
return _sync();
}
public: public:
explicit pythonbuf(const object &pyostream, size_t buffer_size = 1024) explicit pythonbuf(const object &pyostream, size_t buffer_size = 1024)
...@@ -133,17 +123,14 @@ public: ...@@ -133,17 +123,14 @@ public:
setp(d_buffer.get(), d_buffer.get() + buf_size - 1); setp(d_buffer.get(), d_buffer.get() + buf_size - 1);
} }
pythonbuf(pythonbuf&&) = default; pythonbuf(pythonbuf &&) = default;
/// Sync before destroy /// Sync before destroy
~pythonbuf() override { ~pythonbuf() override { _sync(); }
_sync();
}
}; };
PYBIND11_NAMESPACE_END(detail) PYBIND11_NAMESPACE_END(detail)
/** \rst /** \rst
This a move-only guard that redirects output. This a move-only guard that redirects output.
...@@ -183,9 +170,7 @@ public: ...@@ -183,9 +170,7 @@ public:
old = costream.rdbuf(&buffer); old = costream.rdbuf(&buffer);
} }
~scoped_ostream_redirect() { ~scoped_ostream_redirect() { costream.rdbuf(old); }
costream.rdbuf(old);
}
scoped_ostream_redirect(const scoped_ostream_redirect &) = delete; scoped_ostream_redirect(const scoped_ostream_redirect &) = delete;
scoped_ostream_redirect(scoped_ostream_redirect &&other) = default; scoped_ostream_redirect(scoped_ostream_redirect &&other) = default;
...@@ -193,7 +178,6 @@ public: ...@@ -193,7 +178,6 @@ public:
scoped_ostream_redirect &operator=(scoped_ostream_redirect &&) = delete; scoped_ostream_redirect &operator=(scoped_ostream_redirect &&) = delete;
}; };
/** \rst /** \rst
Like `scoped_ostream_redirect`, but redirects cerr by default. This class Like `scoped_ostream_redirect`, but redirects cerr by default. This class
is provided primary to make ``py::call_guard`` easier to make. is provided primary to make ``py::call_guard`` easier to make.
...@@ -213,7 +197,6 @@ public: ...@@ -213,7 +197,6 @@ public:
: scoped_ostream_redirect(costream, pyostream) {} : scoped_ostream_redirect(costream, pyostream) {}
}; };
PYBIND11_NAMESPACE_BEGIN(detail) PYBIND11_NAMESPACE_BEGIN(detail)
// Class to redirect output as a context manager. C++ backend. // Class to redirect output as a context manager. C++ backend.
......
This diff is collapsed.
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