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
5984baaf
Commit
5984baaf
authored
May 10, 2016
by
Wenzel Jakob
Browse files
redesigned cpp_function constructor; significant space savings
parent
07ef518b
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
41 additions
and
77 deletions
+41
-77
include/pybind11/attr.h
include/pybind11/attr.h
+2
-2
include/pybind11/pybind11.h
include/pybind11/pybind11.h
+39
-75
No files found.
include/pybind11/attr.h
View file @
5984baaf
...
@@ -95,10 +95,10 @@ struct function_record {
...
@@ -95,10 +95,10 @@ struct function_record {
handle
(
*
impl
)
(
function_record
*
,
handle
,
handle
)
=
nullptr
;
handle
(
*
impl
)
(
function_record
*
,
handle
,
handle
)
=
nullptr
;
/// Storage for the wrapped function pointer and captured data, if any
/// Storage for the wrapped function pointer and captured data, if any
void
*
data
=
nullptr
;
void
*
data
[
3
]
=
{
}
;
/// Pointer to custom destructor for 'data' (if needed)
/// Pointer to custom destructor for 'data' (if needed)
void
(
*
free_data
)
(
voi
d
*
ptr
)
=
nullptr
;
void
(
*
free_data
)
(
function_recor
d
*
ptr
)
=
nullptr
;
/// Return value policy associated with this function
/// Return value policy associated with this function
return_value_policy
policy
=
return_value_policy
::
automatic
;
return_value_policy
policy
=
return_value_policy
::
automatic
;
...
...
include/pybind11/pybind11.h
View file @
5984baaf
...
@@ -33,77 +33,32 @@ NAMESPACE_BEGIN(pybind11)
...
@@ -33,77 +33,32 @@ NAMESPACE_BEGIN(pybind11)
/// Wraps an arbitrary C++ function/method/lambda function/.. into a callable Python object
/// Wraps an arbitrary C++ function/method/lambda function/.. into a callable Python object
class
cpp_function
:
public
function
{
class
cpp_function
:
public
function
{
protected:
/// Picks a suitable return value converter from cast.h
template
<
typename
T
>
using
return_value_caster
=
detail
::
type_caster
<
typename
std
::
conditional
<
std
::
is_void
<
T
>::
value
,
detail
::
void_type
,
typename
detail
::
intrinsic_type
<
T
>::
type
>::
type
>
;
/// Picks a suitable argument value converter from cast.h
template
<
typename
...
T
>
using
arg_value_caster
=
detail
::
type_caster
<
typename
std
::
tuple
<
T
...
>>
;
public:
public:
cpp_function
()
{
}
cpp_function
()
{
}
///
V
anilla function pointer
s
///
Construct a cpp_function from a v
anilla function pointer
template
<
typename
Return
,
typename
...
Args
,
typename
...
Extra
>
template
<
typename
Return
,
typename
...
Args
,
typename
...
Extra
>
cpp_function
(
Return
(
*
f
)(
Args
...),
const
Extra
&
...
extra
)
{
cpp_function
(
Return
(
*
f
)(
Args
...),
const
Extra
&
...
extra
)
{
auto
rec
=
new
detail
::
function_record
();
initialize
(
f
,
f
,
extra
...);
rec
->
data
=
(
void
*
)
f
;
typedef
arg_value_caster
<
Args
...
>
cast_in
;
typedef
return_value_caster
<
Return
>
cast_out
;
/* Dispatch code which converts function arguments and performs the actual function call */
rec
->
impl
=
[](
detail
::
function_record
*
rec
,
handle
pyArgs
,
handle
parent
)
->
handle
{
cast_in
args
;
/* Try to cast the function arguments into the C++ domain */
if
(
!
args
.
load
(
pyArgs
,
true
))
return
PYBIND11_TRY_NEXT_OVERLOAD
;
/* Invoke call policy pre-call hook */
detail
::
process_attributes
<
Extra
...
>::
precall
(
pyArgs
);
/* Do the call and convert the return value back into the Python domain */
handle
result
=
cast_out
::
cast
(
args
.
template
call
<
Return
>((
Return
(
*
)
(
Args
...))
rec
->
data
),
rec
->
policy
,
parent
);
/* Invoke call policy post-call hook */
detail
::
process_attributes
<
Extra
...
>::
postcall
(
pyArgs
,
result
);
return
result
;
};
/* Process any user-provided function attributes */
detail
::
process_attributes
<
Extra
...
>::
init
(
extra
...,
rec
);
/* Generate a readable signature describing the function's arguments and return value types */
using
detail
::
descr
;
PYBIND11_DESCR
signature
=
cast_in
::
name
()
+
detail
::
_
(
" -> "
)
+
cast_out
::
name
();
/* Register the function with Python from generic (non-templated) code */
initialize
(
rec
,
signature
.
text
(),
signature
.
types
(),
sizeof
...(
Args
));
}
}
///
Delegating helper constructor to deal with lambda functions
///
Construct a cpp_function from a lambda function (possibly with internal state)
template
<
typename
Func
,
typename
...
Extra
>
cpp_function
(
Func
&&
f
,
const
Extra
&
...
extra
)
{
template
<
typename
Func
,
typename
...
Extra
>
cpp_function
(
Func
&&
f
,
const
Extra
&
...
extra
)
{
initialize
(
std
::
forward
<
Func
>
(
f
),
initialize
(
std
::
forward
<
Func
>
(
f
),
(
typename
detail
::
remove_class
<
decltype
(
(
typename
detail
::
remove_class
<
decltype
(
&
std
::
remove_reference
<
Func
>::
type
::
operator
())
>::
type
*
)
nullptr
,
extra
...);
&
std
::
remove_reference
<
Func
>::
type
::
operator
())
>::
type
*
)
nullptr
,
extra
...);
}
}
///
Delegating helper constructor to deal with
class method
s
(non-const)
///
Construct a cpp_function from a
class method (non-const)
template
<
typename
Return
,
typename
Class
,
typename
...
Arg
,
typename
...
Extra
>
cpp_function
(
template
<
typename
Return
,
typename
Class
,
typename
...
Arg
,
typename
...
Extra
>
Return
(
Class
::*
f
)(
Arg
...),
const
Extra
&
...
extra
)
{
cpp_function
(
Return
(
Class
::*
f
)(
Arg
...),
const
Extra
&
...
extra
)
{
initialize
([
f
](
Class
*
c
,
Arg
...
args
)
->
Return
{
return
(
c
->*
f
)(
args
...);
},
initialize
([
f
](
Class
*
c
,
Arg
...
args
)
->
Return
{
return
(
c
->*
f
)(
args
...);
},
(
Return
(
*
)
(
Class
*
,
Arg
...))
nullptr
,
extra
...);
(
Return
(
*
)
(
Class
*
,
Arg
...))
nullptr
,
extra
...);
}
}
///
Delegating helper constructor to deal with
class method
s
(const)
///
Construct a cpp_function from a
class method (const)
template
<
typename
Return
,
typename
Class
,
typename
...
Arg
,
typename
...
Extra
>
cpp_function
(
template
<
typename
Return
,
typename
Class
,
typename
...
Arg
,
typename
...
Extra
>
Return
(
Class
::*
f
)(
Arg
...)
const
,
const
Extra
&
...
extra
)
{
cpp_function
(
Return
(
Class
::*
f
)(
Arg
...)
const
,
const
Extra
&
...
extra
)
{
initialize
([
f
](
const
Class
*
c
,
Arg
...
args
)
->
Return
{
return
(
c
->*
f
)(
args
...);
},
initialize
([
f
](
const
Class
*
c
,
Arg
...
args
)
->
Return
{
return
(
c
->*
f
)(
args
...);
},
(
Return
(
*
)(
const
Class
*
,
Arg
...))
nullptr
,
extra
...);
(
Return
(
*
)(
const
Class
*
,
Arg
...))
nullptr
,
extra
...);
}
}
...
@@ -119,35 +74,44 @@ protected:
...
@@ -119,35 +74,44 @@ protected:
/* Store the function including any extra state it might have (e.g. a lambda capture object) */
/* Store the function including any extra state it might have (e.g. a lambda capture object) */
auto
rec
=
new
detail
::
function_record
();
auto
rec
=
new
detail
::
function_record
();
rec
->
data
=
new
capture
{
std
::
forward
<
Func
>
(
f
)
};
/* Create a cleanup handler, but only if we have to (less generated code) */
/* Store the capture object directly in the function record if there is enough space */
if
(
!
std
::
is_trivially_destructible
<
Func
>::
value
)
if
(
sizeof
(
capture
)
<=
sizeof
(
rec
->
data
))
{
rec
->
free_data
=
[](
void
*
ptr
)
{
delete
(
capture
*
)
ptr
;
};
new
((
capture
*
)
&
rec
->
data
)
capture
{
std
::
forward
<
Func
>
(
f
)
};
else
if
(
!
std
::
is_trivially_destructible
<
Func
>::
value
)
rec
->
free_data
=
operator
delete
;
rec
->
free_data
=
[](
detail
::
function_record
*
r
)
{
((
capture
*
)
&
r
->
data
)
->~
capture
();
};
}
else
{
rec
->
data
[
0
]
=
new
capture
{
std
::
forward
<
Func
>
(
f
)
};
rec
->
free_data
=
[](
detail
::
function_record
*
r
)
{
delete
((
capture
*
)
r
->
data
[
0
]);
};
}
typedef
arg_value_caster
<
Args
...
>
cast_in
;
/* Type casters for the function arguments and return value */
typedef
return_value_caster
<
Return
>
cast_out
;
typedef
detail
::
type_caster
<
typename
std
::
tuple
<
Args
...
>>
cast_in
;
typedef
detail
::
type_caster
<
typename
std
::
conditional
<
std
::
is_void
<
Return
>::
value
,
detail
::
void_type
,
typename
detail
::
intrinsic_type
<
Return
>::
type
>::
type
>
cast_out
;
/* Dispatch code which converts function arguments and performs the actual function call */
/* Dispatch code which converts function arguments and performs the actual function call */
rec
->
impl
=
[](
detail
::
function_record
*
rec
,
handle
pyA
rgs
,
handle
parent
)
->
handle
{
rec
->
impl
=
[](
detail
::
function_record
*
rec
,
handle
a
rgs
,
handle
parent
)
->
handle
{
cast_in
args
;
cast_in
args
_converter
;
/* Try to cast the function arguments into the C++ domain */
/* Try to cast the function arguments into the C++ domain */
if
(
!
args
.
load
(
pyA
rgs
,
true
))
if
(
!
args
_converter
.
load
(
a
rgs
,
true
))
return
PYBIND11_TRY_NEXT_OVERLOAD
;
return
PYBIND11_TRY_NEXT_OVERLOAD
;
/* Invoke call policy pre-call hook */
/* Invoke call policy pre-call hook */
detail
::
process_attributes
<
Extra
...
>::
precall
(
pyArgs
);
detail
::
process_attributes
<
Extra
...
>::
precall
(
args
);
/* Get a pointer to the capture object */
capture
*
cap
=
(
capture
*
)
(
sizeof
(
capture
)
<=
sizeof
(
rec
->
data
)
?
&
rec
->
data
:
rec
->
data
[
0
]);
/* Do the call and convert the return value back into the Python domain */
/* Perform the functionc all */
handle
result
=
cast_out
::
cast
(
handle
result
=
cast_out
::
cast
(
args_converter
.
template
call
<
Return
>(
cap
->
f
),
args
.
template
call
<
Return
>(((
capture
*
)
rec
->
data
)
->
f
),
rec
->
policy
,
parent
);
rec
->
policy
,
parent
);
/* Invoke call policy post-call hook */
/* Invoke call policy post-call hook */
detail
::
process_attributes
<
Extra
...
>::
postcall
(
pyA
rgs
,
result
);
detail
::
process_attributes
<
Extra
...
>::
postcall
(
a
rgs
,
result
);
return
result
;
return
result
;
};
};
...
@@ -160,12 +124,12 @@ protected:
...
@@ -160,12 +124,12 @@ protected:
PYBIND11_DESCR
signature
=
cast_in
::
name
()
+
detail
::
_
(
" -> "
)
+
cast_out
::
name
();
PYBIND11_DESCR
signature
=
cast_in
::
name
()
+
detail
::
_
(
" -> "
)
+
cast_out
::
name
();
/* Register the function with Python from generic (non-templated) code */
/* Register the function with Python from generic (non-templated) code */
initialize
(
rec
,
signature
.
text
(),
signature
.
types
(),
sizeof
...(
Args
));
initialize
_generic
(
rec
,
signature
.
text
(),
signature
.
types
(),
sizeof
...(
Args
));
}
}
/// Register a function call with Python (generic non-templated code goes here)
/// Register a function call with Python (generic non-templated code goes here)
void
initialize
(
detail
::
function_record
*
rec
,
const
char
*
text
,
void
initialize
_generic
(
detail
::
function_record
*
rec
,
const
char
*
text
,
const
std
::
type_info
*
const
*
types
,
int
args
)
{
const
std
::
type_info
*
const
*
types
,
int
args
)
{
/* Create copies of all referenced C-style strings */
/* Create copies of all referenced C-style strings */
rec
->
name
=
strdup
(
rec
->
name
?
rec
->
name
:
""
);
rec
->
name
=
strdup
(
rec
->
name
?
rec
->
name
:
""
);
...
@@ -336,7 +300,7 @@ protected:
...
@@ -336,7 +300,7 @@ protected:
while
(
rec
)
{
while
(
rec
)
{
detail
::
function_record
*
next
=
rec
->
next
;
detail
::
function_record
*
next
=
rec
->
next
;
if
(
rec
->
free_data
)
if
(
rec
->
free_data
)
rec
->
free_data
(
rec
->
data
);
rec
->
free_data
(
rec
);
std
::
free
((
char
*
)
rec
->
name
);
std
::
free
((
char
*
)
rec
->
name
);
std
::
free
((
char
*
)
rec
->
doc
);
std
::
free
((
char
*
)
rec
->
doc
);
std
::
free
((
char
*
)
rec
->
signature
);
std
::
free
((
char
*
)
rec
->
signature
);
...
...
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