Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
gaoqiong
pybind11
Commits
0d765f4a
Commit
0d765f4a
authored
Mar 21, 2017
by
Dean Moldovan
Committed by
Wenzel Jakob
Mar 22, 2017
Browse files
Support class-specific operator new and delete
Fixes #754.
parent
b0292c1d
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
52 additions
and
2 deletions
+52
-2
include/pybind11/attr.h
include/pybind11/attr.h
+3
-0
include/pybind11/cast.h
include/pybind11/cast.h
+1
-0
include/pybind11/class_support.h
include/pybind11/class_support.h
+1
-1
include/pybind11/common.h
include/pybind11/common.h
+7
-0
include/pybind11/pybind11.h
include/pybind11/pybind11.h
+16
-1
tests/test_eigen.cpp
tests/test_eigen.cpp
+14
-0
tests/test_eigen.py
tests/test_eigen.py
+10
-0
No files found.
include/pybind11/attr.h
View file @
0d765f4a
...
...
@@ -174,6 +174,9 @@ struct type_record {
/// How large is pybind11::instance<type>?
size_t
instance_size
=
0
;
/// The global operator new can be overridden with a class-specific variant
void
*
(
*
operator_new
)(
size_t
)
=
::
operator
new
;
/// Function pointer to class_<..>::init_holder
void
(
*
init_holder
)(
PyObject
*
,
const
void
*
)
=
nullptr
;
...
...
include/pybind11/cast.h
View file @
0d765f4a
...
...
@@ -25,6 +25,7 @@ inline PyTypeObject *make_default_metaclass();
struct
type_info
{
PyTypeObject
*
type
;
size_t
type_size
;
void
*
(
*
operator_new
)(
size_t
);
void
(
*
init_holder
)(
PyObject
*
,
const
void
*
);
void
(
*
dealloc
)(
PyObject
*
);
std
::
vector
<
PyObject
*
(
*
)(
PyObject
*
,
PyTypeObject
*
)
>
implicit_conversions
;
...
...
include/pybind11/class_support.h
View file @
0d765f4a
...
...
@@ -183,7 +183,7 @@ extern "C" inline PyObject *pybind11_object_new(PyTypeObject *type, PyObject *,
PyObject
*
self
=
type
->
tp_alloc
(
type
,
0
);
auto
instance
=
(
instance_essentials
<
void
>
*
)
self
;
auto
tinfo
=
get_type_info
(
type
);
instance
->
value
=
::
operator
new
(
tinfo
->
type_size
);
instance
->
value
=
tinfo
->
operator
_
new
(
tinfo
->
type_size
);
instance
->
owned
=
true
;
instance
->
holder_constructed
=
false
;
get_internals
().
registered_instances
.
emplace
(
instance
->
value
,
self
);
...
...
include/pybind11/common.h
View file @
0d765f4a
...
...
@@ -427,6 +427,13 @@ template<size_t N> using make_index_sequence = typename make_index_sequence_impl
template
<
bool
B
>
using
bool_constant
=
std
::
integral_constant
<
bool
,
B
>
;
template
<
typename
T
>
struct
negation
:
bool_constant
<!
T
::
value
>
{
};
#ifdef __cpp_lib_void_t
using
std
::
void_t
;
#else
template
<
typename
...
>
struct
void_t_impl
{
using
type
=
void
;
};
template
<
typename
...
Ts
>
using
void_t
=
typename
void_t_impl
<
Ts
...
>::
type
;
#endif
/// Compile-time all/any/none of that check the boolean value of all template types
#ifdef __cpp_fold_expressions
template
<
class
...
Ts
>
using
all_of
=
bool_constant
<
(
Ts
::
value
&&
...)
>
;
...
...
include/pybind11/pybind11.h
View file @
0d765f4a
...
...
@@ -803,6 +803,7 @@ protected:
auto
*
tinfo
=
new
detail
::
type_info
();
tinfo
->
type
=
(
PyTypeObject
*
)
m_ptr
;
tinfo
->
type_size
=
rec
.
type_size
;
tinfo
->
operator_new
=
rec
.
operator_new
;
tinfo
->
init_holder
=
rec
.
init_holder
;
tinfo
->
dealloc
=
rec
.
dealloc
;
...
...
@@ -860,6 +861,18 @@ protected:
}
};
/// Set the pointer to operator new if it exists. The cast is needed because it can be overloaded.
template
<
typename
T
,
typename
=
void_t
<
decltype
(
static_cast
<
void
*
(
*
)(
size_t
)>(
T
::
operator
new
))
>>
void
set_operator_new
(
type_record
*
r
)
{
r
->
operator_new
=
&
T
::
operator
new
;
}
template
<
typename
>
void
set_operator_new
(...)
{
}
/// Call class-specific delete if it exists or global otherwise. Can also be an overload set.
template
<
typename
T
,
typename
=
void_t
<
decltype
(
static_cast
<
void
(
*
)(
void
*
)>(
T
::
operator
delete
))
>>
void
call_operator_delete
(
T
*
p
)
{
T
::
operator
delete
(
p
);
}
inline
void
call_operator_delete
(
void
*
p
)
{
::
operator
delete
(
p
);
}
NAMESPACE_END
(
detail
)
template
<
typename
type_
,
typename
...
options
>
...
...
@@ -905,6 +918,8 @@ public:
record
.
dealloc
=
dealloc
;
record
.
default_holder
=
std
::
is_same
<
holder_type
,
std
::
unique_ptr
<
type
>>::
value
;
set_operator_new
<
type
>
(
&
record
);
/* Register base classes specified via template arguments to class_, if any */
bool
unused
[]
=
{
(
add_base
<
options
>
(
record
),
false
)...,
false
};
(
void
)
unused
;
...
...
@@ -1125,7 +1140,7 @@ private:
if
(
inst
->
holder_constructed
)
inst
->
holder
.
~
holder_type
();
else
if
(
inst
->
owned
)
::
operator
delete
(
inst
->
value
);
detail
::
call_
operator
_
delete
(
inst
->
value
);
}
static
detail
::
function_record
*
get_function_record
(
handle
h
)
{
...
...
tests/test_eigen.cpp
View file @
0d765f4a
...
...
@@ -60,6 +60,15 @@ template <typename MatrixArgType> Eigen::MatrixXd adjust_matrix(MatrixArgType m)
return
ret
;
}
struct
CustomOperatorNew
{
CustomOperatorNew
()
=
default
;
Eigen
::
Matrix4d
a
=
Eigen
::
Matrix4d
::
Zero
();
Eigen
::
Matrix4d
b
=
Eigen
::
Matrix4d
::
Identity
();
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
;
};
test_initializer
eigen
([](
py
::
module
&
m
)
{
typedef
Eigen
::
Matrix
<
float
,
5
,
6
,
Eigen
::
RowMajor
>
FixedMatrixR
;
typedef
Eigen
::
Matrix
<
float
,
5
,
6
>
FixedMatrixC
;
...
...
@@ -277,4 +286,9 @@ test_initializer eigen([](py::module &m) {
// requiring a copy!) because the stride value can be safely ignored on a size-1 dimension.
m
.
def
(
"iss738_f1"
,
&
adjust_matrix
<
const
Eigen
::
Ref
<
const
Eigen
::
MatrixXd
>
&>
,
py
::
arg
().
noconvert
());
m
.
def
(
"iss738_f2"
,
&
adjust_matrix
<
const
Eigen
::
Ref
<
const
Eigen
::
Matrix
<
double
,
-
1
,
-
1
,
Eigen
::
RowMajor
>>
&>
,
py
::
arg
().
noconvert
());
py
::
class_
<
CustomOperatorNew
>
(
m
,
"CustomOperatorNew"
)
.
def
(
py
::
init
<>
())
.
def_readonly
(
"a"
,
&
CustomOperatorNew
::
a
)
.
def_readonly
(
"b"
,
&
CustomOperatorNew
::
b
);
});
tests/test_eigen.py
View file @
0d765f4a
...
...
@@ -614,3 +614,13 @@ def test_issue738():
assert
np
.
all
(
iss738_f2
(
np
.
array
([[
1.
,
2
,
3
]]))
==
np
.
array
([[
1.
,
102
,
203
]]))
assert
np
.
all
(
iss738_f2
(
np
.
array
([[
1.
],
[
2
],
[
3
]]))
==
np
.
array
([[
1.
],
[
12
],
[
23
]]))
def
test_custom_operator_new
():
"""Using Eigen types as member variables requires a class-specific
operator new with proper alignment"""
from
pybind11_tests
import
CustomOperatorNew
o
=
CustomOperatorNew
()
np
.
testing
.
assert_allclose
(
o
.
a
,
0.0
)
np
.
testing
.
assert_allclose
(
o
.
b
.
diagonal
(),
1.0
)
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment