Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
gaoqiong
pybind11
Commits
f42af24a
Commit
f42af24a
authored
Jun 18, 2017
by
Jason Rhinelander
Browse files
Support std::string_view when compiled under C++17
parent
220a77f5
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
106 additions
and
7 deletions
+106
-7
docs/advanced/cast/overview.rst
docs/advanced/cast/overview.rst
+3
-0
docs/advanced/cast/strings.rst
docs/advanced/cast/strings.rst
+9
-0
include/pybind11/cast.h
include/pybind11/cast.h
+35
-6
tests/test_python_types.cpp
tests/test_python_types.cpp
+15
-0
tests/test_python_types.py
tests/test_python_types.py
+44
-1
No files found.
docs/advanced/cast/overview.rst
View file @
f42af24a
...
...
@@ -116,6 +116,9 @@ as arguments and return values, refer to the section on binding :ref:`classes`.
+------------------------------------+---------------------------+-------------------------------+
| ``std::wstring`` | STL dynamic wide string | :file:`pybind11/pybind11.h` |
+------------------------------------+---------------------------+-------------------------------+
| ``std::string_view``, | STL C++17 string views | :file:`pybind11/pybind11.h` |
| ``std::u16string_view``, etc. | | |
+------------------------------------+---------------------------+-------------------------------+
| ``std::pair<T1, T2>`` | Pair of two custom types | :file:`pybind11/pybind11.h` |
+------------------------------------+---------------------------+-------------------------------+
| ``std::tuple<...>`` | Arbitrary tuple of types | :file:`pybind11/pybind11.h` |
...
...
docs/advanced/cast/strings.rst
View file @
f42af24a
...
...
@@ -287,6 +287,15 @@ expressed as a single Unicode code point
no way to capture them in a C++ character type.
C++17 string views
==================
C++17 string views are automatically supported when compiling in C++17 mode.
They follow the same rules for encoding and decoding as the corresponding STL
string type (for example, a ``std::u16string_view`` argument will be passed
UTF-16-encoded data, and a returned ``std::string_view`` will be decoded as
UTF-8).
References
==========
...
...
include/pybind11/cast.h
View file @
f42af24a
...
...
@@ -18,6 +18,19 @@
#include <tuple>
#include <cstring>
#if defined(PYBIND11_CPP17)
# if defined(__has_include)
# if __has_include(<string_view>)
# define PYBIND11_HAS_STRING_VIEW
# endif
# elif defined(_MSC_VER)
# define PYBIND11_HAS_STRING_VIEW
# endif
#endif
#ifdef PYBIND11_HAS_STRING_VIEW
#include <string_view>
#endif
NAMESPACE_BEGIN
(
pybind11
)
NAMESPACE_BEGIN
(
detail
)
// Forward declarations:
...
...
@@ -1003,10 +1016,11 @@ public:
};
// Helper class for UTF-{8,16,32} C++ stl strings:
template
<
typename
CharT
,
class
Traits
,
class
Allocator
>
struct
type_caster
<
std
::
basic_string
<
CharT
,
Traits
,
Allocator
>
,
enable_if_t
<
is_std_char_type
<
CharT
>::
value
>>
{
template
<
typename
StringType
,
bool
IsView
=
false
>
struct
string_caster
{
using
CharT
=
typename
StringType
::
value_type
;
// Simplify life by being able to assume standard char sizes (the standard only guarantees
// minimums
)
, but Python requires exact sizes
// minimums, but Python requires exact sizes
)
static_assert
(
!
std
::
is_same
<
CharT
,
char
>::
value
||
sizeof
(
CharT
)
==
1
,
"Unsupported char size != 1"
);
static_assert
(
!
std
::
is_same
<
CharT
,
char16_t
>::
value
||
sizeof
(
CharT
)
==
2
,
"Unsupported char16_t size != 2"
);
static_assert
(
!
std
::
is_same
<
CharT
,
char32_t
>::
value
||
sizeof
(
CharT
)
==
4
,
"Unsupported char32_t size != 4"
);
...
...
@@ -1015,8 +1029,6 @@ struct type_caster<std::basic_string<CharT, Traits, Allocator>, enable_if_t<is_s
"Unsupported wchar_t size != 2/4"
);
static
constexpr
size_t
UTF_N
=
8
*
sizeof
(
CharT
);
using
StringType
=
std
::
basic_string
<
CharT
,
Traits
,
Allocator
>
;
bool
load
(
handle
src
,
bool
)
{
#if PY_MAJOR_VERSION < 3
object
temp
;
...
...
@@ -1050,11 +1062,16 @@ struct type_caster<std::basic_string<CharT, Traits, Allocator>, enable_if_t<is_s
size_t
length
=
(
size_t
)
PYBIND11_BYTES_SIZE
(
utfNbytes
.
ptr
())
/
sizeof
(
CharT
);
if
(
UTF_N
>
8
)
{
buffer
++
;
length
--
;
}
// Skip BOM for UTF-16/32
value
=
StringType
(
buffer
,
length
);
// If we're loading a string_view we need to keep the encoded Python object alive:
if
(
IsView
)
view_into
=
std
::
move
(
utfNbytes
);
return
true
;
}
static
handle
cast
(
const
StringType
&
src
,
return_value_policy
/* policy */
,
handle
/* parent */
)
{
const
char
*
buffer
=
reinterpret_cast
<
const
char
*>
(
src
.
c_str
());
const
char
*
buffer
=
reinterpret_cast
<
const
char
*>
(
src
.
data
());
ssize_t
nbytes
=
ssize_t
(
src
.
size
()
*
sizeof
(
CharT
));
handle
s
=
decode_utfN
(
buffer
,
nbytes
);
if
(
!
s
)
throw
error_already_set
();
...
...
@@ -1064,6 +1081,8 @@ struct type_caster<std::basic_string<CharT, Traits, Allocator>, enable_if_t<is_s
PYBIND11_TYPE_CASTER
(
StringType
,
_
(
PYBIND11_STRING_NAME
));
private:
object
view_into
;
static
handle
decode_utfN
(
const
char
*
buffer
,
ssize_t
nbytes
)
{
#if !defined(PYPY_VERSION)
return
...
...
@@ -1101,6 +1120,16 @@ private:
bool
load_bytes
(
enable_if_t
<
sizeof
(
C
)
!=
1
,
handle
>
)
{
return
false
;
}
};
template
<
typename
CharT
,
class
Traits
,
class
Allocator
>
struct
type_caster
<
std
::
basic_string
<
CharT
,
Traits
,
Allocator
>
,
enable_if_t
<
is_std_char_type
<
CharT
>::
value
>>
:
string_caster
<
std
::
basic_string
<
CharT
,
Traits
,
Allocator
>>
{};
#ifdef PYBIND11_HAS_STRING_VIEW
template
<
typename
CharT
,
class
Traits
>
struct
type_caster
<
std
::
basic_string_view
<
CharT
,
Traits
>
,
enable_if_t
<
is_std_char_type
<
CharT
>::
value
>>
:
string_caster
<
std
::
basic_string_view
<
CharT
,
Traits
>
,
true
>
{};
#endif
// Type caster for C-style strings. We basically use a std::string type caster, but also add the
// ability to use None as a nullptr char* (which the string caster doesn't allow).
template
<
typename
CharT
>
struct
type_caster
<
CharT
,
enable_if_t
<
is_std_char_type
<
CharT
>::
value
>>
{
...
...
tests/test_python_types.cpp
View file @
f42af24a
...
...
@@ -555,6 +555,21 @@ test_initializer python_types([](py::module &m) {
m
.
def
(
"nodefer_none_optional"
,
[](
py
::
none
)
{
return
false
;
});
#endif
#ifdef PYBIND11_HAS_STRING_VIEW
m
.
attr
(
"has_string_view"
)
=
true
;
m
.
def
(
"string_view_print"
,
[](
std
::
string_view
s
)
{
py
::
print
(
s
,
s
.
size
());
});
m
.
def
(
"string_view16_print"
,
[](
std
::
u16string_view
s
)
{
py
::
print
(
s
,
s
.
size
());
});
m
.
def
(
"string_view32_print"
,
[](
std
::
u32string_view
s
)
{
py
::
print
(
s
,
s
.
size
());
});
m
.
def
(
"string_view_chars"
,
[](
std
::
string_view
s
)
{
py
::
list
l
;
for
(
auto
c
:
s
)
l
.
append
((
std
::
uint8_t
)
c
);
return
l
;
});
m
.
def
(
"string_view16_chars"
,
[](
std
::
u16string_view
s
)
{
py
::
list
l
;
for
(
auto
c
:
s
)
l
.
append
((
int
)
c
);
return
l
;
});
m
.
def
(
"string_view32_chars"
,
[](
std
::
u32string_view
s
)
{
py
::
list
l
;
for
(
auto
c
:
s
)
l
.
append
((
int
)
c
);
return
l
;
});
m
.
def
(
"string_view_return"
,
[]()
{
return
std
::
string_view
(
u8"utf8 secret \U0001f382"
);
});
m
.
def
(
"string_view16_return"
,
[]()
{
return
std
::
u16string_view
(
u"utf16 secret \U0001f382"
);
});
m
.
def
(
"string_view32_return"
,
[]()
{
return
std
::
u32string_view
(
U"utf32 secret \U0001f382"
);
});
#else
m
.
attr
(
"has_string_view"
)
=
false
;
#endif
m
.
def
(
"return_capsule_with_destructor"
,
[]()
{
py
::
print
(
"creating capsule"
);
...
...
tests/test_python_types.py
View file @
f42af24a
...
...
@@ -2,7 +2,8 @@
import
pytest
import
pybind11_tests
from
pybind11_tests
import
ExamplePythonTypes
,
ConstructorStats
,
has_optional
,
has_exp_optional
from
pybind11_tests
import
(
ExamplePythonTypes
,
ConstructorStats
,
has_optional
,
has_exp_optional
,
has_string_view
)
def
test_repr
():
...
...
@@ -558,6 +559,48 @@ def test_bytes_to_string():
assert
string_length
(
u
'💩'
.
encode
(
"utf8"
))
==
4
@
pytest
.
mark
.
skipif
(
not
has_string_view
,
reason
=
'no <string_view>'
)
def
test_string_view
(
capture
):
"""Tests support for C++17 string_view arguments and return values"""
from
pybind11_tests
import
(
string_view_print
,
string_view16_print
,
string_view32_print
,
string_view_chars
,
string_view16_chars
,
string_view32_chars
,
string_view_return
,
string_view16_return
,
string_view32_return
)
assert
string_view_chars
(
"Hi"
)
==
[
72
,
105
]
assert
string_view_chars
(
"Hi 🎂"
)
==
[
72
,
105
,
32
,
0xf0
,
0x9f
,
0x8e
,
0x82
]
assert
string_view16_chars
(
"Hi 🎂"
)
==
[
72
,
105
,
32
,
0xd83c
,
0xdf82
]
assert
string_view32_chars
(
"Hi 🎂"
)
==
[
72
,
105
,
32
,
127874
]
assert
string_view_return
()
==
"utf8 secret 🎂"
assert
string_view16_return
()
==
"utf16 secret 🎂"
assert
string_view32_return
()
==
"utf32 secret 🎂"
with
capture
:
string_view_print
(
"Hi"
)
string_view_print
(
"utf8 🎂"
)
string_view16_print
(
"utf16 🎂"
)
string_view32_print
(
"utf32 🎂"
)
assert
capture
==
"""
Hi 2
utf8 🎂 9
utf16 🎂 8
utf32 🎂 7
"""
with
capture
:
string_view_print
(
"Hi, ascii"
)
string_view_print
(
"Hi, utf8 🎂"
)
string_view16_print
(
"Hi, utf16 🎂"
)
string_view32_print
(
"Hi, utf32 🎂"
)
assert
capture
==
"""
Hi, ascii 9
Hi, utf8 🎂 13
Hi, utf16 🎂 12
Hi, utf32 🎂 11
"""
def
test_builtins_cast_return_none
():
"""Casters produced with PYBIND11_TYPE_CASTER() should convert nullptr to None"""
import
pybind11_tests
as
m
...
...
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