Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
P
pybind11_abseil
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_abseil
Commits
28f46a10
Commit
28f46a10
authored
Dec 22, 2021
by
Ken Oslund
Committed by
Copybara-Service
Jan 04, 2022
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Internal change
PiperOrigin-RevId: 417834077
parent
8e9b6c5a
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
335 additions
and
339 deletions
+335
-339
README.md
+56
-59
pybind11_abseil/BUILD
+3
-1
pybind11_abseil/absl_casters.h
+105
-64
pybind11_abseil/absl_numpy_span_caster.h
+1
-90
pybind11_abseil/tests/BUILD
+0
-1
pybind11_abseil/tests/absl_example.cc
+70
-43
pybind11_abseil/tests/absl_test.py
+100
-81
No files found.
README.md
View file @
28f46a10
...
@@ -17,13 +17,6 @@ in the .cc file with your bindings:
...
@@ -17,13 +17,6 @@ in the .cc file with your bindings:
#include "pybind11_abseil/absl_casters.h"
#include "pybind11_abseil/absl_casters.h"
```
```
Support for non-const
`absl::Span`
for numeric types is also available by
including a separated header file:
```
#include "pybind11_abseil/absl_numpy_span_caster.h"
```
## Installation
## Installation
You will need to depend on
`pybind11`
,
`pybind11_bazel`
(see
You will need to depend on
`pybind11`
,
`pybind11_bazel`
(see
...
@@ -96,58 +89,62 @@ less granular C++ types, and time zone information is ignored.
...
@@ -96,58 +89,62 @@ less granular C++ types, and time zone information is ignored.
## absl::Span
## absl::Span
For non-const
`absl::Span`
and conversion from
`numpy`
arrays, see
### Loading
[
non-const absl::Span
](
#non-const-abslspan
)
later.
Some python types can be loaded (Python->C++) without copying or converting the
When
`absl::Span<const T>`
(i.e. the
`const`
version) is considered, there is
list, while some require copying/ converting the list. The non-converting load
full support to mapping into Python sequences.
methods will be tried first, and, if the span elements are const, the converting
Currently, this will always result in the list being copied, so you lose the
load methods will be tried next.
efficiency gains of spans in native C++, but you still get the API versatility.
Arguments cast to a span with
*non-const*
elements can never be copied/converted.
The value type in the span can be any type that pybind knows about. However, it
To prevent an argument cast to a span with
*const*
elements from being copied or
must be immutable (i.e.,
`absl::Span<const ValueType>`
). Theoretically mutable
converted, mark it as
`noconvert()`
(see go/pybind11-non-converting-arguments).
ValueTypes could be supported, but with some subtle limitations, and this is
not needed right now, so the implementation has been deferred.
The following python types can be loaded
*without*
copying or converting:
The
`convert`
and
`return_value_policy`
parameters will apply to the
*elements*
.
-
Numpy array (or anything else that supports
[
buffer protocol
](
The list containing those elements will aways be converted/copied.
https://docs.python.org/3/c-api/buffer.htm
)
) =>
`Span<{const or non-const} T>`
if
*all*
of the following conditions are satisfied:
### non-const absl::Span
-
The buffer is 1-D.
Support for non-cost
`absl::Span`
, for numeric types only, is provided for
-
T is a numeric type.
`numpy`
arrays. Support is only for output function parameters and not for
-
The array dtype matches T exactly.
returned value. The rationale behind this decision is that, if a
`absl::Span`
-
If T is not const, the buffer allows writing.
were to be returned, the C++ object would have needed to outlive the mapped
-
The stride does not indicate to skip elements or go in reverse order.
Python object. Given the complexity of memory management across languages, we
-
[
Opaque
](
go/pybind11-opaque-types
)
`std::vector<T>`
=>
`Span<{const or non-const} T>`
.
did not add support of returned
`absl::Span`
.
-
T can be any type, including converted or pointer types, but must
That is the following is supported:
match exactly between C++ and python.
-
Opaque vectors are
*not*
currently compatible with the smart holder.
```
void Foo(absl::Span<double> some_span);
The following python types must be copied/converted to be loaded:
```
while the following is not (it will generate a compile error):
-
Python sequence of elements that require conversion (numbers, strings,
```
datetimes, etc) =>
`Span<const T>`
.
absl::Span<double> Bar();
-
The elements will be copied/ converted, so that conversion must be legal.
```
-
T
*cannot*
be a pointer.
-
Python sequence of elements that do
*not*
require conversion (ie, classes
Note: It is possible to use the non-const
`absl::Span`
bindings to wrap a
wrapped with py::class_) =>
`Span<const T>`
(elements
*will*
be copied) or
function with
`absl::Span<const T>`
argument if you are using
`numpy`
arrays
`Span<{const or non-const} T* const>`
(elements will
*not*
be copied).
and you do not want a copy to be performed. This can be done by defining a
lambda function in the
`pybind11`
wrapper, as in the following example. See
Specifically, this conversion will
*fail*
if any of the following are true:
b/155596364 for more details.
-
`noconvert()`
was specified (see go/pybind11-non-converting-arguments).
```
-
The element conversion is not allowed (eg, floating point to integer).
void MyConstSpanFunction(absl::Span<const double> a_span);
-
The sequence is being loaded into a
`Span<{non-const} T>`
or
...
`Span<{const or non-const} T* {non-const}>`
.
-
The elements require conversion
*and*
the sequence is being loaded into a
PYBIND11_MODULE(bindings, m) {
`Span<T*>`
(regardless of any
`const`
s; the element caster which owns the
m.def(
converted value would be destroyed before
`load`
is complete, resulting in
"wrap_span",
dangling references).
[](absl::Span<double> span) {
-
The span is nested (ie,
`absl::Span<absl::Span<T>>`
, regardless of any
`const`
s).
MyConstSpanFunction(span);
});
Note: These failure conditions only apply to
*converted*
python types.
}
```
### Casting
Spans are cast (C++->Python) with the standard list caster, which always
converts the list. This could be changed in the future (eg, using
[
buffer protocol
](
https://pybind11.readthedocs.io/en/stable/advanced/pycpp/numpy.html#buffer-protocol
)
)
but generally using spans as return values is not recommended.
## absl::string_view
## absl::string_view
...
...
pybind11_abseil/BUILD
View file @
28f46a10
...
@@ -12,6 +12,7 @@ pybind_library(
...
@@ -12,6 +12,7 @@ pybind_library(
name = "absl_casters",
name = "absl_casters",
hdrs = ["absl_casters.h"],
hdrs = ["absl_casters.h"],
deps = [
deps = [
"@com_google_absl//absl/cleanup",
"@com_google_absl//absl/container:flat_hash_map",
"@com_google_absl//absl/container:flat_hash_map",
"@com_google_absl//absl/container:flat_hash_set",
"@com_google_absl//absl/container:flat_hash_set",
"@com_google_absl//absl/strings",
"@com_google_absl//absl/strings",
...
@@ -24,7 +25,8 @@ pybind_library(
...
@@ -24,7 +25,8 @@ pybind_library(
pybind_library(
pybind_library(
name = "absl_numpy_span_caster",
name = "absl_numpy_span_caster",
hdrs = ["absl_numpy_span_caster.h"],
hdrs = ["absl_numpy_span_caster.h"],
deps = ["@com_google_absl//absl/types:span"],
deprecation = "Please use //pybind11_abseil:absl_casters.",
deps = [":absl_casters"],
)
)
cc_library(
cc_library(
...
...
pybind11_abseil/absl_casters.h
View file @
28f46a10
...
@@ -13,7 +13,8 @@
...
@@ -13,7 +13,8 @@
// - absl::Duration- converted to/from python datetime.timedelta
// - absl::Duration- converted to/from python datetime.timedelta
// - absl::CivilTime- converted to/from python datetime.datetime and from date.
// - absl::CivilTime- converted to/from python datetime.datetime and from date.
// - absl::Time- converted to/from python datetime.datetime and from date.
// - absl::Time- converted to/from python datetime.datetime and from date.
// - absl::Span- const value types only.
// - absl::Span- converted to python sequences and from python buffers,
// opaque std::vectors and/or sequences.
// - absl::string_view
// - absl::string_view
// - absl::optional- converts absl::nullopt to/from python None, otherwise
// - absl::optional- converts absl::nullopt to/from python None, otherwise
// converts the contained value.
// converts the contained value.
...
@@ -33,13 +34,11 @@
...
@@ -33,13 +34,11 @@
#include <cmath>
#include <cmath>
#include <cstdint>
#include <cstdint>
#include <exception>
#include <tuple>
#include <memory>
#include <stdexcept>
#include <type_traits>
#include <type_traits>
#include <typeinfo>
#include <vector>
#include <vector>
#include "absl/cleanup/cleanup.h"
#include "absl/container/flat_hash_map.h"
#include "absl/container/flat_hash_map.h"
#include "absl/container/flat_hash_set.h"
#include "absl/container/flat_hash_set.h"
#include "absl/strings/string_view.h"
#include "absl/strings/string_view.h"
...
@@ -228,56 +227,70 @@ template <>
...
@@ -228,56 +227,70 @@ template <>
struct
type_caster
<
absl
::
CivilYear
>
struct
type_caster
<
absl
::
CivilYear
>
:
public
absl_civil_time_caster
<
absl
::
CivilYear
>
{};
:
public
absl_civil_time_caster
<
absl
::
CivilYear
>
{};
// Convert between absl::Span and python sequence types.
// Returns {true, a span referencing the data contained by src} without copying
//
// or converting the data if possible. Otherwise returns {false, an empty span}.
// TODO(kenoslund): It may be possible to avoid copies in some cases:
template
<
typename
T
,
typename
std
::
enable_if
<
std
::
is_arithmetic
<
T
>::
value
,
// Python to C++: Numpy arrays are contiguous, so we could overlay without copy.
bool
>::
type
=
true
>
// C++ to Python: Python buffer.
std
::
tuple
<
bool
,
absl
::
Span
<
T
>>
LoadSpanFromBuffer
(
handle
src
)
{
// https://pybind11.readthedocs.io/en/stable/advanced/pycpp/numpy.html#buffer-protocol
Py_buffer
view
;
int
flags
=
PyBUF_STRIDES
|
PyBUF_FORMAT
;
if
(
!
std
::
is_const
<
T
>::
value
)
flags
|=
PyBUF_WRITABLE
;
if
(
PyObject_GetBuffer
(
src
.
ptr
(),
&
view
,
flags
)
==
0
)
{
auto
cleanup
=
absl
::
MakeCleanup
([
&
view
]
{
PyBuffer_Release
(
&
view
);
});
if
(
view
.
ndim
==
1
&&
view
.
strides
[
0
]
==
sizeof
(
T
)
&&
view
.
format
[
0
]
==
format_descriptor
<
T
>::
c
)
{
return
{
true
,
absl
::
MakeSpan
(
static_cast
<
T
*>
(
view
.
buf
),
view
.
shape
[
0
])};
}
}
else
{
// Clear the buffer error (failure is reported in the return value).
PyErr_Clear
();
}
return
{
false
,
absl
::
Span
<
T
>
()};
}
// If T is not a numeric type, the buffer interface cannot be used.
template
<
typename
T
,
typename
std
::
enable_if
<!
std
::
is_arithmetic
<
T
>::
value
,
bool
>::
type
=
true
>
constexpr
std
::
tuple
<
bool
,
absl
::
Span
<
T
>>
LoadSpanFromBuffer
(
handle
src
)
{
return
{
false
,
absl
::
Span
<
T
>
()};
}
// Helper to determine whether T is a span.
template
<
typename
T
>
struct
is_absl_span
:
std
::
false_type
{};
template
<
typename
T
>
template
<
typename
T
>
struct
type_caster
<
absl
::
Span
<
const
T
>>
{
struct
is_absl_span
<
absl
::
Span
<
T
>>
:
std
::
true_type
{};
// NOTE: In general, it's *unsafe* to have a pointer type for T. It's
// ok for unmutable sequences of pybind11-wrapped objects.
// Convert between absl::Span and sequence types.
//
// See http://g3doc/pybind11_abseil/README.md#abslspan
// In general if `T` is a pointer or other non-owning reference type, the
template
<
typename
T
>
// resultant `Span` may immediately contain dangling references to temporary
struct
type_caster
<
absl
::
Span
<
T
>>
{
// objects owned by temporary `type_caster<T>` objects, and cannot be used.
public
:
// In particular, passing a list that is mutated before the C++ call
// The type referenced by the span, with const removed.
// returns, or a lazy sequence is unsafe. Use `std::vector<pybind11::object>`
using
value_type
=
typename
std
::
remove_cv
<
T
>::
type
;
// instead and convert the element in C++.
static_assert
(
!
is_absl_span
<
value_type
>::
value
,
//
"Nested absl spans are not supported."
);
// If the Python calling code ensures that the sequence of elements used to
// initialize the Span are kept alive until the pybind11-bound function
type_caster
()
=
default
;
// returns, then the Span can safely be used, e.g. using a tuple or a
// Copy and Move operations must ensure the span points to the copied or
// not-mutated list of pybind11-wrapped objects is ok.
// moved vector (if any), not the original one. Allows implicit conversions.
//
template
<
typename
U
>
// The static_assert below prevents spans of pointers to converted types from
type_caster
(
const
type_caster
<
absl
::
Span
<
U
>>&
other
)
{
// being used, since the caster (which owns the converted value) would be
*
this
=
other
;
// destroyed before the function that uses it executes, resulting in a
}
// dangling reference.
template
<
typename
U
>
static_assert
(
type_caster
(
type_caster
<
absl
::
Span
<
U
>>&&
other
)
{
!
std
::
is_pointer
<
T
>::
value
||
*
this
=
std
::
move
(
other
);
std
::
is_base_of
<
type_caster_base
<
pybind11
::
detail
::
intrinsic_t
<
T
>>
,
}
pybind11
::
detail
::
make_caster
<
T
>>::
value
,
template
<
typename
U
>
"Spans of pointers are not supported for converted types."
);
type_caster
&
operator
=
(
const
type_caster
<
absl
::
Span
<
U
>>&
other
)
{
type_caster
()
:
vector_converter_
(),
value_
(
get_vector
())
{}
list_caster_
=
other
.
list_caster_
;
// Copy and Move constructors need to ensure the span points to the copied
value_
=
list_caster_
?
get_value
(
*
list_caster_
)
:
other
.
value_
;
// or moved vector, not the original one.
type_caster
(
const
type_caster
<
absl
::
Span
<
const
T
>>&
other
)
:
vector_converter_
(
other
.
vector_converter_
),
value_
(
get_vector
())
{}
type_caster
(
type_caster
<
absl
::
Span
<
const
T
>>&&
other
)
:
vector_converter_
(
std
::
move
(
other
.
vector_converter_
)),
value_
(
get_vector
())
{}
type_caster
&
operator
=
(
const
type_caster
<
absl
::
Span
<
const
T
>>&
other
)
{
vector_converter_
=
other
.
vector_converter_
;
value_
=
get_vector
();
return
*
this
;
return
*
this
;
}
}
template
<
typename
U
>
type_caster
&
operator
=
(
type_caster
<
absl
::
Span
<
const
T
>>&&
other
)
{
type_caster
&
operator
=
(
type_caster
<
absl
::
Span
<
U
>>&&
other
)
{
vector_converter_
=
std
::
move
(
other
.
vector_conver
ter_
);
list_caster_
=
std
::
move
(
other
.
list_cas
ter_
);
value_
=
get_vector
()
;
value_
=
list_caster_
?
get_value
(
*
list_caster_
)
:
other
.
value_
;
return
*
this
;
return
*
this
;
}
}
...
@@ -287,30 +300,58 @@ struct type_caster<absl::Span<const T>> {
...
@@ -287,30 +300,58 @@ struct type_caster<absl::Span<const T>> {
// no advantage to moving and 2) the span cannot exist without the caster,
// no advantage to moving and 2) the span cannot exist without the caster,
// so moving leaves an implicit dependency (while a reference or pointer
// so moving leaves an implicit dependency (while a reference or pointer
// make that dependency explicit).
// make that dependency explicit).
operator
absl
::
Span
<
const
T
>*
()
{
return
&
value_
;
}
operator
absl
::
Span
<
T
>*
()
{
return
&
value_
;
}
operator
absl
::
Span
<
const
T
>&
()
{
return
value_
;
}
operator
absl
::
Span
<
T
>&
()
{
return
value_
;
}
template
<
typename
T_
>
template
<
typename
T_
>
using
cast_op_type
=
cast_op_type
<
T_
>
;
using
cast_op_type
=
cast_op_type
<
T_
>
;
bool
load
(
handle
src
,
bool
convert
)
{
bool
load
(
handle
src
,
bool
convert
)
{
if
(
!
vector_converter_
.
load
(
src
,
convert
))
return
false
;
// Attempt to reference a buffer, including np.ndarray and array.arrays.
// std::vector implicitly converted to absl::Span.
bool
loaded
;
value_
=
get_vector
();
std
::
tie
(
loaded
,
value_
)
=
LoadSpanFromBuffer
<
T
>
(
src
);
return
true
;
if
(
loaded
)
return
true
;
// Attempt to unwrap an opaque std::vector.
type_caster_base
<
std
::
vector
<
value_type
>>
caster
;
if
(
caster
.
load
(
src
,
false
))
{
value_
=
get_value
(
caster
);
return
true
;
}
// Attempt to convert a native sequence. If the is_base_of_v check passes,
// the elements do not require converting and pointers do not reference a
// temporary object owned by the element caster. Pointers to converted
// types are not allowed because they would result a dangling reference
// when the element caster is destroyed. TODO(b/169068487): improve this.
if
(
convert
&&
std
::
is_const
<
T
>::
value
&&
(
!
std
::
is_pointer
<
T
>::
value
||
std
::
is_base_of
<
type_caster_generic
,
make_caster
<
T
>>::
value
))
{
list_caster_
.
emplace
();
if
(
list_caster_
->
load
(
src
,
convert
))
{
value_
=
get_value
(
*
list_caster_
);
return
true
;
}
else
{
list_caster_
.
reset
();
}
}
return
false
;
// Python type cannot be loaded into a span.
}
}
template
<
typename
CType
>
template
<
typename
CType
>
static
handle
cast
(
CType
&&
src
,
return_value_policy
policy
,
handle
parent
)
{
static
handle
cast
(
CType
&&
src
,
return_value_policy
policy
,
handle
parent
)
{
return
VectorConver
ter
::
cast
(
src
,
policy
,
parent
);
return
ListCas
ter
::
cast
(
src
,
policy
,
parent
);
}
}
private
:
private
:
std
::
vector
<
T
>&
get_vector
()
{
template
<
typename
Caster
>
return
static_cast
<
std
::
vector
<
T
>&>
(
vector_converter_
);
absl
::
Span
<
T
>
get_value
(
Caster
&
caster
)
{
return
absl
::
MakeSpan
(
static_cast
<
std
::
vector
<
value_type
>&>
(
caster
));
}
}
using
VectorConverter
=
make_caster
<
std
::
vector
<
T
>>
;
VectorConverter
vector_converter_
;
using
ListCaster
=
list_caster
<
std
::
vector
<
value_type
>
,
value_type
>
;
absl
::
Span
<
const
T
>
value_
;
absl
::
optional
<
ListCaster
>
list_caster_
;
absl
::
Span
<
T
>
value_
;
};
};
// Convert between absl::flat_hash_map and python dict.
// Convert between absl::flat_hash_map and python dict.
...
...
pybind11_abseil/absl_numpy_span_caster.h
View file @
28f46a10
#ifndef PYBIND11_ABSEIL_ABSL_NUMPY_SPAN_CASTER_H_
#ifndef PYBIND11_ABSEIL_ABSL_NUMPY_SPAN_CASTER_H_
#define PYBIND11_ABSEIL_ABSL_NUMPY_SPAN_CASTER_H_
#define PYBIND11_ABSEIL_ABSL_NUMPY_SPAN_CASTER_H_
#include <type_traits>
#include "pybind11_abseil/absl_casters.h"
#include "absl/types/span.h"
#include "pybind11/cast.h"
#include "pybind11/numpy.h"
// Support for conversion from NumPy array to template specializations of
// absl::Span. Note that no data is copied, the `Span`ned memory is owned by the
// NumPy array.
//
// Only one direction of conversion is provided: a Span argument can be exposed
// to Python as a NumPy array argument. No conversion is provided for a Span
// return value.
//
// Lifetime management will become complicated if a `Span` returned by a C++
// object is converted into a NumPy array which outlives the C++ object. Such
// memory management concerns are normal for C++ but undesirable to introduce to
// Python.
//
// A `Span` argument can be used to expose an output argument to Python so that
// Python is wholly responsible for memory management of the output object.
// Using an output argument rather than a return value means that memory can be
// reused.
//
// C++:
// Simulation::Simulation(int buffer_size);
// void Simulation::RenderFrame(int frame_index, Span<uint8> buffer);
//
// Python:
// buffer = np.zeroes(1024*768, dtype='uint8')
// simulation = Simulation(1024*768)
// simulation.renderFrame(0, buffer)
// # RGB data can now be read from the buffer.
namespace
pybind11
::
detail
{
// Conversion of non-const Span.
// Note that there are two template specialisations for `absl::Span`: the one in
// this file and the one for `const T` in `absl_caster.h`.
// The use of `std::enable_if_t`, and in particular of the `std::is_const_v`
// condition check, is really important and prevents unpleasant ODR (one
// definition rule) violations when linking together different object files with
// different includes.
// TODO(b/155596364) merge this implementation with the absl::Span<const T>
// caster.
template
<
typename
T
>
class
type_caster
<
absl
::
Span
<
T
>
,
// C++11 compatibility.
typename
std
::
enable_if
<
std
::
is_arithmetic
<
T
>::
value
&&
!
std
::
is_const
<
T
>::
value
>::
type
>
{
public
:
// Instead of using the macro PYBIND11_TYPE_CASTER we explicitly define value
// and functions. This is because, the macro has default implementations for
// move constructors and cast method.
// Note: we also disable the linter on these methods and variables.
static
constexpr
auto
name
=
// NOLINT
_
(
"Span["
)
+
make_caster
<
T
>::
name
+
_
(
"]"
);
// We do not allow moving because 1) spans are super lightweight, so there is
// no advantage to moving and 2) the span cannot exist without the caster,
// so moving leaves an implicit dependency (while a reference or pointer
// make that dependency explicit).
operator
absl
::
Span
<
T
>*
()
{
// NOLINT(google-explicit-constructor)
return
&
value_
;
}
operator
absl
::
Span
<
T
>&
()
{
// NOLINT(google-explicit-constructor)
return
value_
;
}
template
<
typename
T_
>
using
cast_op_type
=
cast_op_type
<
T_
>
;
// Conversion Python->C++: convert a NumPy array into a Span.
bool
load
(
handle
src
,
bool
/* convert */
)
{
// Extract PyObject from handle.
if
(
!
pybind11
::
isinstance
<
pybind11
::
array_t
<
T
>>
(
src
))
{
return
false
;
}
auto
array
=
src
.
cast
<
pybind11
::
array_t
<
T
>>
();
if
(
!
array
||
array
.
ndim
()
!=
1
||
array
.
strides
()[
0
]
!=
sizeof
(
T
)
||
!
array
.
writeable
())
{
return
false
;
}
value_
=
absl
::
Span
<
T
>
(
static_cast
<
T
*>
(
array
.
mutable_data
()),
array
.
size
());
return
true
;
}
protected
:
absl
::
Span
<
T
>
value_
;
};
}
// namespace pybind11::detail
#endif // PYBIND11_ABSEIL_ABSL_NUMPY_SPAN_CASTER_H_
#endif // PYBIND11_ABSEIL_ABSL_NUMPY_SPAN_CASTER_H_
pybind11_abseil/tests/BUILD
View file @
28f46a10
...
@@ -10,7 +10,6 @@ pybind_extension(
...
@@ -10,7 +10,6 @@ pybind_extension(
srcs = ["absl_example.cc"],
srcs = ["absl_example.cc"],
deps = [
deps = [
"//pybind11_abseil:absl_casters",
"//pybind11_abseil:absl_casters",
"//pybind11_abseil:absl_numpy_span_caster",
"@com_google_absl//absl/container:flat_hash_set",
"@com_google_absl//absl/container:flat_hash_set",
"@com_google_absl//absl/strings",
"@com_google_absl//absl/strings",
"@com_google_absl//absl/time",
"@com_google_absl//absl/time",
...
...
pybind11_abseil/tests/absl_example.cc
View file @
28f46a10
...
@@ -4,7 +4,10 @@
...
@@ -4,7 +4,10 @@
// BSD-style license that can be found in the LICENSE file.
// BSD-style license that can be found in the LICENSE file.
#include <pybind11/pybind11.h>
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/stl_bind.h>
#include <cstddef>
#include <vector>
#include <vector>
#include "absl/container/flat_hash_set.h"
#include "absl/container/flat_hash_set.h"
...
@@ -15,7 +18,6 @@
...
@@ -15,7 +18,6 @@
#include "absl/types/optional.h"
#include "absl/types/optional.h"
#include "absl/types/span.h"
#include "absl/types/span.h"
#include "pybind11_abseil/absl_casters.h"
#include "pybind11_abseil/absl_casters.h"
#include "pybind11_abseil/absl_numpy_span_caster.h"
namespace
pybind11
{
namespace
pybind11
{
namespace
test
{
namespace
test
{
...
@@ -35,21 +37,6 @@ bool CheckDatetime(const absl::Time& datetime, double secs) {
...
@@ -35,21 +37,6 @@ bool CheckDatetime(const absl::Time& datetime, double secs) {
return
datetime
==
MakeTime
(
secs
);
return
datetime
==
MakeTime
(
secs
);
}
}
bool
CheckSpan
(
absl
::
Span
<
const
int
>
span
,
const
std
::
vector
<
int
>&
values
)
{
if
(
span
.
size
()
!=
values
.
size
())
return
false
;
for
(
int
i
=
0
;
i
<
span
.
size
();
++
i
)
{
if
(
span
[
i
]
!=
values
[
i
])
return
false
;
}
return
true
;
}
bool
CheckSpanCasterCopy
(
const
handle
&
span
,
const
std
::
vector
<
int
>&
values
)
{
pybind11
::
detail
::
make_caster
<
absl
::
Span
<
const
int
>>
caster
;
caster
=
pybind11
::
detail
::
load_type
<
absl
::
Span
<
const
int
>>
(
span
);
return
CheckSpan
(
pybind11
::
detail
::
cast_op
<
absl
::
Span
<
const
int
>>
(
caster
),
values
);
}
absl
::
CivilSecond
MakeCivilSecond
(
double
secs
)
{
absl
::
CivilSecond
MakeCivilSecond
(
double
secs
)
{
return
absl
::
ToCivilSecond
(
absl
::
FromUnixSeconds
(
static_cast
<
int64_t
>
(
secs
)),
return
absl
::
ToCivilSecond
(
absl
::
FromUnixSeconds
(
static_cast
<
int64_t
>
(
secs
)),
absl
::
UTCTimeZone
());
absl
::
UTCTimeZone
());
...
@@ -176,12 +163,24 @@ bool CheckSet(const absl::flat_hash_set<int>& set,
...
@@ -176,12 +163,24 @@ bool CheckSet(const absl::flat_hash_set<int>& set,
return
set
==
check
;
return
set
==
check
;
}
}
//
Non-const Span.
//
Span
template
<
typename
T
>
bool
CheckSpan
(
absl
::
Span
<
const
int
>
span
,
const
std
::
vector
<
int
>&
values
)
{
void
FillNonConstSpan
(
T
value
,
absl
::
Span
<
T
>
output_span
)
{
if
(
span
.
size
()
!=
values
.
size
())
return
false
;
for
(
auto
&
i
:
output_span
)
{
for
(
size_t
i
=
0
;
i
<
span
.
size
();
++
i
)
{
i
=
valu
e
;
i
f
(
span
[
i
]
!=
values
[
i
])
return
fals
e
;
}
}
return
true
;
}
bool
CheckSpanCasterCopy
(
const
handle
&
span
,
const
std
::
vector
<
int
>&
values
)
{
pybind11
::
detail
::
make_caster
<
absl
::
Span
<
const
int
>>
caster
;
caster
=
pybind11
::
detail
::
load_type
<
absl
::
Span
<
const
int
>>
(
span
);
return
CheckSpan
(
pybind11
::
detail
::
cast_op
<
absl
::
Span
<
const
int
>>
(
caster
),
values
);
}
void
FillSpan
(
int
value
,
absl
::
Span
<
int
>
output_span
)
{
for
(
auto
&
i
:
output_span
)
i
=
value
;
}
}
struct
ObjectForSpan
{
struct
ObjectForSpan
{
...
@@ -189,18 +188,25 @@ struct ObjectForSpan {
...
@@ -189,18 +188,25 @@ struct ObjectForSpan {
int
value
;
int
value
;
};
};
int
SumObjectPointersSpan
(
absl
::
Span
<
ObjectForSpan
*
const
>
inputs
)
{
void
FillObjectPointersSpan
(
int
value
,
absl
::
Span
<
ObjectForSpan
*
const
>
output_span
)
{
for
(
ObjectForSpan
*
item
:
output_span
)
item
->
value
=
value
;
}
void
FillObjectSpan
(
int
value
,
absl
::
Span
<
ObjectForSpan
>
output_span
)
{
for
(
auto
&
item
:
output_span
)
item
.
value
=
value
;
}
int
SumObjectPointersSpan
(
absl
::
Span
<
const
ObjectForSpan
*
const
>
span
)
{
int
result
=
0
;
int
result
=
0
;
for
(
ObjectForSpan
*
item
:
inputs
)
{
for
(
const
ObjectForSpan
*
item
:
span
)
result
+=
item
->
value
;
result
+=
item
->
value
;
}
return
result
;
return
result
;
}
}
template
<
typename
T
>
int
SumObjectSpan
(
absl
::
Span
<
const
ObjectForSpan
>
span
)
{
void
DefineNonConstSpan
(
module
*
py_m
,
absl
::
string_view
type_name
)
{
int
result
=
0
;
py_m
->
def
(
absl
::
StrCat
(
"fill_non_const_span_"
,
type_name
).
c_str
(),
for
(
auto
&
item
:
span
)
result
+=
item
.
value
;
&
FillNonConstSpan
<
T
>
,
arg
(
"value"
),
arg
(
"output_span"
).
noconvert
())
;
return
result
;
}
}
// absl::variant
// absl::variant
...
@@ -230,6 +236,24 @@ std::vector<absl::variant<A*, B*>> Identity(
...
@@ -230,6 +236,24 @@ std::vector<absl::variant<A*, B*>> Identity(
return
value
;
return
value
;
}
}
}
// namespace test
}
// namespace pybind11
PYBIND11_MAKE_OPAQUE
(
std
::
vector
<
pybind11
::
test
::
ObjectForSpan
>
);
namespace
pybind11
{
namespace
test
{
// Demonstration of constness check for span template parameters.
static_assert
(
std
::
is_const
<
const
int
>::
value
);
static_assert
(
std
::
is_const
<
int
*
const
>::
value
);
// pointer is const, int is not.
static_assert
(
std
::
is_const
<
const
int
*
const
>::
value
);
static_assert
(
!
std
::
is_const
<
int
>::
value
);
static_assert
(
!
std
::
is_const
<
int
*>::
value
);
static_assert
(
!
std
::
is_const
<
const
int
*>::
value
);
// int is const, pointer is not.
PYBIND11_MODULE
(
absl_example
,
m
)
{
PYBIND11_MODULE
(
absl_example
,
m
)
{
// absl::Time/Duration bindings.
// absl::Time/Duration bindings.
m
.
def
(
"make_duration"
,
&
MakeDuration
,
arg
(
"secs"
));
m
.
def
(
"make_duration"
,
&
MakeDuration
,
arg
(
"secs"
));
...
@@ -253,25 +277,28 @@ PYBIND11_MODULE(absl_example, m) {
...
@@ -253,25 +277,28 @@ PYBIND11_MODULE(absl_example, m) {
// absl::Span bindings.
// absl::Span bindings.
m
.
def
(
"check_span"
,
&
CheckSpan
,
arg
(
"span"
),
arg
(
"values"
));
m
.
def
(
"check_span"
,
&
CheckSpan
,
arg
(
"span"
),
arg
(
"values"
));
m
.
def
(
"check_span_no_convert"
,
&
CheckSpan
,
arg
(
"span"
).
noconvert
(),
arg
(
"values"
));
m
.
def
(
"check_span_caster_copy"
,
&
CheckSpanCasterCopy
,
arg
(
"span"
),
m
.
def
(
"check_span_caster_copy"
,
&
CheckSpanCasterCopy
,
arg
(
"span"
),
arg
(
"values"
));
arg
(
"values"
));
class_
<
VectorContainer
>
(
m
,
"VectorContainer"
)
class_
<
VectorContainer
>
(
m
,
"VectorContainer"
)
.
def
(
init
())
.
def
(
init
())
.
def
(
"make_span"
,
&
VectorContainer
::
MakeSpan
,
arg
(
"values"
));
.
def
(
"make_span"
,
&
VectorContainer
::
MakeSpan
,
arg
(
"values"
));
// Non-const spans can never be converted, so `output_span` could be marked as
// non-const absl::Span bindings.
// `noconvert`, but that would be redundant (so test that it is not needed).
DefineNonConstSpan
<
double
>
(
&
m
,
"double"
);
m
.
def
(
"fill_span"
,
&
FillSpan
,
arg
(
"value"
),
arg
(
"output_span"
));
DefineNonConstSpan
<
int
>
(
&
m
,
"int"
);
// Wrap a const Span with a non-const Span lambda to avoid copying data.
// Span of objects.
m
.
def
(
class_
<
ObjectForSpan
>
(
m
,
"ObjectForSpan"
)
"check_span_no_copy"
,
.
def
(
init
<
int
>
())
[](
absl
::
Span
<
int
>
span
,
const
std
::
vector
<
int
>&
values
)
->
bool
{
.
def_readwrite
(
"value"
,
&
ObjectForSpan
::
value
);
return
CheckSpan
(
span
,
values
);
bind_vector
<
std
::
vector
<
ObjectForSpan
>>
(
m
,
"ObjectVector"
);
},
m
.
def
(
"sum_object_pointers_span"
,
&
SumObjectPointersSpan
,
arg
(
"span"
));
arg
(
"span"
),
arg
(
"values"
));
m
.
def
(
"sum_object_span"
,
&
SumObjectSpan
,
arg
(
"span"
));
m
.
def
(
"sum_object_span_no_convert"
,
&
SumObjectSpan
,
arg
(
"span"
).
noconvert
());
class_
<
ObjectForSpan
>
(
m
,
"ObjectForSpan"
).
def
(
init
<
int
>
());
m
.
def
(
"fill_object_pointers_span"
,
&
FillObjectPointersSpan
,
arg
(
"value"
),
m
.
def
(
"SumObjectPointersSpan"
,
&
SumObjectPointersSpan
);
arg
(
"output_span"
));
m
.
def
(
"fill_object_span"
,
&
FillObjectSpan
,
arg
(
"value"
),
arg
(
"output_span"
));
// absl::string_view bindings.
// absl::string_view bindings.
m
.
def
(
"check_string_view"
,
&
CheckStringView
,
arg
(
"view"
),
arg
(
"values"
));
m
.
def
(
"check_string_view"
,
&
CheckStringView
,
arg
(
"view"
),
arg
(
"values"
));
...
...
pybind11_abseil/tests/absl_test.py
View file @
28f46a10
This diff is collapsed.
Click to expand it.
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