Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
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 {
...
@@ -174,6 +174,9 @@ struct type_record {
/// How large is pybind11::instance<type>?
/// How large is pybind11::instance<type>?
size_t
instance_size
=
0
;
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
/// Function pointer to class_<..>::init_holder
void
(
*
init_holder
)(
PyObject
*
,
const
void
*
)
=
nullptr
;
void
(
*
init_holder
)(
PyObject
*
,
const
void
*
)
=
nullptr
;
...
...
include/pybind11/cast.h
View file @
0d765f4a
...
@@ -25,6 +25,7 @@ inline PyTypeObject *make_default_metaclass();
...
@@ -25,6 +25,7 @@ inline PyTypeObject *make_default_metaclass();
struct
type_info
{
struct
type_info
{
PyTypeObject
*
type
;
PyTypeObject
*
type
;
size_t
type_size
;
size_t
type_size
;
void
*
(
*
operator_new
)(
size_t
);
void
(
*
init_holder
)(
PyObject
*
,
const
void
*
);
void
(
*
init_holder
)(
PyObject
*
,
const
void
*
);
void
(
*
dealloc
)(
PyObject
*
);
void
(
*
dealloc
)(
PyObject
*
);
std
::
vector
<
PyObject
*
(
*
)(
PyObject
*
,
PyTypeObject
*
)
>
implicit_conversions
;
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 *,
...
@@ -183,7 +183,7 @@ extern "C" inline PyObject *pybind11_object_new(PyTypeObject *type, PyObject *,
PyObject
*
self
=
type
->
tp_alloc
(
type
,
0
);
PyObject
*
self
=
type
->
tp_alloc
(
type
,
0
);
auto
instance
=
(
instance_essentials
<
void
>
*
)
self
;
auto
instance
=
(
instance_essentials
<
void
>
*
)
self
;
auto
tinfo
=
get_type_info
(
type
);
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
->
owned
=
true
;
instance
->
holder_constructed
=
false
;
instance
->
holder_constructed
=
false
;
get_internals
().
registered_instances
.
emplace
(
instance
->
value
,
self
);
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
...
@@ -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
<
bool
B
>
using
bool_constant
=
std
::
integral_constant
<
bool
,
B
>
;
template
<
typename
T
>
struct
negation
:
bool_constant
<!
T
::
value
>
{
};
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
/// Compile-time all/any/none of that check the boolean value of all template types
#ifdef __cpp_fold_expressions
#ifdef __cpp_fold_expressions
template
<
class
...
Ts
>
using
all_of
=
bool_constant
<
(
Ts
::
value
&&
...)
>
;
template
<
class
...
Ts
>
using
all_of
=
bool_constant
<
(
Ts
::
value
&&
...)
>
;
...
...
include/pybind11/pybind11.h
View file @
0d765f4a
...
@@ -803,6 +803,7 @@ protected:
...
@@ -803,6 +803,7 @@ protected:
auto
*
tinfo
=
new
detail
::
type_info
();
auto
*
tinfo
=
new
detail
::
type_info
();
tinfo
->
type
=
(
PyTypeObject
*
)
m_ptr
;
tinfo
->
type
=
(
PyTypeObject
*
)
m_ptr
;
tinfo
->
type_size
=
rec
.
type_size
;
tinfo
->
type_size
=
rec
.
type_size
;
tinfo
->
operator_new
=
rec
.
operator_new
;
tinfo
->
init_holder
=
rec
.
init_holder
;
tinfo
->
init_holder
=
rec
.
init_holder
;
tinfo
->
dealloc
=
rec
.
dealloc
;
tinfo
->
dealloc
=
rec
.
dealloc
;
...
@@ -860,6 +861,18 @@ protected:
...
@@ -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
)
NAMESPACE_END
(
detail
)
template
<
typename
type_
,
typename
...
options
>
template
<
typename
type_
,
typename
...
options
>
...
@@ -905,6 +918,8 @@ public:
...
@@ -905,6 +918,8 @@ public:
record
.
dealloc
=
dealloc
;
record
.
dealloc
=
dealloc
;
record
.
default_holder
=
std
::
is_same
<
holder_type
,
std
::
unique_ptr
<
type
>>::
value
;
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 */
/* Register base classes specified via template arguments to class_, if any */
bool
unused
[]
=
{
(
add_base
<
options
>
(
record
),
false
)...,
false
};
bool
unused
[]
=
{
(
add_base
<
options
>
(
record
),
false
)...,
false
};
(
void
)
unused
;
(
void
)
unused
;
...
@@ -1125,7 +1140,7 @@ private:
...
@@ -1125,7 +1140,7 @@ private:
if
(
inst
->
holder_constructed
)
if
(
inst
->
holder_constructed
)
inst
->
holder
.
~
holder_type
();
inst
->
holder
.
~
holder_type
();
else
if
(
inst
->
owned
)
else
if
(
inst
->
owned
)
::
operator
delete
(
inst
->
value
);
detail
::
call_
operator
_
delete
(
inst
->
value
);
}
}
static
detail
::
function_record
*
get_function_record
(
handle
h
)
{
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)
...
@@ -60,6 +60,15 @@ template <typename MatrixArgType> Eigen::MatrixXd adjust_matrix(MatrixArgType m)
return
ret
;
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
)
{
test_initializer
eigen
([](
py
::
module
&
m
)
{
typedef
Eigen
::
Matrix
<
float
,
5
,
6
,
Eigen
::
RowMajor
>
FixedMatrixR
;
typedef
Eigen
::
Matrix
<
float
,
5
,
6
,
Eigen
::
RowMajor
>
FixedMatrixR
;
typedef
Eigen
::
Matrix
<
float
,
5
,
6
>
FixedMatrixC
;
typedef
Eigen
::
Matrix
<
float
,
5
,
6
>
FixedMatrixC
;
...
@@ -277,4 +286,9 @@ test_initializer eigen([](py::module &m) {
...
@@ -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.
// 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_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
());
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():
...
@@ -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.
,
102
,
203
]]))
assert
np
.
all
(
iss738_f2
(
np
.
array
([[
1.
],
[
2
],
[
3
]]))
==
np
.
array
([[
1.
],
[
12
],
[
23
]]))
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