Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
P
pybind11
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
open
pybind11
Commits
d3b2d567
Commit
d3b2d567
authored
Feb 15, 2021
by
Ralf W. Grosse-Kunstleve
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'test_unique_ptr_member' into pr2672_use_smart_holder_as_default
parents
dc10e8a9
6005632b
Show whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
809 additions
and
756 deletions
+809
-756
CMakeLists.txt
+2
-0
include/pybind11/cast.h
+28
-693
include/pybind11/detail/init.h
+4
-49
include/pybind11/detail/smart_holder_init_inline_include.h
+55
-0
include/pybind11/detail/smart_holder_type_casters_inline_include.h
+691
-0
include/pybind11/pybind11.h
+27
-14
tests/extra_python_package/test_files.py
+2
-0
No files found.
CMakeLists.txt
View file @
d3b2d567
...
@@ -105,7 +105,9 @@ set(PYBIND11_HEADERS
...
@@ -105,7 +105,9 @@ set(PYBIND11_HEADERS
include/pybind11/detail/descr.h
include/pybind11/detail/descr.h
include/pybind11/detail/init.h
include/pybind11/detail/init.h
include/pybind11/detail/internals.h
include/pybind11/detail/internals.h
include/pybind11/detail/smart_holder_init_inline_include.h
include/pybind11/detail/smart_holder_poc.h
include/pybind11/detail/smart_holder_poc.h
include/pybind11/detail/smart_holder_type_casters_inline_include.h
include/pybind11/detail/typeid.h
include/pybind11/detail/typeid.h
include/pybind11/attr.h
include/pybind11/attr.h
include/pybind11/buffer_info.h
include/pybind11/buffer_info.h
...
...
include/pybind11/cast.h
View file @
d3b2d567
// clang-format off
/*
/*
pybind11/cast.h: Partial template specializations to cast between
pybind11/cast.h: Partial template specializations to cast between
C++ and Python types
C++ and Python types
...
@@ -18,7 +19,6 @@
...
@@ -18,7 +19,6 @@
#include "detail/typeid.h"
#include "detail/typeid.h"
#include "detail/descr.h"
#include "detail/descr.h"
#include "detail/internals.h"
#include "detail/internals.h"
#include "detail/smart_holder_poc.h"
#include <array>
#include <array>
#include <limits>
#include <limits>
#include <tuple>
#include <tuple>
...
@@ -42,9 +42,6 @@
...
@@ -42,9 +42,6 @@
#endif
#endif
PYBIND11_NAMESPACE_BEGIN
(
PYBIND11_NAMESPACE
)
PYBIND11_NAMESPACE_BEGIN
(
PYBIND11_NAMESPACE
)
using
pybindit
::
memory
::
smart_holder
;
PYBIND11_NAMESPACE_BEGIN
(
detail
)
PYBIND11_NAMESPACE_BEGIN
(
detail
)
/// A life support system for temporary objects created by `type_caster::load()`.
/// A life support system for temporary objects created by `type_caster::load()`.
...
@@ -959,700 +956,34 @@ protected:
...
@@ -959,700 +956,34 @@ protected:
static
Constructor
make_move_constructor
(...)
{
return
nullptr
;
}
static
Constructor
make_move_constructor
(...)
{
return
nullptr
;
}
};
};
// clang-format on
// Tag to be used as base class, inspected by is_smart_holder_type_caster<T> test.
// Tag to be used as base class, inspected by is_smart_holder_type_caster<T> test.
struct
is_smart_holder_type_caster_base_tag
{};
struct
is_smart_holder_type_caster_base_tag
{};
template
<
typename
T
>
template
<
typename
T
>
struct
is_smart_holder_type_caster
;
struct
is_smart_holder_type_caster
;
//DETAIL/SMART_HOLDER_TYPE_CASTERS_H/BEGIN/////////////////////////////////////////////////////////
PYBIND11_NAMESPACE_END
(
detail
)
PYBIND11_NAMESPACE_END
(
PYBIND11_NAMESPACE
)
//FWD begin
inline
void
register_instance
(
instance
*
self
,
void
*
valptr
,
const
type_info
*
tinfo
);
inline
bool
deregister_instance
(
instance
*
self
,
void
*
valptr
,
const
type_info
*
tinfo
);
//FWD end
// The modified_type_caster_generic_load_impl could replace type_caster_generic::load_impl but not
// vice versa. The main difference is that the original code only propagates a reference to the
// held value, while the modified implementation propagates value_and_holder.
// clang-format off
class
modified_type_caster_generic_load_impl
{
public
:
PYBIND11_NOINLINE
modified_type_caster_generic_load_impl
(
const
std
::
type_info
&
type_info
)
:
typeinfo
(
get_type_info
(
type_info
)),
cpptype
(
&
type_info
)
{
}
explicit
modified_type_caster_generic_load_impl
(
const
type_info
*
typeinfo
=
nullptr
)
:
typeinfo
(
typeinfo
),
cpptype
(
typeinfo
?
typeinfo
->
cpptype
:
nullptr
)
{
}
bool
load
(
handle
src
,
bool
convert
)
{
return
load_impl
<
modified_type_caster_generic_load_impl
>
(
src
,
convert
);
}
// Base methods for generic caster; there are overridden in copyable_holder_caster
void
load_value_and_holder
(
value_and_holder
&&
v_h
)
{
if
(
!
v_h
.
holder_constructed
())
{
// This is needed for old-style __init__.
// type_caster_generic::load_value BEGIN
auto
*&
vptr
=
v_h
.
value_ptr
();
// Lazy allocation for unallocated values:
if
(
vptr
==
nullptr
)
{
// Lazy allocation for unallocated values:
auto
*
type
=
v_h
.
type
?
v_h
.
type
:
typeinfo
;
if
(
type
->
operator_new
)
{
vptr
=
type
->
operator_new
(
type
->
type_size
);
}
else
{
#if defined(__cpp_aligned_new) && (!defined(_MSC_VER) || _MSC_VER >= 1912)
if
(
type
->
type_align
>
__STDCPP_DEFAULT_NEW_ALIGNMENT__
)
vptr
=
::
operator
new
(
type
->
type_size
,
std
::
align_val_t
(
type
->
type_align
));
else
#endif
vptr
=
::
operator
new
(
type
->
type_size
);
}
}
// type_caster_generic::load_value END
}
loaded_v_h
=
std
::
move
(
v_h
);
loaded_v_h
.
type
=
typeinfo
;
}
bool
try_implicit_casts
(
handle
src
,
bool
convert
)
{
for
(
auto
&
cast
:
typeinfo
->
implicit_casts
)
{
modified_type_caster_generic_load_impl
sub_caster
(
*
cast
.
first
);
if
(
sub_caster
.
load
(
src
,
convert
))
{
if
(
loaded_v_h_cpptype
!=
nullptr
)
{
pybind11_fail
(
"smart_holder_type_casters: try_implicit_casts failure."
);
}
loaded_v_h
=
sub_caster
.
loaded_v_h
;
loaded_v_h_cpptype
=
cast
.
first
;
implicit_cast
=
cast
.
second
;
return
true
;
}
}
return
false
;
}
bool
try_direct_conversions
(
handle
src
)
{
for
(
auto
&
converter
:
*
typeinfo
->
direct_conversions
)
{
if
(
converter
(
src
.
ptr
(),
unowned_void_ptr_from_direct_conversion
))
{
return
true
;
}
}
return
false
;
}
PYBIND11_NOINLINE
static
void
*
local_load
(
PyObject
*
src
,
const
type_info
*
ti
)
{
std
::
unique_ptr
<
modified_type_caster_generic_load_impl
>
loader
(
new
modified_type_caster_generic_load_impl
(
ti
));
if
(
loader
->
load
(
src
,
false
))
{
// Trick to work with the existing pybind11 internals.
// The void pointer is immediately captured in a new unique_ptr in
// try_load_foreign_module_local. If this assumption is violated sanitizers
// will most likely flag a leak (verified to be the case with ASAN).
return
static_cast
<
void
*>
(
loader
.
release
());
}
return
nullptr
;
}
/// Try to load with foreign typeinfo, if available. Used when there is no
/// native typeinfo, or when the native one wasn't able to produce a value.
PYBIND11_NOINLINE
bool
try_load_foreign_module_local
(
handle
src
)
{
constexpr
auto
*
local_key
=
PYBIND11_MODULE_LOCAL_ID
;
const
auto
pytype
=
type
::
handle_of
(
src
);
if
(
!
hasattr
(
pytype
,
local_key
))
return
false
;
type_info
*
foreign_typeinfo
=
reinterpret_borrow
<
capsule
>
(
getattr
(
pytype
,
local_key
));
// Only consider this foreign loader if actually foreign and is a loader of the correct cpp type
if
(
foreign_typeinfo
->
module_local_load
==
&
local_load
||
(
cpptype
&&
!
same_type
(
*
cpptype
,
*
foreign_typeinfo
->
cpptype
)))
return
false
;
void
*
foreign_loader_void_ptr
=
foreign_typeinfo
->
module_local_load
(
src
.
ptr
(),
foreign_typeinfo
);
if
(
foreign_loader_void_ptr
!=
nullptr
)
{
auto
foreign_loader
=
std
::
unique_ptr
<
modified_type_caster_generic_load_impl
>
(
static_cast
<
modified_type_caster_generic_load_impl
*>
(
foreign_loader_void_ptr
));
// Magic number intentionally hard-coded for simplicity and maximum robustness.
if
(
foreign_loader
->
local_load_safety_guard
!=
1887406645
)
{
pybind11_fail
(
"smart_holder_type_casters: Unexpected local_load_safety_guard,"
" possibly due to py::class_ holder mixup."
);
}
if
(
loaded_v_h_cpptype
!=
nullptr
)
{
pybind11_fail
(
"smart_holder_type_casters: try_load_foreign_module_local failure."
);
}
loaded_v_h
=
foreign_loader
->
loaded_v_h
;
loaded_v_h_cpptype
=
foreign_loader
->
loaded_v_h_cpptype
;
implicit_cast
=
foreign_loader
->
implicit_cast
;
return
true
;
}
return
false
;
}
// Implementation of `load`; this takes the type of `this` so that it can dispatch the relevant
// bits of code between here and copyable_holder_caster where the two classes need different
// logic (without having to resort to virtual inheritance).
template
<
typename
ThisT
>
PYBIND11_NOINLINE
bool
load_impl
(
handle
src
,
bool
convert
)
{
if
(
!
src
)
return
false
;
if
(
!
typeinfo
)
return
try_load_foreign_module_local
(
src
);
if
(
src
.
is_none
())
{
// Defer accepting None to other overloads (if we aren't in convert mode):
if
(
!
convert
)
return
false
;
loaded_v_h
=
value_and_holder
();
return
true
;
}
auto
&
this_
=
static_cast
<
ThisT
&>
(
*
this
);
PyTypeObject
*
srctype
=
Py_TYPE
(
src
.
ptr
());
// Case 1: If src is an exact type match for the target type then we can reinterpret_cast
// the instance's value pointer to the target type:
if
(
srctype
==
typeinfo
->
type
)
{
this_
.
load_value_and_holder
(
reinterpret_cast
<
instance
*>
(
src
.
ptr
())
->
get_value_and_holder
());
return
true
;
}
// Case 2: We have a derived class
else
if
(
PyType_IsSubtype
(
srctype
,
typeinfo
->
type
))
{
auto
&
bases
=
all_type_info
(
srctype
);
// subtype bases
bool
no_cpp_mi
=
typeinfo
->
simple_type
;
// Case 2a: the python type is a Python-inherited derived class that inherits from just
// one simple (no MI) pybind11 class, or is an exact match, so the C++ instance is of
// the right type and we can use reinterpret_cast.
// (This is essentially the same as case 2b, but because not using multiple inheritance
// is extremely common, we handle it specially to avoid the loop iterator and type
// pointer lookup overhead)
if
(
bases
.
size
()
==
1
&&
(
no_cpp_mi
||
bases
.
front
()
->
type
==
typeinfo
->
type
))
{
this_
.
load_value_and_holder
(
reinterpret_cast
<
instance
*>
(
src
.
ptr
())
->
get_value_and_holder
());
loaded_v_h_cpptype
=
bases
.
front
()
->
cpptype
;
reinterpret_cast_deemed_ok
=
true
;
return
true
;
}
// Case 2b: the python type inherits from multiple C++ bases. Check the bases to see if
// we can find an exact match (or, for a simple C++ type, an inherited match); if so, we
// can safely reinterpret_cast to the relevant pointer.
else
if
(
bases
.
size
()
>
1
)
{
for
(
auto
base
:
bases
)
{
if
(
no_cpp_mi
?
PyType_IsSubtype
(
base
->
type
,
typeinfo
->
type
)
:
base
->
type
==
typeinfo
->
type
)
{
this_
.
load_value_and_holder
(
reinterpret_cast
<
instance
*>
(
src
.
ptr
())
->
get_value_and_holder
(
base
));
loaded_v_h_cpptype
=
base
->
cpptype
;
reinterpret_cast_deemed_ok
=
true
;
return
true
;
}
}
}
// Case 2c: C++ multiple inheritance is involved and we couldn't find an exact type match
// in the registered bases, above, so try implicit casting (needed for proper C++ casting
// when MI is involved).
if
(
this_
.
try_implicit_casts
(
src
,
convert
))
{
return
true
;
}
}
// Perform an implicit conversion
if
(
convert
)
{
for
(
auto
&
converter
:
typeinfo
->
implicit_conversions
)
{
auto
temp
=
reinterpret_steal
<
object
>
(
converter
(
src
.
ptr
(),
typeinfo
->
type
));
if
(
load_impl
<
ThisT
>
(
temp
,
false
))
{
loader_life_support
::
add_patient
(
temp
);
return
true
;
}
}
if
(
this_
.
try_direct_conversions
(
src
))
return
true
;
}
// Failed to match local typeinfo. Try again with global.
if
(
typeinfo
->
module_local
)
{
if
(
auto
gtype
=
get_global_type_info
(
*
typeinfo
->
cpptype
))
{
typeinfo
=
gtype
;
return
load
(
src
,
false
);
}
}
// Global typeinfo has precedence over foreign module_local
return
try_load_foreign_module_local
(
src
);
}
const
type_info
*
typeinfo
=
nullptr
;
const
std
::
type_info
*
cpptype
=
nullptr
;
void
*
unowned_void_ptr_from_direct_conversion
=
nullptr
;
const
std
::
type_info
*
loaded_v_h_cpptype
=
nullptr
;
void
*
(
*
implicit_cast
)(
void
*
)
=
nullptr
;
value_and_holder
loaded_v_h
;
bool
reinterpret_cast_deemed_ok
=
false
;
// Magic number intentionally hard-coded, to guard against class_ holder mixups.
// Ideally type_caster_generic would have a similar guard, but this requires a change there.
std
::
size_t
local_load_safety_guard
=
1887406645
;
// 32-bit compatible value for portability.
};
// clang-format on
struct
smart_holder_type_caster_class_hooks
:
is_smart_holder_type_caster_base_tag
{
static
decltype
(
&
modified_type_caster_generic_load_impl
::
local_load
)
get_local_load_function_ptr
()
{
return
&
modified_type_caster_generic_load_impl
::
local_load
;
}
template
<
typename
T
>
static
void
init_instance_for_type
(
detail
::
instance
*
inst
,
const
void
*
holder_const_void_ptr
)
{
// Need for const_cast is a consequence of the type_info::init_instance type:
// void (*init_instance)(instance *, const void *);
auto
holder_void_ptr
=
const_cast
<
void
*>
(
holder_const_void_ptr
);
auto
v_h
=
inst
->
get_value_and_holder
(
detail
::
get_type_info
(
typeid
(
T
)));
if
(
!
v_h
.
instance_registered
())
{
register_instance
(
inst
,
v_h
.
value_ptr
(),
v_h
.
type
);
v_h
.
set_instance_registered
();
}
using
holder_type
=
pybindit
::
memory
::
smart_holder
;
if
(
holder_void_ptr
)
{
// Note: inst->owned ignored.
auto
holder_ptr
=
static_cast
<
holder_type
*>
(
holder_void_ptr
);
new
(
std
::
addressof
(
v_h
.
holder
<
holder_type
>
()))
holder_type
(
std
::
move
(
*
holder_ptr
));
}
else
if
(
inst
->
owned
)
{
new
(
std
::
addressof
(
v_h
.
holder
<
holder_type
>
()))
holder_type
(
holder_type
::
from_raw_ptr_take_ownership
(
v_h
.
value_ptr
<
T
>
()));
}
else
{
new
(
std
::
addressof
(
v_h
.
holder
<
holder_type
>
()))
holder_type
(
holder_type
::
from_raw_ptr_unowned
(
v_h
.
value_ptr
<
T
>
()));
}
v_h
.
set_holder_constructed
();
}
};
template
<
typename
T
>
struct
smart_holder_type_caster_load
{
using
holder_type
=
pybindit
::
memory
::
smart_holder
;
bool
load
(
handle
src
,
bool
convert
)
{
static_assert
(
is_smart_holder_type_caster
<
T
>::
value
,
"Internal consistency error."
);
load_impl
=
modified_type_caster_generic_load_impl
(
typeid
(
T
));
if
(
!
load_impl
.
load
(
src
,
convert
))
return
false
;
return
true
;
}
T
*
loaded_as_raw_ptr_unowned
()
const
{
void
*
void_ptr
=
load_impl
.
unowned_void_ptr_from_direct_conversion
;
if
(
void_ptr
==
nullptr
)
{
if
(
have_holder
())
{
throw_if_uninitialized_or_disowned_holder
();
void_ptr
=
holder
().
template
as_raw_ptr_unowned
<
void
>
();
}
else
if
(
load_impl
.
loaded_v_h
.
vh
!=
nullptr
)
void_ptr
=
load_impl
.
loaded_v_h
.
value_ptr
();
if
(
void_ptr
==
nullptr
)
return
nullptr
;
}
return
convert_type
(
void_ptr
);
}
T
&
loaded_as_lvalue_ref
()
const
{
T
*
raw_ptr
=
loaded_as_raw_ptr_unowned
();
if
(
raw_ptr
==
nullptr
)
throw
reference_cast_error
();
return
*
raw_ptr
;
}
std
::
shared_ptr
<
T
>
loaded_as_shared_ptr
()
const
{
if
(
load_impl
.
unowned_void_ptr_from_direct_conversion
!=
nullptr
)
throw
cast_error
(
"Unowned pointer from direct conversion cannot be converted to a"
" std::shared_ptr."
);
if
(
!
have_holder
())
return
nullptr
;
throw_if_uninitialized_or_disowned_holder
();
std
::
shared_ptr
<
void
>
void_ptr
=
holder
().
template
as_shared_ptr
<
void
>
();
return
std
::
shared_ptr
<
T
>
(
void_ptr
,
convert_type
(
void_ptr
.
get
()));
}
template
<
typename
D
>
std
::
unique_ptr
<
T
,
D
>
loaded_as_unique_ptr
(
const
char
*
context
=
"loaded_as_unique_ptr"
)
{
if
(
load_impl
.
unowned_void_ptr_from_direct_conversion
!=
nullptr
)
throw
cast_error
(
"Unowned pointer from direct conversion cannot be converted to a"
" std::unique_ptr."
);
if
(
!
have_holder
())
return
nullptr
;
throw_if_uninitialized_or_disowned_holder
();
holder
().
template
ensure_compatible_rtti_uqp_del
<
T
,
D
>
(
context
);
holder
().
ensure_use_count_1
(
context
);
auto
raw_void_ptr
=
holder
().
template
as_raw_ptr_unowned
<
void
>
();
// SMART_HOLDER_WIP: MISSING: Safety checks for type conversions
// (T must be polymorphic or meet certain other conditions).
T
*
raw_type_ptr
=
convert_type
(
raw_void_ptr
);
// Critical transfer-of-ownership section. This must stay together.
holder
().
release_ownership
();
auto
result
=
std
::
unique_ptr
<
T
,
D
>
(
raw_type_ptr
);
void
*
value_void_ptr
=
load_impl
.
loaded_v_h
.
value_ptr
();
if
(
value_void_ptr
!=
raw_void_ptr
)
{
pybind11_fail
(
"smart_holder_type_casters: loaded_as_unique_ptr failure:"
" value_void_ptr != raw_void_ptr"
);
}
load_impl
.
loaded_v_h
.
value_ptr
()
=
nullptr
;
deregister_instance
(
load_impl
.
loaded_v_h
.
inst
,
value_void_ptr
,
load_impl
.
loaded_v_h
.
type
);
return
result
;
}
private
:
modified_type_caster_generic_load_impl
load_impl
;
bool
have_holder
()
const
{
return
load_impl
.
loaded_v_h
.
vh
!=
nullptr
&&
load_impl
.
loaded_v_h
.
holder_constructed
();
}
holder_type
&
holder
()
const
{
return
load_impl
.
loaded_v_h
.
holder
<
holder_type
>
();
}
// have_holder() must be true or this function will fail.
void
throw_if_uninitialized_or_disowned_holder
()
const
{
if
(
!
holder
().
is_populated
)
{
pybind11_fail
(
"Missing value for wrapped C++ type:"
" Python instance is uninitialized."
);
}
if
(
!
holder
().
has_pointee
())
{
throw
cast_error
(
"Missing value for wrapped C++ type:"
" Python instance was disowned."
);
}
}
T
*
convert_type
(
void
*
void_ptr
)
const
{
if
(
void_ptr
!=
nullptr
&&
load_impl
.
loaded_v_h_cpptype
!=
nullptr
&&
!
load_impl
.
reinterpret_cast_deemed_ok
&&
load_impl
.
implicit_cast
!=
nullptr
)
{
void_ptr
=
load_impl
.
implicit_cast
(
void_ptr
);
}
return
static_cast
<
T
*>
(
void_ptr
);
}
};
// SMART_HOLDER_WIP: IMPROVABLE: Formally factor out of type_caster_base.
struct
make_constructor
:
private
type_caster_base
<
int
>
{
// Any type, nothing special about int.
using
type_caster_base
<
int
>::
Constructor
;
using
type_caster_base
<
int
>::
make_copy_constructor
;
using
type_caster_base
<
int
>::
make_move_constructor
;
};
template
<
typename
T
>
struct
smart_holder_type_caster
:
smart_holder_type_caster_load
<
T
>
,
smart_holder_type_caster_class_hooks
{
static
constexpr
auto
name
=
_
<
T
>
();
// static handle cast(T, ...)
// is redundant (leads to ambiguous overloads).
static
handle
cast
(
T
&&
src
,
return_value_policy
/*policy*/
,
handle
parent
)
{
// type_caster_base BEGIN
// clang-format off
return
cast
(
&
src
,
return_value_policy
::
move
,
parent
);
// clang-format on
// type_caster_base END
}
static
handle
cast
(
T
const
&
src
,
return_value_policy
policy
,
handle
parent
)
{
// type_caster_base BEGIN
// clang-format off
if
(
policy
==
return_value_policy
::
automatic
||
policy
==
return_value_policy
::
automatic_reference
)
policy
=
return_value_policy
::
copy
;
return
cast
(
&
src
,
policy
,
parent
);
// clang-format on
// type_caster_base END
}
static
handle
cast
(
T
&
src
,
return_value_policy
policy
,
handle
parent
)
{
return
cast
(
const_cast
<
T
const
&>
(
src
),
policy
,
parent
);
// Mutbl2Const
}
static
handle
cast
(
T
const
*
src
,
return_value_policy
policy
,
handle
parent
)
{
auto
st
=
type_caster_base
<
T
>::
src_and_type
(
src
);
return
cast_const_raw_ptr
(
// Originally type_caster_generic::cast.
st
.
first
,
policy
,
parent
,
st
.
second
,
make_constructor
::
make_copy_constructor
(
src
),
make_constructor
::
make_move_constructor
(
src
));
}
static
handle
cast
(
T
*
src
,
return_value_policy
policy
,
handle
parent
)
{
return
cast
(
const_cast
<
T
const
*>
(
src
),
policy
,
parent
);
// Mutbl2Const
}
#if defined(_MSC_VER) && _MSC_VER < 1910
// Working around MSVC 2015 bug. const-correctness is lost.
// SMART_HOLDER_WIP: IMPROVABLE: make common code work with MSVC 2015.
template
<
typename
T_
>
using
cast_op_type
=
detail
::
cast_op_type
<
T_
>
;
#else
template
<
typename
T_
>
using
cast_op_type
=
conditional_t
<
std
::
is_same
<
remove_reference_t
<
T_
>
,
T
const
*>::
value
,
T
const
*
,
conditional_t
<
std
::
is_same
<
remove_reference_t
<
T_
>
,
T
*>::
value
,
T
*
,
conditional_t
<
std
::
is_same
<
T_
,
T
const
&>::
value
,
T
const
&
,
T
&>>>
;
#endif
// The const operators here prove that the existing type_caster mechanism already supports
// const-correctness. However, fully implementing const-correctness inside this type_caster
// is still a major project.
operator
T
const
&
()
const
{
return
const_cast
<
smart_holder_type_caster
*>
(
this
)
->
loaded_as_lvalue_ref
();
}
operator
T
const
*
()
const
{
return
const_cast
<
smart_holder_type_caster
*>
(
this
)
->
loaded_as_raw_ptr_unowned
();
}
operator
T
&
()
{
return
this
->
loaded_as_lvalue_ref
();
}
operator
T
*
()
{
return
this
->
loaded_as_raw_ptr_unowned
();
}
// Originally type_caster_generic::cast.
PYBIND11_NOINLINE
static
handle
cast_const_raw_ptr
(
const
void
*
_src
,
return_value_policy
policy
,
handle
parent
,
const
detail
::
type_info
*
tinfo
,
void
*
(
*
copy_constructor
)(
const
void
*
),
void
*
(
*
move_constructor
)(
const
void
*
),
const
void
*
existing_holder
=
nullptr
)
{
if
(
!
tinfo
)
// no type info: error will be set already
return
handle
();
void
*
src
=
const_cast
<
void
*>
(
_src
);
if
(
src
==
nullptr
)
return
none
().
release
();
if
(
handle
existing_inst
=
find_registered_python_instance
(
src
,
tinfo
))
return
existing_inst
;
auto
inst
=
reinterpret_steal
<
object
>
(
make_new_instance
(
tinfo
->
type
));
auto
wrapper
=
reinterpret_cast
<
instance
*>
(
inst
.
ptr
());
wrapper
->
owned
=
false
;
void
*&
valueptr
=
values_and_holders
(
wrapper
).
begin
()
->
value_ptr
();
switch
(
policy
)
{
case
return_value_policy
:
:
automatic
:
case
return_value_policy
:
:
take_ownership
:
valueptr
=
src
;
wrapper
->
owned
=
true
;
break
;
case
return_value_policy
:
:
automatic_reference
:
case
return_value_policy
:
:
reference
:
valueptr
=
src
;
wrapper
->
owned
=
false
;
break
;
case
return_value_policy
:
:
copy
:
if
(
copy_constructor
)
valueptr
=
copy_constructor
(
src
);
else
{
#if defined(NDEBUG)
throw
cast_error
(
"return_value_policy = copy, but type is "
"non-copyable! (compile in debug mode for details)"
);
#else
std
::
string
type_name
(
tinfo
->
cpptype
->
name
());
detail
::
clean_type_id
(
type_name
);
throw
cast_error
(
"return_value_policy = copy, but type "
+
type_name
+
" is non-copyable!"
);
#endif
}
wrapper
->
owned
=
true
;
break
;
case
return_value_policy
:
:
move
:
if
(
move_constructor
)
valueptr
=
move_constructor
(
src
);
else
if
(
copy_constructor
)
valueptr
=
copy_constructor
(
src
);
else
{
#if defined(NDEBUG)
throw
cast_error
(
"return_value_policy = move, but type is neither "
"movable nor copyable! "
"(compile in debug mode for details)"
);
#else
std
::
string
type_name
(
tinfo
->
cpptype
->
name
());
detail
::
clean_type_id
(
type_name
);
throw
cast_error
(
"return_value_policy = move, but type "
+
type_name
+
" is neither movable nor copyable!"
);
#endif
}
wrapper
->
owned
=
true
;
break
;
case
return_value_policy
:
:
reference_internal
:
valueptr
=
src
;
wrapper
->
owned
=
false
;
keep_alive_impl
(
inst
,
parent
);
break
;
default
:
throw
cast_error
(
"unhandled return_value_policy: should not happen!"
);
}
tinfo
->
init_instance
(
wrapper
,
existing_holder
);
return
inst
.
release
();
}
};
template
<
typename
T
>
struct
smart_holder_type_caster
<
std
::
shared_ptr
<
T
>>
:
smart_holder_type_caster_load
<
T
>
,
smart_holder_type_caster_class_hooks
{
static
constexpr
auto
name
=
_
<
std
::
shared_ptr
<
T
>>
();
static
handle
cast
(
const
std
::
shared_ptr
<
T
>
&
src
,
return_value_policy
policy
,
handle
parent
)
{
if
(
policy
!=
return_value_policy
::
automatic
&&
policy
!=
return_value_policy
::
reference_internal
)
{
// SMART_HOLDER_WIP: IMPROVABLE: Error message.
throw
cast_error
(
"Invalid return_value_policy for shared_ptr."
);
}
auto
src_raw_ptr
=
src
.
get
();
auto
st
=
type_caster_base
<
T
>::
src_and_type
(
src_raw_ptr
);
if
(
st
.
first
==
nullptr
)
return
none
().
release
();
// PyErr was set already.
void
*
src_raw_void_ptr
=
static_cast
<
void
*>
(
src_raw_ptr
);
const
detail
::
type_info
*
tinfo
=
st
.
second
;
if
(
handle
existing_inst
=
find_registered_python_instance
(
src_raw_void_ptr
,
tinfo
))
// SMART_HOLDER_WIP: MISSING: Enforcement of consistency with existing smart_holder.
// SMART_HOLDER_WIP: MISSING: keep_alive.
return
existing_inst
;
auto
inst
=
reinterpret_steal
<
object
>
(
make_new_instance
(
tinfo
->
type
));
auto
*
inst_raw_ptr
=
reinterpret_cast
<
instance
*>
(
inst
.
ptr
());
inst_raw_ptr
->
owned
=
true
;
void
*&
valueptr
=
values_and_holders
(
inst_raw_ptr
).
begin
()
->
value_ptr
();
valueptr
=
src_raw_void_ptr
;
auto
smhldr
=
pybindit
::
memory
::
smart_holder
::
from_shared_ptr
(
src
);
tinfo
->
init_instance
(
inst_raw_ptr
,
static_cast
<
const
void
*>
(
&
smhldr
));
if
(
policy
==
return_value_policy
::
reference_internal
)
keep_alive_impl
(
inst
,
parent
);
return
inst
.
release
();
}
template
<
typename
>
using
cast_op_type
=
std
::
shared_ptr
<
T
>
;
operator
std
::
shared_ptr
<
T
>
()
{
return
this
->
loaded_as_shared_ptr
();
}
};
template
<
typename
T
>
struct
smart_holder_type_caster
<
std
::
shared_ptr
<
T
const
>>
:
smart_holder_type_caster_load
<
T
>
,
smart_holder_type_caster_class_hooks
{
static
constexpr
auto
name
=
_
<
std
::
shared_ptr
<
T
const
>>
();
static
handle
cast
(
const
std
::
shared_ptr
<
T
const
>
&
src
,
return_value_policy
policy
,
handle
parent
)
{
return
smart_holder_type_caster
<
std
::
shared_ptr
<
T
>>::
cast
(
std
::
const_pointer_cast
<
T
>
(
src
),
// Const2Mutbl
policy
,
parent
);
}
template
<
typename
>
using
cast_op_type
=
std
::
shared_ptr
<
T
const
>
;
operator
std
::
shared_ptr
<
T
const
>
()
{
return
this
->
loaded_as_shared_ptr
();
}
// Mutbl2Const
};
template
<
typename
T
,
typename
D
>
struct
smart_holder_type_caster
<
std
::
unique_ptr
<
T
,
D
>>
:
smart_holder_type_caster_load
<
T
>
,
smart_holder_type_caster_class_hooks
{
static
constexpr
auto
name
=
_
<
std
::
unique_ptr
<
T
,
D
>>
();
static
handle
cast
(
std
::
unique_ptr
<
T
,
D
>
&&
src
,
return_value_policy
policy
,
handle
parent
)
{
if
(
policy
!=
return_value_policy
::
automatic
&&
policy
!=
return_value_policy
::
reference_internal
&&
policy
!=
return_value_policy
::
move
)
{
// SMART_HOLDER_WIP: IMPROVABLE: Error message.
throw
cast_error
(
"Invalid return_value_policy for unique_ptr."
);
}
auto
src_raw_ptr
=
src
.
get
();
auto
st
=
type_caster_base
<
T
>::
src_and_type
(
src_raw_ptr
);
if
(
st
.
first
==
nullptr
)
return
none
().
release
();
// PyErr was set already.
void
*
src_raw_void_ptr
=
static_cast
<
void
*>
(
src_raw_ptr
);
const
detail
::
type_info
*
tinfo
=
st
.
second
;
if
(
find_registered_python_instance
(
src_raw_void_ptr
,
tinfo
))
throw
cast_error
(
"Invalid unique_ptr: another instance owns this pointer already."
);
auto
inst
=
reinterpret_steal
<
object
>
(
make_new_instance
(
tinfo
->
type
));
auto
*
inst_raw_ptr
=
reinterpret_cast
<
instance
*>
(
inst
.
ptr
());
inst_raw_ptr
->
owned
=
true
;
void
*&
valueptr
=
values_and_holders
(
inst_raw_ptr
).
begin
()
->
value_ptr
();
valueptr
=
src_raw_void_ptr
;
auto
smhldr
=
pybindit
::
memory
::
smart_holder
::
from_unique_ptr
(
std
::
move
(
src
));
tinfo
->
init_instance
(
inst_raw_ptr
,
static_cast
<
const
void
*>
(
&
smhldr
));
if
(
policy
==
return_value_policy
::
reference_internal
)
keep_alive_impl
(
inst
,
parent
);
return
inst
.
release
();
}
template
<
typename
>
using
cast_op_type
=
std
::
unique_ptr
<
T
,
D
>
;
operator
std
::
unique_ptr
<
T
,
D
>
()
{
return
this
->
template
loaded_as_unique_ptr
<
D
>
();
}
};
template
<
typename
T
,
typename
D
>
struct
smart_holder_type_caster
<
std
::
unique_ptr
<
T
const
,
D
>>
:
smart_holder_type_caster_load
<
T
>
,
smart_holder_type_caster_class_hooks
{
static
constexpr
auto
name
=
_
<
std
::
unique_ptr
<
T
const
,
D
>>
();
static
handle
cast
(
std
::
unique_ptr
<
T
const
,
D
>
&&
src
,
return_value_policy
policy
,
handle
parent
)
{
return
smart_holder_type_caster
<
std
::
unique_ptr
<
T
,
D
>>::
cast
(
std
::
unique_ptr
<
T
,
D
>
(
const_cast
<
T
*>
(
src
.
release
())),
// Const2Mutbl
policy
,
parent
);
}
template
<
typename
>
using
cast_op_type
=
std
::
unique_ptr
<
T
const
,
D
>
;
operator
std
::
unique_ptr
<
T
const
,
D
>
()
{
return
this
->
template
loaded_as_unique_ptr
<
D
>
();
}
// SMART_HOLDER_WIP: Needs refactoring of existing pybind11 code.
};
#define PYBIND11_CAST_H_SMART_HOLDER_TYPE_CASTERS_INLINE_INCLUDE_SAFETY_GUARD
#include "detail/smart_holder_type_casters_inline_include.h"
#undef PYBIND11_CAST_H_SMART_HOLDER_TYPE_CASTERS_INLINE_INCLUDE_SAFETY_GUARD
#ifndef PYBIND11_USE_SMART_HOLDER_AS_DEFAULT
PYBIND11_NAMESPACE_BEGIN
(
PYBIND11_NAMESPACE
)
#define PYBIND11_SMART_HOLDER_TYPE_CASTERS(T) \
PYBIND11_NAMESPACE_BEGIN
(
detail
)
namespace pybind11 { \
namespace detail { \
template <> \
class type_caster<T> : public smart_holder_type_caster<T> {}; \
template <> \
class type_caster<std::shared_ptr<T>> : public smart_holder_type_caster<std::shared_ptr<T>> { \
}; \
template <> \
class type_caster<std::shared_ptr<T const>> \
: public smart_holder_type_caster<std::shared_ptr<T const>> {}; \
template <typename D> \
class type_caster<std::unique_ptr<T, D>> \
: public smart_holder_type_caster<std::unique_ptr<T, D>> {}; \
template <typename D> \
class type_caster<std::unique_ptr<T const, D>> \
: public smart_holder_type_caster<std::unique_ptr<T const, D>> {}; \
} \
}
#endif
//DETAIL/SMART_HOLDER_TYPE_CASTERS_H/END///////////////////////////////////////////////////////////
#ifndef PYBIND11_USE_SMART_HOLDER_AS_DEFAULT
#ifndef PYBIND11_USE_SMART_HOLDER_AS_DEFAULT
#define PYBIND11_SMART_POINTER_HOLDER_TYPE_CASTERS(T, ...)
#
define PYBIND11_SMART_POINTER_HOLDER_TYPE_CASTERS(T, ...)
template
<
typename
T
>
class
type_caster_for_class_
:
public
type_caster_base
<
T
>
{};
template
<
typename
T
>
class
type_caster_for_class_
:
public
type_caster_base
<
T
>
{};
#else
#else
#
define PYBIND11_SMART_POINTER_HOLDER_TYPE_CASTERS(T, ...)
\
#
define PYBIND11_SMART_POINTER_HOLDER_TYPE_CASTERS(T, ...)
\
namespace pybind11 { \
namespace pybind11 { \
namespace detail { \
namespace detail { \
template <> \
template <> \
...
@@ -1662,10 +993,12 @@ template <typename T> class type_caster_for_class_ : public type_caster_base<T>
...
@@ -1662,10 +993,12 @@ template <typename T> class type_caster_for_class_ : public type_caster_base<T>
} \
} \
}
}
template
<
typename
T
>
class
type_caster_for_class_
:
public
smart_holder_type_caster
<
T
>
{};
template
<
typename
T
>
class
type_caster_for_class_
:
public
smart_holder_type_caster
<
T
>
{};
template
<
typename
T
>
template
<
typename
T
>
class
type_caster_for_class_
<
std
::
shared_ptr
<
T
>>
:
public
smart_holder_type_caster
<
std
::
shared_ptr
<
T
>>
{};
class
type_caster_for_class_
<
std
::
shared_ptr
<
T
>>
:
public
smart_holder_type_caster
<
std
::
shared_ptr
<
T
>>
{};
template
<
typename
T
>
template
<
typename
T
>
class
type_caster_for_class_
<
std
::
shared_ptr
<
T
const
>>
class
type_caster_for_class_
<
std
::
shared_ptr
<
T
const
>>
...
@@ -1679,20 +1012,22 @@ template <typename T, typename D>
...
@@ -1679,20 +1012,22 @@ template <typename T, typename D>
class
type_caster_for_class_
<
std
::
unique_ptr
<
T
const
,
D
>>
class
type_caster_for_class_
<
std
::
unique_ptr
<
T
const
,
D
>>
:
public
smart_holder_type_caster
<
std
::
unique_ptr
<
T
const
,
D
>>
{};
:
public
smart_holder_type_caster
<
std
::
unique_ptr
<
T
const
,
D
>>
{};
#define PYBIND11_SMART_HOLDER_TYPE_CASTERS(T)
#
define PYBIND11_SMART_HOLDER_TYPE_CASTERS(T)
#endif
#endif
template
<
typename
type
,
typename
SFINAE
=
void
>
class
type_caster
:
public
type_caster_for_class_
<
type
>
{
};
template
<
typename
type
,
typename
SFINAE
=
void
>
class
type_caster
:
public
type_caster_for_class_
<
type
>
{};
template
<
typename
type
>
using
make_caster
=
type_caster
<
intrinsic_t
<
type
>>
;
template
<
typename
type
>
using
make_caster
=
type_caster
<
intrinsic_t
<
type
>>
;
template
<
typename
T
>
template
<
typename
T
>
struct
is_smart_holder_type_caster
{
struct
is_smart_holder_type_caster
{
static
constexpr
bool
value
=
std
::
is_base_of
<
static
constexpr
bool
value
is_smart_holder_type_caster_base_tag
,
=
std
::
is_base_of
<
is_smart_holder_type_caster_base_tag
,
make_caster
<
T
>>::
value
;
make_caster
<
T
>>::
value
;
};
};
// clang-format off
// Shortcut for calling a caster's `cast_op_type` cast operator for casting a type_caster to a T
// Shortcut for calling a caster's `cast_op_type` cast operator for casting a type_caster to a T
template
<
typename
T
>
typename
make_caster
<
T
>::
template
cast_op_type
<
T
>
cast_op
(
make_caster
<
T
>
&
caster
)
{
template
<
typename
T
>
typename
make_caster
<
T
>::
template
cast_op_type
<
T
>
cast_op
(
make_caster
<
T
>
&
caster
)
{
...
@@ -2468,8 +1803,8 @@ template <typename T> using move_never = none_of<move_always<T>, move_if_unrefer
...
@@ -2468,8 +1803,8 @@ template <typename T> using move_never = none_of<move_always<T>, move_if_unrefer
template
<
typename
type
>
using
cast_is_temporary_value_reference
=
bool_constant
<
template
<
typename
type
>
using
cast_is_temporary_value_reference
=
bool_constant
<
(
std
::
is_reference
<
type
>::
value
||
std
::
is_pointer
<
type
>::
value
)
&&
(
std
::
is_reference
<
type
>::
value
||
std
::
is_pointer
<
type
>::
value
)
&&
!
std
::
is_base_of
<
type_caster_generic
,
make_caster
<
type
>>::
value
&&
!
std
::
is_base_of
<
type_caster_generic
,
make_caster
<
type
>>::
value
&&
!
std
::
is_same
<
intrinsic_t
<
type
>
,
void
>::
value
&&
!
is_smart_holder_type_caster
<
intrinsic_t
<
type
>
>::
value
&&
!
is_smart_holder_type_caster
<
intrinsic_t
<
type
>
>::
value
!
std
::
is_same
<
intrinsic_t
<
type
>
,
void
>::
value
>
;
>
;
// When a value returned from a C++ function is being cast back to Python, we almost always want to
// When a value returned from a C++ function is being cast back to Python, we almost always want to
...
...
include/pybind11/detail/init.h
View file @
d3b2d567
...
@@ -169,55 +169,10 @@ void construct(value_and_holder &v_h, Alias<Class> &&result, bool) {
...
@@ -169,55 +169,10 @@ void construct(value_and_holder &v_h, Alias<Class> &&result, bool) {
v_h
.
value_ptr
()
=
new
Alias
<
Class
>
(
std
::
move
(
result
));
v_h
.
value_ptr
()
=
new
Alias
<
Class
>
(
std
::
move
(
result
));
}
}
//DETAIL/SMART_HOLDER_INIT_H/BEGIN/////////////////////////////////////////////////////////////////
// SMART_HOLDER_WIP: Needs refactoring of existing pybind11 code.
#define PYBIND11_DETAIL_INIT_H_SMART_HOLDER_INIT_INLINE_INCLUDE_SAFETY_GUARD
template
<
typename
Class
,
typename
D
=
std
::
default_delete
<
Cpp
<
Class
>>
,
#include "smart_holder_init_inline_include.h"
detail
::
enable_if_t
<
detail
::
is_smart_holder_type_caster
<
Cpp
<
Class
>>::
value
,
int
>
=
0
>
#undef PYBIND11_DETAIL_INIT_H_SMART_HOLDER_INIT_INLINE_INCLUDE_SAFETY_GUARD
void
construct
(
value_and_holder
&
v_h
,
std
::
unique_ptr
<
Cpp
<
Class
>
,
D
>
&&
unq_ptr
,
bool
need_alias
)
{
auto
*
ptr
=
unq_ptr
.
get
();
no_nullptr
(
ptr
);
if
(
Class
::
has_alias
&&
need_alias
)
throw
type_error
(
"pybind11::init(): construction failed: returned std::unique_ptr pointee "
"is not an alias instance"
);
auto
smhldr
=
smart_holder
::
from_unique_ptr
(
std
::
move
(
unq_ptr
));
v_h
.
value_ptr
()
=
ptr
;
v_h
.
type
->
init_instance
(
v_h
.
inst
,
&
smhldr
);
}
template
<
typename
Class
,
typename
D
=
std
::
default_delete
<
Alias
<
Class
>>
,
detail
::
enable_if_t
<
detail
::
is_smart_holder_type_caster
<
Alias
<
Class
>>::
value
,
int
>
=
0
>
void
construct
(
value_and_holder
&
v_h
,
std
::
unique_ptr
<
Alias
<
Class
>
,
D
>
&&
unq_ptr
,
bool
/*need_alias*/
)
{
auto
*
ptr
=
unq_ptr
.
get
();
no_nullptr
(
ptr
);
auto
smhldr
=
smart_holder
::
from_unique_ptr
(
std
::
move
(
unq_ptr
));
v_h
.
value_ptr
()
=
ptr
;
v_h
.
type
->
init_instance
(
v_h
.
inst
,
&
smhldr
);
}
template
<
typename
Class
,
detail
::
enable_if_t
<
detail
::
is_smart_holder_type_caster
<
Cpp
<
Class
>>::
value
,
int
>
=
0
>
void
construct
(
value_and_holder
&
v_h
,
std
::
shared_ptr
<
Cpp
<
Class
>>
&&
shd_ptr
,
bool
need_alias
)
{
auto
*
ptr
=
shd_ptr
.
get
();
no_nullptr
(
ptr
);
if
(
Class
::
has_alias
&&
need_alias
)
throw
type_error
(
"pybind11::init(): construction failed: returned std::shared_ptr pointee "
"is not an alias instance"
);
auto
smhldr
=
smart_holder
::
from_shared_ptr
(
std
::
move
(
shd_ptr
));
v_h
.
value_ptr
()
=
ptr
;
v_h
.
type
->
init_instance
(
v_h
.
inst
,
&
smhldr
);
}
template
<
typename
Class
,
detail
::
enable_if_t
<
detail
::
is_smart_holder_type_caster
<
Alias
<
Class
>>::
value
,
int
>
=
0
>
void
construct
(
value_and_holder
&
v_h
,
std
::
shared_ptr
<
Alias
<
Class
>>
&&
shd_ptr
,
bool
/*need_alias*/
)
{
auto
*
ptr
=
shd_ptr
.
get
();
no_nullptr
(
ptr
);
auto
smhldr
=
smart_holder
::
from_shared_ptr
(
std
::
move
(
shd_ptr
));
v_h
.
value_ptr
()
=
ptr
;
v_h
.
type
->
init_instance
(
v_h
.
inst
,
&
smhldr
);
}
//DETAIL/SMART_HOLDER_INIT_H/END///////////////////////////////////////////////////////////////////
// Implementing class for py::init<...>()
// Implementing class for py::init<...>()
template
<
typename
...
Args
>
template
<
typename
...
Args
>
...
...
include/pybind11/detail/smart_holder_init_inline_include.h
0 → 100644
View file @
d3b2d567
#ifndef PYBIND11_DETAIL_INIT_H_SMART_HOLDER_INIT_INLINE_INCLUDE_SAFETY_GUARD
# error "THIS FILE MUST ONLY BE INCLUDED FROM pybind11/detail/init.h"
#endif
template
<
typename
Class
,
typename
D
=
std
::
default_delete
<
Cpp
<
Class
>>
,
detail
::
enable_if_t
<
detail
::
is_smart_holder_type_caster
<
Cpp
<
Class
>>::
value
,
int
>
=
0
>
void
construct
(
value_and_holder
&
v_h
,
std
::
unique_ptr
<
Cpp
<
Class
>
,
D
>
&&
unq_ptr
,
bool
need_alias
)
{
auto
*
ptr
=
unq_ptr
.
get
();
no_nullptr
(
ptr
);
if
(
Class
::
has_alias
&&
need_alias
)
throw
type_error
(
"pybind11::init(): construction failed: returned std::unique_ptr pointee "
"is not an alias instance"
);
auto
smhldr
=
smart_holder
::
from_unique_ptr
(
std
::
move
(
unq_ptr
));
v_h
.
value_ptr
()
=
ptr
;
v_h
.
type
->
init_instance
(
v_h
.
inst
,
&
smhldr
);
}
template
<
typename
Class
,
typename
D
=
std
::
default_delete
<
Alias
<
Class
>>
,
detail
::
enable_if_t
<
detail
::
is_smart_holder_type_caster
<
Alias
<
Class
>>::
value
,
int
>
=
0
>
void
construct
(
value_and_holder
&
v_h
,
std
::
unique_ptr
<
Alias
<
Class
>
,
D
>
&&
unq_ptr
,
bool
/*need_alias*/
)
{
auto
*
ptr
=
unq_ptr
.
get
();
no_nullptr
(
ptr
);
auto
smhldr
=
smart_holder
::
from_unique_ptr
(
std
::
move
(
unq_ptr
));
v_h
.
value_ptr
()
=
ptr
;
v_h
.
type
->
init_instance
(
v_h
.
inst
,
&
smhldr
);
}
template
<
typename
Class
,
detail
::
enable_if_t
<
detail
::
is_smart_holder_type_caster
<
Cpp
<
Class
>>::
value
,
int
>
=
0
>
void
construct
(
value_and_holder
&
v_h
,
std
::
shared_ptr
<
Cpp
<
Class
>>
&&
shd_ptr
,
bool
need_alias
)
{
auto
*
ptr
=
shd_ptr
.
get
();
no_nullptr
(
ptr
);
if
(
Class
::
has_alias
&&
need_alias
)
throw
type_error
(
"pybind11::init(): construction failed: returned std::shared_ptr pointee "
"is not an alias instance"
);
auto
smhldr
=
smart_holder
::
from_shared_ptr
(
std
::
move
(
shd_ptr
));
v_h
.
value_ptr
()
=
ptr
;
v_h
.
type
->
init_instance
(
v_h
.
inst
,
&
smhldr
);
}
template
<
typename
Class
,
detail
::
enable_if_t
<
detail
::
is_smart_holder_type_caster
<
Alias
<
Class
>>::
value
,
int
>
=
0
>
void
construct
(
value_and_holder
&
v_h
,
std
::
shared_ptr
<
Alias
<
Class
>>
&&
shd_ptr
,
bool
/*need_alias*/
)
{
auto
*
ptr
=
shd_ptr
.
get
();
no_nullptr
(
ptr
);
auto
smhldr
=
smart_holder
::
from_shared_ptr
(
std
::
move
(
shd_ptr
));
v_h
.
value_ptr
()
=
ptr
;
v_h
.
type
->
init_instance
(
v_h
.
inst
,
&
smhldr
);
}
include/pybind11/detail/smart_holder_type_casters_inline_include.h
0 → 100644
View file @
d3b2d567
#ifndef PYBIND11_CAST_H_SMART_HOLDER_TYPE_CASTERS_INLINE_INCLUDE_SAFETY_GUARD
# error "THIS FILE MUST ONLY BE INCLUDED FROM pybind11/cast.h"
#endif
#include "smart_holder_poc.h"
PYBIND11_NAMESPACE_BEGIN
(
PYBIND11_NAMESPACE
)
using
pybindit
::
memory
::
smart_holder
;
PYBIND11_NAMESPACE_BEGIN
(
detail
)
// SMART_HOLDER_WIP: Needs refactoring of existing pybind11 code.
inline
void
register_instance
(
instance
*
self
,
void
*
valptr
,
const
type_info
*
tinfo
);
inline
bool
deregister_instance
(
instance
*
self
,
void
*
valptr
,
const
type_info
*
tinfo
);
// The modified_type_caster_generic_load_impl could replace type_caster_generic::load_impl but not
// vice versa. The main difference is that the original code only propagates a reference to the
// held value, while the modified implementation propagates value_and_holder.
// clang-format off
class
modified_type_caster_generic_load_impl
{
public
:
PYBIND11_NOINLINE
modified_type_caster_generic_load_impl
(
const
std
::
type_info
&
type_info
)
:
typeinfo
(
get_type_info
(
type_info
)),
cpptype
(
&
type_info
)
{
}
explicit
modified_type_caster_generic_load_impl
(
const
type_info
*
typeinfo
=
nullptr
)
:
typeinfo
(
typeinfo
),
cpptype
(
typeinfo
?
typeinfo
->
cpptype
:
nullptr
)
{
}
bool
load
(
handle
src
,
bool
convert
)
{
return
load_impl
<
modified_type_caster_generic_load_impl
>
(
src
,
convert
);
}
// Base methods for generic caster; there are overridden in copyable_holder_caster
void
load_value_and_holder
(
value_and_holder
&&
v_h
)
{
if
(
!
v_h
.
holder_constructed
())
{
// This is needed for old-style __init__.
// type_caster_generic::load_value BEGIN
auto
*&
vptr
=
v_h
.
value_ptr
();
// Lazy allocation for unallocated values:
if
(
vptr
==
nullptr
)
{
// Lazy allocation for unallocated values:
auto
*
type
=
v_h
.
type
?
v_h
.
type
:
typeinfo
;
if
(
type
->
operator_new
)
{
vptr
=
type
->
operator_new
(
type
->
type_size
);
}
else
{
#if defined(__cpp_aligned_new) && (!defined(_MSC_VER) || _MSC_VER >= 1912)
if
(
type
->
type_align
>
__STDCPP_DEFAULT_NEW_ALIGNMENT__
)
vptr
=
::
operator
new
(
type
->
type_size
,
std
::
align_val_t
(
type
->
type_align
));
else
#endif
vptr
=
::
operator
new
(
type
->
type_size
);
}
}
// type_caster_generic::load_value END
}
loaded_v_h
=
std
::
move
(
v_h
);
loaded_v_h
.
type
=
typeinfo
;
}
bool
try_implicit_casts
(
handle
src
,
bool
convert
)
{
for
(
auto
&
cast
:
typeinfo
->
implicit_casts
)
{
modified_type_caster_generic_load_impl
sub_caster
(
*
cast
.
first
);
if
(
sub_caster
.
load
(
src
,
convert
))
{
if
(
loaded_v_h_cpptype
!=
nullptr
)
{
pybind11_fail
(
"smart_holder_type_casters: try_implicit_casts failure."
);
}
loaded_v_h
=
sub_caster
.
loaded_v_h
;
loaded_v_h_cpptype
=
cast
.
first
;
implicit_cast
=
cast
.
second
;
return
true
;
}
}
return
false
;
}
bool
try_direct_conversions
(
handle
src
)
{
for
(
auto
&
converter
:
*
typeinfo
->
direct_conversions
)
{
if
(
converter
(
src
.
ptr
(),
unowned_void_ptr_from_direct_conversion
))
{
return
true
;
}
}
return
false
;
}
PYBIND11_NOINLINE
static
void
*
local_load
(
PyObject
*
src
,
const
type_info
*
ti
)
{
std
::
unique_ptr
<
modified_type_caster_generic_load_impl
>
loader
(
new
modified_type_caster_generic_load_impl
(
ti
));
if
(
loader
->
load
(
src
,
false
))
{
// Trick to work with the existing pybind11 internals.
// The void pointer is immediately captured in a new unique_ptr in
// try_load_foreign_module_local. If this assumption is violated sanitizers
// will most likely flag a leak (verified to be the case with ASAN).
return
static_cast
<
void
*>
(
loader
.
release
());
}
return
nullptr
;
}
/// Try to load with foreign typeinfo, if available. Used when there is no
/// native typeinfo, or when the native one wasn't able to produce a value.
PYBIND11_NOINLINE
bool
try_load_foreign_module_local
(
handle
src
)
{
constexpr
auto
*
local_key
=
PYBIND11_MODULE_LOCAL_ID
;
const
auto
pytype
=
type
::
handle_of
(
src
);
if
(
!
hasattr
(
pytype
,
local_key
))
return
false
;
type_info
*
foreign_typeinfo
=
reinterpret_borrow
<
capsule
>
(
getattr
(
pytype
,
local_key
));
// Only consider this foreign loader if actually foreign and is a loader of the correct cpp type
if
(
foreign_typeinfo
->
module_local_load
==
&
local_load
||
(
cpptype
&&
!
same_type
(
*
cpptype
,
*
foreign_typeinfo
->
cpptype
)))
return
false
;
void
*
foreign_loader_void_ptr
=
foreign_typeinfo
->
module_local_load
(
src
.
ptr
(),
foreign_typeinfo
);
if
(
foreign_loader_void_ptr
!=
nullptr
)
{
auto
foreign_loader
=
std
::
unique_ptr
<
modified_type_caster_generic_load_impl
>
(
static_cast
<
modified_type_caster_generic_load_impl
*>
(
foreign_loader_void_ptr
));
// Magic number intentionally hard-coded for simplicity and maximum robustness.
if
(
foreign_loader
->
local_load_safety_guard
!=
1887406645
)
{
pybind11_fail
(
"smart_holder_type_casters: Unexpected local_load_safety_guard,"
" possibly due to py::class_ holder mixup."
);
}
if
(
loaded_v_h_cpptype
!=
nullptr
)
{
pybind11_fail
(
"smart_holder_type_casters: try_load_foreign_module_local failure."
);
}
loaded_v_h
=
foreign_loader
->
loaded_v_h
;
loaded_v_h_cpptype
=
foreign_loader
->
loaded_v_h_cpptype
;
implicit_cast
=
foreign_loader
->
implicit_cast
;
return
true
;
}
return
false
;
}
// Implementation of `load`; this takes the type of `this` so that it can dispatch the relevant
// bits of code between here and copyable_holder_caster where the two classes need different
// logic (without having to resort to virtual inheritance).
template
<
typename
ThisT
>
PYBIND11_NOINLINE
bool
load_impl
(
handle
src
,
bool
convert
)
{
if
(
!
src
)
return
false
;
if
(
!
typeinfo
)
return
try_load_foreign_module_local
(
src
);
if
(
src
.
is_none
())
{
// Defer accepting None to other overloads (if we aren't in convert mode):
if
(
!
convert
)
return
false
;
loaded_v_h
=
value_and_holder
();
return
true
;
}
auto
&
this_
=
static_cast
<
ThisT
&>
(
*
this
);
PyTypeObject
*
srctype
=
Py_TYPE
(
src
.
ptr
());
// Case 1: If src is an exact type match for the target type then we can reinterpret_cast
// the instance's value pointer to the target type:
if
(
srctype
==
typeinfo
->
type
)
{
this_
.
load_value_and_holder
(
reinterpret_cast
<
instance
*>
(
src
.
ptr
())
->
get_value_and_holder
());
return
true
;
}
// Case 2: We have a derived class
else
if
(
PyType_IsSubtype
(
srctype
,
typeinfo
->
type
))
{
auto
&
bases
=
all_type_info
(
srctype
);
// subtype bases
bool
no_cpp_mi
=
typeinfo
->
simple_type
;
// Case 2a: the python type is a Python-inherited derived class that inherits from just
// one simple (no MI) pybind11 class, or is an exact match, so the C++ instance is of
// the right type and we can use reinterpret_cast.
// (This is essentially the same as case 2b, but because not using multiple inheritance
// is extremely common, we handle it specially to avoid the loop iterator and type
// pointer lookup overhead)
if
(
bases
.
size
()
==
1
&&
(
no_cpp_mi
||
bases
.
front
()
->
type
==
typeinfo
->
type
))
{
this_
.
load_value_and_holder
(
reinterpret_cast
<
instance
*>
(
src
.
ptr
())
->
get_value_and_holder
());
loaded_v_h_cpptype
=
bases
.
front
()
->
cpptype
;
reinterpret_cast_deemed_ok
=
true
;
return
true
;
}
// Case 2b: the python type inherits from multiple C++ bases. Check the bases to see if
// we can find an exact match (or, for a simple C++ type, an inherited match); if so, we
// can safely reinterpret_cast to the relevant pointer.
else
if
(
bases
.
size
()
>
1
)
{
for
(
auto
base
:
bases
)
{
if
(
no_cpp_mi
?
PyType_IsSubtype
(
base
->
type
,
typeinfo
->
type
)
:
base
->
type
==
typeinfo
->
type
)
{
this_
.
load_value_and_holder
(
reinterpret_cast
<
instance
*>
(
src
.
ptr
())
->
get_value_and_holder
(
base
));
loaded_v_h_cpptype
=
base
->
cpptype
;
reinterpret_cast_deemed_ok
=
true
;
return
true
;
}
}
}
// Case 2c: C++ multiple inheritance is involved and we couldn't find an exact type match
// in the registered bases, above, so try implicit casting (needed for proper C++ casting
// when MI is involved).
if
(
this_
.
try_implicit_casts
(
src
,
convert
))
{
return
true
;
}
}
// Perform an implicit conversion
if
(
convert
)
{
for
(
auto
&
converter
:
typeinfo
->
implicit_conversions
)
{
auto
temp
=
reinterpret_steal
<
object
>
(
converter
(
src
.
ptr
(),
typeinfo
->
type
));
if
(
load_impl
<
ThisT
>
(
temp
,
false
))
{
loader_life_support
::
add_patient
(
temp
);
return
true
;
}
}
if
(
this_
.
try_direct_conversions
(
src
))
return
true
;
}
// Failed to match local typeinfo. Try again with global.
if
(
typeinfo
->
module_local
)
{
if
(
auto
gtype
=
get_global_type_info
(
*
typeinfo
->
cpptype
))
{
typeinfo
=
gtype
;
return
load
(
src
,
false
);
}
}
// Global typeinfo has precedence over foreign module_local
return
try_load_foreign_module_local
(
src
);
}
const
type_info
*
typeinfo
=
nullptr
;
const
std
::
type_info
*
cpptype
=
nullptr
;
void
*
unowned_void_ptr_from_direct_conversion
=
nullptr
;
const
std
::
type_info
*
loaded_v_h_cpptype
=
nullptr
;
void
*
(
*
implicit_cast
)(
void
*
)
=
nullptr
;
value_and_holder
loaded_v_h
;
bool
reinterpret_cast_deemed_ok
=
false
;
// Magic number intentionally hard-coded, to guard against class_ holder mixups.
// Ideally type_caster_generic would have a similar guard, but this requires a change there.
std
::
size_t
local_load_safety_guard
=
1887406645
;
// 32-bit compatible value for portability.
};
// clang-format on
struct
smart_holder_type_caster_class_hooks
:
is_smart_holder_type_caster_base_tag
{
static
decltype
(
&
modified_type_caster_generic_load_impl
::
local_load
)
get_local_load_function_ptr
()
{
return
&
modified_type_caster_generic_load_impl
::
local_load
;
}
template
<
typename
T
>
static
void
init_instance_for_type
(
detail
::
instance
*
inst
,
const
void
*
holder_const_void_ptr
)
{
// Need for const_cast is a consequence of the type_info::init_instance type:
// void (*init_instance)(instance *, const void *);
auto
holder_void_ptr
=
const_cast
<
void
*>
(
holder_const_void_ptr
);
auto
v_h
=
inst
->
get_value_and_holder
(
detail
::
get_type_info
(
typeid
(
T
)));
if
(
!
v_h
.
instance_registered
())
{
register_instance
(
inst
,
v_h
.
value_ptr
(),
v_h
.
type
);
v_h
.
set_instance_registered
();
}
using
holder_type
=
pybindit
::
memory
::
smart_holder
;
if
(
holder_void_ptr
)
{
// Note: inst->owned ignored.
auto
holder_ptr
=
static_cast
<
holder_type
*>
(
holder_void_ptr
);
new
(
std
::
addressof
(
v_h
.
holder
<
holder_type
>
()))
holder_type
(
std
::
move
(
*
holder_ptr
));
}
else
if
(
inst
->
owned
)
{
new
(
std
::
addressof
(
v_h
.
holder
<
holder_type
>
()))
holder_type
(
holder_type
::
from_raw_ptr_take_ownership
(
v_h
.
value_ptr
<
T
>
()));
}
else
{
new
(
std
::
addressof
(
v_h
.
holder
<
holder_type
>
()))
holder_type
(
holder_type
::
from_raw_ptr_unowned
(
v_h
.
value_ptr
<
T
>
()));
}
v_h
.
set_holder_constructed
();
}
};
template
<
typename
T
>
struct
smart_holder_type_caster_load
{
using
holder_type
=
pybindit
::
memory
::
smart_holder
;
bool
load
(
handle
src
,
bool
convert
)
{
static_assert
(
is_smart_holder_type_caster
<
T
>::
value
,
"Internal consistency error."
);
load_impl
=
modified_type_caster_generic_load_impl
(
typeid
(
T
));
if
(
!
load_impl
.
load
(
src
,
convert
))
return
false
;
return
true
;
}
T
*
loaded_as_raw_ptr_unowned
()
const
{
void
*
void_ptr
=
load_impl
.
unowned_void_ptr_from_direct_conversion
;
if
(
void_ptr
==
nullptr
)
{
if
(
have_holder
())
{
throw_if_uninitialized_or_disowned_holder
();
void_ptr
=
holder
().
template
as_raw_ptr_unowned
<
void
>
();
}
else
if
(
load_impl
.
loaded_v_h
.
vh
!=
nullptr
)
void_ptr
=
load_impl
.
loaded_v_h
.
value_ptr
();
if
(
void_ptr
==
nullptr
)
return
nullptr
;
}
return
convert_type
(
void_ptr
);
}
T
&
loaded_as_lvalue_ref
()
const
{
T
*
raw_ptr
=
loaded_as_raw_ptr_unowned
();
if
(
raw_ptr
==
nullptr
)
throw
reference_cast_error
();
return
*
raw_ptr
;
}
std
::
shared_ptr
<
T
>
loaded_as_shared_ptr
()
const
{
if
(
load_impl
.
unowned_void_ptr_from_direct_conversion
!=
nullptr
)
throw
cast_error
(
"Unowned pointer from direct conversion cannot be converted to a"
" std::shared_ptr."
);
if
(
!
have_holder
())
return
nullptr
;
throw_if_uninitialized_or_disowned_holder
();
std
::
shared_ptr
<
void
>
void_ptr
=
holder
().
template
as_shared_ptr
<
void
>
();
return
std
::
shared_ptr
<
T
>
(
void_ptr
,
convert_type
(
void_ptr
.
get
()));
}
template
<
typename
D
>
std
::
unique_ptr
<
T
,
D
>
loaded_as_unique_ptr
(
const
char
*
context
=
"loaded_as_unique_ptr"
)
{
if
(
load_impl
.
unowned_void_ptr_from_direct_conversion
!=
nullptr
)
throw
cast_error
(
"Unowned pointer from direct conversion cannot be converted to a"
" std::unique_ptr."
);
if
(
!
have_holder
())
return
nullptr
;
throw_if_uninitialized_or_disowned_holder
();
holder
().
template
ensure_compatible_rtti_uqp_del
<
T
,
D
>
(
context
);
holder
().
ensure_use_count_1
(
context
);
auto
raw_void_ptr
=
holder
().
template
as_raw_ptr_unowned
<
void
>
();
// SMART_HOLDER_WIP: MISSING: Safety checks for type conversions
// (T must be polymorphic or meet certain other conditions).
T
*
raw_type_ptr
=
convert_type
(
raw_void_ptr
);
// Critical transfer-of-ownership section. This must stay together.
holder
().
release_ownership
();
auto
result
=
std
::
unique_ptr
<
T
,
D
>
(
raw_type_ptr
);
void
*
value_void_ptr
=
load_impl
.
loaded_v_h
.
value_ptr
();
if
(
value_void_ptr
!=
raw_void_ptr
)
{
pybind11_fail
(
"smart_holder_type_casters: loaded_as_unique_ptr failure:"
" value_void_ptr != raw_void_ptr"
);
}
load_impl
.
loaded_v_h
.
value_ptr
()
=
nullptr
;
deregister_instance
(
load_impl
.
loaded_v_h
.
inst
,
value_void_ptr
,
load_impl
.
loaded_v_h
.
type
);
return
result
;
}
private
:
modified_type_caster_generic_load_impl
load_impl
;
bool
have_holder
()
const
{
return
load_impl
.
loaded_v_h
.
vh
!=
nullptr
&&
load_impl
.
loaded_v_h
.
holder_constructed
();
}
holder_type
&
holder
()
const
{
return
load_impl
.
loaded_v_h
.
holder
<
holder_type
>
();
}
// have_holder() must be true or this function will fail.
void
throw_if_uninitialized_or_disowned_holder
()
const
{
if
(
!
holder
().
is_populated
)
{
pybind11_fail
(
"Missing value for wrapped C++ type:"
" Python instance is uninitialized."
);
}
if
(
!
holder
().
has_pointee
())
{
throw
cast_error
(
"Missing value for wrapped C++ type:"
" Python instance was disowned."
);
}
}
T
*
convert_type
(
void
*
void_ptr
)
const
{
if
(
void_ptr
!=
nullptr
&&
load_impl
.
loaded_v_h_cpptype
!=
nullptr
&&
!
load_impl
.
reinterpret_cast_deemed_ok
&&
load_impl
.
implicit_cast
!=
nullptr
)
{
void_ptr
=
load_impl
.
implicit_cast
(
void_ptr
);
}
return
static_cast
<
T
*>
(
void_ptr
);
}
};
// SMART_HOLDER_WIP: Needs refactoring of existing pybind11 code.
struct
make_constructor
:
private
type_caster_base
<
int
>
{
// Any type, nothing special about int.
using
type_caster_base
<
int
>::
Constructor
;
using
type_caster_base
<
int
>::
make_copy_constructor
;
using
type_caster_base
<
int
>::
make_move_constructor
;
};
template
<
typename
T
>
struct
smart_holder_type_caster
:
smart_holder_type_caster_load
<
T
>
,
smart_holder_type_caster_class_hooks
{
static
constexpr
auto
name
=
_
<
T
>
();
// static handle cast(T, ...)
// is redundant (leads to ambiguous overloads).
static
handle
cast
(
T
&&
src
,
return_value_policy
/*policy*/
,
handle
parent
)
{
// type_caster_base BEGIN
// clang-format off
return
cast
(
&
src
,
return_value_policy
::
move
,
parent
);
// clang-format on
// type_caster_base END
}
static
handle
cast
(
T
const
&
src
,
return_value_policy
policy
,
handle
parent
)
{
// type_caster_base BEGIN
// clang-format off
if
(
policy
==
return_value_policy
::
automatic
||
policy
==
return_value_policy
::
automatic_reference
)
policy
=
return_value_policy
::
copy
;
return
cast
(
&
src
,
policy
,
parent
);
// clang-format on
// type_caster_base END
}
static
handle
cast
(
T
&
src
,
return_value_policy
policy
,
handle
parent
)
{
return
cast
(
const_cast
<
T
const
&>
(
src
),
policy
,
parent
);
// Mutbl2Const
}
static
handle
cast
(
T
const
*
src
,
return_value_policy
policy
,
handle
parent
)
{
auto
st
=
type_caster_base
<
T
>::
src_and_type
(
src
);
return
cast_const_raw_ptr
(
// Originally type_caster_generic::cast.
st
.
first
,
policy
,
parent
,
st
.
second
,
make_constructor
::
make_copy_constructor
(
src
),
make_constructor
::
make_move_constructor
(
src
));
}
static
handle
cast
(
T
*
src
,
return_value_policy
policy
,
handle
parent
)
{
return
cast
(
const_cast
<
T
const
*>
(
src
),
policy
,
parent
);
// Mutbl2Const
}
#if defined(_MSC_VER) && _MSC_VER < 1910
// Working around MSVC 2015 bug. const-correctness is lost.
// SMART_HOLDER_WIP: IMPROVABLE: make common code work with MSVC 2015.
template
<
typename
T_
>
using
cast_op_type
=
detail
::
cast_op_type
<
T_
>
;
#else
template
<
typename
T_
>
using
cast_op_type
=
conditional_t
<
std
::
is_same
<
remove_reference_t
<
T_
>
,
T
const
*>::
value
,
T
const
*
,
conditional_t
<
std
::
is_same
<
remove_reference_t
<
T_
>
,
T
*>::
value
,
T
*
,
conditional_t
<
std
::
is_same
<
T_
,
T
const
&>::
value
,
T
const
&
,
T
&>>>
;
#endif
// The const operators here prove that the existing type_caster mechanism already supports
// const-correctness. However, fully implementing const-correctness inside this type_caster
// is still a major project.
operator
T
const
&
()
const
{
return
const_cast
<
smart_holder_type_caster
*>
(
this
)
->
loaded_as_lvalue_ref
();
}
operator
T
const
*
()
const
{
return
const_cast
<
smart_holder_type_caster
*>
(
this
)
->
loaded_as_raw_ptr_unowned
();
}
operator
T
&
()
{
return
this
->
loaded_as_lvalue_ref
();
}
operator
T
*
()
{
return
this
->
loaded_as_raw_ptr_unowned
();
}
// Originally type_caster_generic::cast.
PYBIND11_NOINLINE
static
handle
cast_const_raw_ptr
(
const
void
*
_src
,
return_value_policy
policy
,
handle
parent
,
const
detail
::
type_info
*
tinfo
,
void
*
(
*
copy_constructor
)(
const
void
*
),
void
*
(
*
move_constructor
)(
const
void
*
),
const
void
*
existing_holder
=
nullptr
)
{
if
(
!
tinfo
)
// no type info: error will be set already
return
handle
();
void
*
src
=
const_cast
<
void
*>
(
_src
);
if
(
src
==
nullptr
)
return
none
().
release
();
if
(
handle
existing_inst
=
find_registered_python_instance
(
src
,
tinfo
))
return
existing_inst
;
auto
inst
=
reinterpret_steal
<
object
>
(
make_new_instance
(
tinfo
->
type
));
auto
wrapper
=
reinterpret_cast
<
instance
*>
(
inst
.
ptr
());
wrapper
->
owned
=
false
;
void
*&
valueptr
=
values_and_holders
(
wrapper
).
begin
()
->
value_ptr
();
switch
(
policy
)
{
case
return_value_policy
:
:
automatic
:
case
return_value_policy
:
:
take_ownership
:
valueptr
=
src
;
wrapper
->
owned
=
true
;
break
;
case
return_value_policy
:
:
automatic_reference
:
case
return_value_policy
:
:
reference
:
valueptr
=
src
;
wrapper
->
owned
=
false
;
break
;
case
return_value_policy
:
:
copy
:
if
(
copy_constructor
)
valueptr
=
copy_constructor
(
src
);
else
{
#if defined(NDEBUG)
throw
cast_error
(
"return_value_policy = copy, but type is "
"non-copyable! (compile in debug mode for details)"
);
#else
std
::
string
type_name
(
tinfo
->
cpptype
->
name
());
detail
::
clean_type_id
(
type_name
);
throw
cast_error
(
"return_value_policy = copy, but type "
+
type_name
+
" is non-copyable!"
);
#endif
}
wrapper
->
owned
=
true
;
break
;
case
return_value_policy
:
:
move
:
if
(
move_constructor
)
valueptr
=
move_constructor
(
src
);
else
if
(
copy_constructor
)
valueptr
=
copy_constructor
(
src
);
else
{
#if defined(NDEBUG)
throw
cast_error
(
"return_value_policy = move, but type is neither "
"movable nor copyable! "
"(compile in debug mode for details)"
);
#else
std
::
string
type_name
(
tinfo
->
cpptype
->
name
());
detail
::
clean_type_id
(
type_name
);
throw
cast_error
(
"return_value_policy = move, but type "
+
type_name
+
" is neither movable nor copyable!"
);
#endif
}
wrapper
->
owned
=
true
;
break
;
case
return_value_policy
:
:
reference_internal
:
valueptr
=
src
;
wrapper
->
owned
=
false
;
keep_alive_impl
(
inst
,
parent
);
break
;
default
:
throw
cast_error
(
"unhandled return_value_policy: should not happen!"
);
}
tinfo
->
init_instance
(
wrapper
,
existing_holder
);
return
inst
.
release
();
}
};
template
<
typename
T
>
struct
smart_holder_type_caster
<
std
::
shared_ptr
<
T
>>
:
smart_holder_type_caster_load
<
T
>
,
smart_holder_type_caster_class_hooks
{
static
constexpr
auto
name
=
_
<
std
::
shared_ptr
<
T
>>
();
static
handle
cast
(
const
std
::
shared_ptr
<
T
>
&
src
,
return_value_policy
policy
,
handle
parent
)
{
if
(
policy
!=
return_value_policy
::
automatic
&&
policy
!=
return_value_policy
::
reference_internal
)
{
// SMART_HOLDER_WIP: IMPROVABLE: Error message.
throw
cast_error
(
"Invalid return_value_policy for shared_ptr."
);
}
auto
src_raw_ptr
=
src
.
get
();
auto
st
=
type_caster_base
<
T
>::
src_and_type
(
src_raw_ptr
);
if
(
st
.
first
==
nullptr
)
return
none
().
release
();
// PyErr was set already.
void
*
src_raw_void_ptr
=
static_cast
<
void
*>
(
src_raw_ptr
);
const
detail
::
type_info
*
tinfo
=
st
.
second
;
if
(
handle
existing_inst
=
find_registered_python_instance
(
src_raw_void_ptr
,
tinfo
))
// SMART_HOLDER_WIP: MISSING: Enforcement of consistency with existing smart_holder.
// SMART_HOLDER_WIP: MISSING: keep_alive.
return
existing_inst
;
auto
inst
=
reinterpret_steal
<
object
>
(
make_new_instance
(
tinfo
->
type
));
auto
*
inst_raw_ptr
=
reinterpret_cast
<
instance
*>
(
inst
.
ptr
());
inst_raw_ptr
->
owned
=
true
;
void
*&
valueptr
=
values_and_holders
(
inst_raw_ptr
).
begin
()
->
value_ptr
();
valueptr
=
src_raw_void_ptr
;
auto
smhldr
=
pybindit
::
memory
::
smart_holder
::
from_shared_ptr
(
src
);
tinfo
->
init_instance
(
inst_raw_ptr
,
static_cast
<
const
void
*>
(
&
smhldr
));
if
(
policy
==
return_value_policy
::
reference_internal
)
keep_alive_impl
(
inst
,
parent
);
return
inst
.
release
();
}
template
<
typename
>
using
cast_op_type
=
std
::
shared_ptr
<
T
>
;
operator
std
::
shared_ptr
<
T
>
()
{
return
this
->
loaded_as_shared_ptr
();
}
};
template
<
typename
T
>
struct
smart_holder_type_caster
<
std
::
shared_ptr
<
T
const
>>
:
smart_holder_type_caster_load
<
T
>
,
smart_holder_type_caster_class_hooks
{
static
constexpr
auto
name
=
_
<
std
::
shared_ptr
<
T
const
>>
();
static
handle
cast
(
const
std
::
shared_ptr
<
T
const
>
&
src
,
return_value_policy
policy
,
handle
parent
)
{
return
smart_holder_type_caster
<
std
::
shared_ptr
<
T
>>::
cast
(
std
::
const_pointer_cast
<
T
>
(
src
),
// Const2Mutbl
policy
,
parent
);
}
template
<
typename
>
using
cast_op_type
=
std
::
shared_ptr
<
T
const
>
;
operator
std
::
shared_ptr
<
T
const
>
()
{
return
this
->
loaded_as_shared_ptr
();
}
// Mutbl2Const
};
template
<
typename
T
,
typename
D
>
struct
smart_holder_type_caster
<
std
::
unique_ptr
<
T
,
D
>>
:
smart_holder_type_caster_load
<
T
>
,
smart_holder_type_caster_class_hooks
{
static
constexpr
auto
name
=
_
<
std
::
unique_ptr
<
T
,
D
>>
();
static
handle
cast
(
std
::
unique_ptr
<
T
,
D
>
&&
src
,
return_value_policy
policy
,
handle
parent
)
{
if
(
policy
!=
return_value_policy
::
automatic
&&
policy
!=
return_value_policy
::
reference_internal
&&
policy
!=
return_value_policy
::
move
)
{
// SMART_HOLDER_WIP: IMPROVABLE: Error message.
throw
cast_error
(
"Invalid return_value_policy for unique_ptr."
);
}
auto
src_raw_ptr
=
src
.
get
();
auto
st
=
type_caster_base
<
T
>::
src_and_type
(
src_raw_ptr
);
if
(
st
.
first
==
nullptr
)
return
none
().
release
();
// PyErr was set already.
void
*
src_raw_void_ptr
=
static_cast
<
void
*>
(
src_raw_ptr
);
const
detail
::
type_info
*
tinfo
=
st
.
second
;
if
(
find_registered_python_instance
(
src_raw_void_ptr
,
tinfo
))
throw
cast_error
(
"Invalid unique_ptr: another instance owns this pointer already."
);
auto
inst
=
reinterpret_steal
<
object
>
(
make_new_instance
(
tinfo
->
type
));
auto
*
inst_raw_ptr
=
reinterpret_cast
<
instance
*>
(
inst
.
ptr
());
inst_raw_ptr
->
owned
=
true
;
void
*&
valueptr
=
values_and_holders
(
inst_raw_ptr
).
begin
()
->
value_ptr
();
valueptr
=
src_raw_void_ptr
;
auto
smhldr
=
pybindit
::
memory
::
smart_holder
::
from_unique_ptr
(
std
::
move
(
src
));
tinfo
->
init_instance
(
inst_raw_ptr
,
static_cast
<
const
void
*>
(
&
smhldr
));
if
(
policy
==
return_value_policy
::
reference_internal
)
keep_alive_impl
(
inst
,
parent
);
return
inst
.
release
();
}
template
<
typename
>
using
cast_op_type
=
std
::
unique_ptr
<
T
,
D
>
;
operator
std
::
unique_ptr
<
T
,
D
>
()
{
return
this
->
template
loaded_as_unique_ptr
<
D
>
();
}
};
template
<
typename
T
,
typename
D
>
struct
smart_holder_type_caster
<
std
::
unique_ptr
<
T
const
,
D
>>
:
smart_holder_type_caster_load
<
T
>
,
smart_holder_type_caster_class_hooks
{
static
constexpr
auto
name
=
_
<
std
::
unique_ptr
<
T
const
,
D
>>
();
static
handle
cast
(
std
::
unique_ptr
<
T
const
,
D
>
&&
src
,
return_value_policy
policy
,
handle
parent
)
{
return
smart_holder_type_caster
<
std
::
unique_ptr
<
T
,
D
>>::
cast
(
std
::
unique_ptr
<
T
,
D
>
(
const_cast
<
T
*>
(
src
.
release
())),
// Const2Mutbl
policy
,
parent
);
}
template
<
typename
>
using
cast_op_type
=
std
::
unique_ptr
<
T
const
,
D
>
;
operator
std
::
unique_ptr
<
T
const
,
D
>
()
{
return
this
->
template
loaded_as_unique_ptr
<
D
>
();
}
};
#ifndef PYBIND11_USE_SMART_HOLDER_AS_DEFAULT
# define PYBIND11_SMART_HOLDER_TYPE_CASTERS(T) \
namespace pybind11 { \
namespace detail { \
template <> \
class type_caster<T> : public smart_holder_type_caster<T> {}; \
template <> \
class type_caster<std::shared_ptr<T>> \
: public smart_holder_type_caster<std::shared_ptr<T>> {}; \
template <> \
class type_caster<std::shared_ptr<T const>> \
: public smart_holder_type_caster<std::shared_ptr<T const>> {}; \
template <typename D> \
class type_caster<std::unique_ptr<T, D>> \
: public smart_holder_type_caster<std::unique_ptr<T, D>> {}; \
template <typename D> \
class type_caster<std::unique_ptr<T const, D>> \
: public smart_holder_type_caster<std::unique_ptr<T const, D>> {}; \
} \
}
#endif
PYBIND11_NAMESPACE_END
(
detail
)
PYBIND11_NAMESPACE_END
(
PYBIND11_NAMESPACE
)
include/pybind11/pybind11.h
View file @
d3b2d567
// clang-format off
/*
/*
pybind11/pybind11.h: Main header file of the C++11 python
pybind11/pybind11.h: Main header file of the C++11 python
binding generator library
binding generator library
...
@@ -1240,22 +1241,26 @@ auto method_adaptor(Return (Class::*pmf)(Args...) const) -> Return (Derived::*)(
...
@@ -1240,22 +1241,26 @@ auto method_adaptor(Return (Class::*pmf)(Args...) const) -> Return (Derived::*)(
return
pmf
;
return
pmf
;
}
}
// clang-format on
template
<
typename
T
>
template
<
typename
T
>
#ifndef PYBIND11_USE_SMART_HOLDER_AS_DEFAULT
#ifndef PYBIND11_USE_SMART_HOLDER_AS_DEFAULT
using
default_holder_type
=
std
::
unique_ptr
<
T
>
;
using
default_holder_type
=
std
::
unique_ptr
<
T
>
;
#else
#else
using
default_holder_type
=
smart_holder
;
using
default_holder_type
=
smart_holder
;
#endif
#endif
// clang-format off
template
<
typename
type_
,
typename
...
options
>
template
<
typename
type_
,
typename
...
options
>
class
class_
:
public
detail
::
generic_type
{
class
class_
:
public
detail
::
generic_type
{
template
<
typename
T
>
using
is_subtype
=
detail
::
is_strict_base_of
<
type_
,
T
>
;
template
<
typename
T
>
using
is_subtype
=
detail
::
is_strict_base_of
<
type_
,
T
>
;
template
<
typename
T
>
using
is_base
=
detail
::
is_strict_base_of
<
T
,
type_
>
;
template
<
typename
T
>
using
is_base
=
detail
::
is_strict_base_of
<
T
,
type_
>
;
template
<
typename
T
>
template
<
typename
T
>
// clang-format on
using
is_holder
=
detail
::
any_of
<
detail
::
is_holder_type
<
type_
,
T
>
,
using
is_holder
=
detail
::
any_of
<
detail
::
is_holder_type
<
type_
,
T
>
,
detail
::
all_of
<
detail
::
negation
<
is_base
<
T
>>
,
detail
::
all_of
<
detail
::
negation
<
is_base
<
T
>>
,
detail
::
negation
<
is_subtype
<
T
>>
,
detail
::
negation
<
is_subtype
<
T
>>
,
detail
::
is_smart_holder_type_caster
<
type_
>>>
;
detail
::
is_smart_holder_type_caster
<
type_
>>>
;
// clang-format off
// struct instead of using here to help MSVC:
// struct instead of using here to help MSVC:
template
<
typename
T
>
struct
is_valid_class_option
:
template
<
typename
T
>
struct
is_valid_class_option
:
detail
::
any_of
<
is_holder
<
T
>
,
is_subtype
<
T
>
,
is_base
<
T
>>
{};
detail
::
any_of
<
is_holder
<
T
>
,
is_subtype
<
T
>
,
is_base
<
T
>>
{};
...
@@ -1286,16 +1291,22 @@ public:
...
@@ -1286,16 +1291,22 @@ public:
none_of
<
std
::
is_same
<
multiple_inheritance
,
Extra
>
...
>::
value
),
// no multiple_inheritance attr
none_of
<
std
::
is_same
<
multiple_inheritance
,
Extra
>
...
>::
value
),
// no multiple_inheritance attr
"Error: multiple inheritance bases must be specified via class_ template options"
);
"Error: multiple inheritance bases must be specified via class_ template options"
);
static
constexpr
bool
holder_is_smart_holder
=
std
::
is_same
<
holder_type
,
smart_holder
>::
value
;
// clang-format on
static
constexpr
bool
type_caster_type_is_smart_holder_type_caster
=
detail
::
is_smart_holder_type_caster
<
type
>::
value
;
static
constexpr
bool
holder_is_smart_holder
static
constexpr
bool
type_caster_type_is_type_caster_base_subtype
=
std
::
is_base_of
<
detail
::
type_caster_base
<
type
>
,
detail
::
type_caster
<
type
>>::
value
;
=
std
::
is_same
<
holder_type
,
smart_holder
>::
value
;
static
constexpr
bool
type_caster_type_is_smart_holder_type_caster
=
detail
::
is_smart_holder_type_caster
<
type
>::
value
;
static
constexpr
bool
type_caster_type_is_type_caster_base_subtype
=
std
::
is_base_of
<
detail
::
type_caster_base
<
type
>
,
detail
::
type_caster
<
type
>>::
value
;
// Necessary conditions, but not strict.
// Necessary conditions, but not strict.
static_assert
(
!
(
detail
::
is_instantiation
<
std
::
unique_ptr
,
holder_type
>::
value
&&
static_assert
(
type_caster_type_is_smart_holder_type_caster
),
!
(
detail
::
is_instantiation
<
std
::
unique_ptr
,
holder_type
>::
value
&&
type_caster_type_is_smart_holder_type_caster
),
"py::class_ holder vs type_caster mismatch:"
"py::class_ holder vs type_caster mismatch:"
" missing PYBIND11_SMART_POINTER_HOLDER_TYPE_CASTERS(T, std::unique_ptr<T>)?"
);
" missing PYBIND11_SMART_POINTER_HOLDER_TYPE_CASTERS(T, std::unique_ptr<T>)?"
);
static_assert
(
!
(
detail
::
is_instantiation
<
std
::
shared_ptr
,
holder_type
>::
value
&&
static_assert
(
type_caster_type_is_smart_holder_type_caster
),
!
(
detail
::
is_instantiation
<
std
::
shared_ptr
,
holder_type
>::
value
&&
type_caster_type_is_smart_holder_type_caster
),
"py::class_ holder vs type_caster mismatch:"
"py::class_ holder vs type_caster mismatch:"
" missing PYBIND11_SMART_POINTER_HOLDER_TYPE_CASTERS(T, std::shared_ptr<T>)?"
);
" missing PYBIND11_SMART_POINTER_HOLDER_TYPE_CASTERS(T, std::shared_ptr<T>)?"
);
static_assert
(
!
(
holder_is_smart_holder
&&
type_caster_type_is_type_caster_base_subtype
),
static_assert
(
!
(
holder_is_smart_holder
&&
type_caster_type_is_type_caster_base_subtype
),
...
@@ -1312,6 +1323,7 @@ public:
...
@@ -1312,6 +1323,7 @@ public:
" missing PYBIND11_SMART_POINTER_HOLDER_TYPE_CASTERS(T, ...)"
" missing PYBIND11_SMART_POINTER_HOLDER_TYPE_CASTERS(T, ...)"
" or collision with custom py::detail::type_caster<T>?"
);
" or collision with custom py::detail::type_caster<T>?"
);
#endif
#endif
// clang-format off
type_record
record
;
type_record
record
;
record
.
scope
=
scope
;
record
.
scope
=
scope
;
record
.
name
=
name
;
record
.
name
=
name
;
...
@@ -1322,7 +1334,7 @@ public:
...
@@ -1322,7 +1334,7 @@ public:
record
.
init_instance
=
init_instance
;
record
.
init_instance
=
init_instance
;
record
.
dealloc
=
dealloc
;
record
.
dealloc
=
dealloc
;
// A
better
name would be uses_unique_ptr_holder.
// A
more fitting
name would be uses_unique_ptr_holder.
record
.
default_holder
=
detail
::
is_instantiation
<
std
::
unique_ptr
,
holder_type
>::
value
;
record
.
default_holder
=
detail
::
is_instantiation
<
std
::
unique_ptr
,
holder_type
>::
value
;
set_operator_new
<
type
>
(
&
record
);
set_operator_new
<
type
>
(
&
record
);
...
@@ -1541,19 +1553,19 @@ public:
...
@@ -1541,19 +1553,19 @@ public:
}
}
private
:
private
:
template
<
// clang-format on
typename
T
=
type
,
template
<
typename
T
=
type
,
detail
::
enable_if_t
<!
detail
::
is_smart_holder_type_caster
<
T
>::
value
,
int
>
=
0
>
detail
::
enable_if_t
<!
detail
::
is_smart_holder_type_caster
<
T
>::
value
,
int
>
=
0
>
void
generic_type_initialize
(
const
detail
::
type_record
&
record
)
{
void
generic_type_initialize
(
const
detail
::
type_record
&
record
)
{
generic_type
::
initialize
(
record
,
&
detail
::
type_caster_generic
::
local_load
);
generic_type
::
initialize
(
record
,
&
detail
::
type_caster_generic
::
local_load
);
}
}
template
<
template
<
typename
T
=
type
,
typename
T
=
type
,
detail
::
enable_if_t
<
detail
::
is_smart_holder_type_caster
<
T
>::
value
,
int
>
=
0
>
detail
::
enable_if_t
<
detail
::
is_smart_holder_type_caster
<
T
>::
value
,
int
>
=
0
>
void
generic_type_initialize
(
const
detail
::
type_record
&
record
)
{
void
generic_type_initialize
(
const
detail
::
type_record
&
record
)
{
generic_type
::
initialize
(
record
,
detail
::
type_caster
<
T
>::
get_local_load_function_ptr
());
generic_type
::
initialize
(
record
,
detail
::
type_caster
<
T
>::
get_local_load_function_ptr
());
}
}
// clang-format off
/// Initialize holder object, variant 1: object derives from enable_shared_from_this
/// Initialize holder object, variant 1: object derives from enable_shared_from_this
template
<
typename
T
>
template
<
typename
T
>
...
@@ -1611,12 +1623,13 @@ private:
...
@@ -1611,12 +1623,13 @@ private:
init_holder
(
inst
,
v_h
,
(
const
holder_type
*
)
holder_ptr
,
v_h
.
value_ptr
<
type
>
());
init_holder
(
inst
,
v_h
,
(
const
holder_type
*
)
holder_ptr
,
v_h
.
value_ptr
<
type
>
());
}
}
template
<
// clang-format on
typename
T
=
type
,
template
<
typename
T
=
type
,
detail
::
enable_if_t
<
detail
::
is_smart_holder_type_caster
<
T
>::
value
,
int
>
=
0
>
detail
::
enable_if_t
<
detail
::
is_smart_holder_type_caster
<
T
>::
value
,
int
>
=
0
>
static
void
init_instance
(
detail
::
instance
*
inst
,
const
void
*
holder_ptr
)
{
static
void
init_instance
(
detail
::
instance
*
inst
,
const
void
*
holder_ptr
)
{
detail
::
type_caster
<
T
>::
template
init_instance_for_type
<
type
>
(
inst
,
holder_ptr
);
detail
::
type_caster
<
T
>::
template
init_instance_for_type
<
type
>
(
inst
,
holder_ptr
);
}
}
// clang-format off
/// Deallocates an instance; via holder, if constructed; otherwise via operator delete.
/// Deallocates an instance; via holder, if constructed; otherwise via operator delete.
static
void
dealloc
(
detail
::
value_and_holder
&
v_h
)
{
static
void
dealloc
(
detail
::
value_and_holder
&
v_h
)
{
...
...
tests/extra_python_package/test_files.py
View file @
d3b2d567
...
@@ -42,7 +42,9 @@ detail_headers = {
...
@@ -42,7 +42,9 @@ detail_headers = {
"include/pybind11/detail/descr.h"
,
"include/pybind11/detail/descr.h"
,
"include/pybind11/detail/init.h"
,
"include/pybind11/detail/init.h"
,
"include/pybind11/detail/internals.h"
,
"include/pybind11/detail/internals.h"
,
"include/pybind11/detail/smart_holder_init_inline_include.h"
,
"include/pybind11/detail/smart_holder_poc.h"
,
"include/pybind11/detail/smart_holder_poc.h"
,
"include/pybind11/detail/smart_holder_type_casters_inline_include.h"
,
"include/pybind11/detail/typeid.h"
,
"include/pybind11/detail/typeid.h"
,
}
}
...
...
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