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
f42af24a
Commit
f42af24a
authored
Jun 18, 2017
by
Jason Rhinelander
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Support std::string_view when compiled under C++17
parent
220a77f5
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
106 additions
and
7 deletions
+106
-7
docs/advanced/cast/overview.rst
+3
-0
docs/advanced/cast/strings.rst
+9
-0
include/pybind11/cast.h
+35
-6
tests/test_python_types.cpp
+15
-0
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`.
...
@@ -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::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::pair<T1, T2>`` | Pair of two custom types | :file:`pybind11/pybind11.h` |
+------------------------------------+---------------------------+-------------------------------+
+------------------------------------+---------------------------+-------------------------------+
| ``std::tuple<...>`` | Arbitrary tuple of 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
...
@@ -287,6 +287,15 @@ expressed as a single Unicode code point
no way to capture them in a C++ character type.
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
References
==========
==========
...
...
include/pybind11/cast.h
View file @
f42af24a
...
@@ -18,6 +18,19 @@
...
@@ -18,6 +18,19 @@
#include <tuple>
#include <tuple>
#include <cstring>
#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
(
pybind11
)
NAMESPACE_BEGIN
(
detail
)
NAMESPACE_BEGIN
(
detail
)
// Forward declarations:
// Forward declarations:
...
@@ -1003,10 +1016,11 @@ public:
...
@@ -1003,10 +1016,11 @@ public:
};
};
// Helper class for UTF-{8,16,32} C++ stl strings:
// Helper class for UTF-{8,16,32} C++ stl strings:
template
<
typename
CharT
,
class
Traits
,
class
Allocator
>
template
<
typename
StringType
,
bool
IsView
=
false
>
struct
string_caster
{
struct
type_caster
<
std
::
basic_string
<
CharT
,
Traits
,
Allocator
>
,
enable_if_t
<
is_std_char_type
<
CharT
>::
value
>>
{
using
CharT
=
typename
StringType
::
value_type
;
// Simplify life by being able to assume standard char sizes (the standard only guarantees
// 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
,
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
,
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"
);
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
...
@@ -1015,8 +1029,6 @@ struct type_caster<std::basic_string<CharT, Traits, Allocator>, enable_if_t<is_s
"Unsupported wchar_t size != 2/4"
);
"Unsupported wchar_t size != 2/4"
);
static
constexpr
size_t
UTF_N
=
8
*
sizeof
(
CharT
);
static
constexpr
size_t
UTF_N
=
8
*
sizeof
(
CharT
);
using
StringType
=
std
::
basic_string
<
CharT
,
Traits
,
Allocator
>
;
bool
load
(
handle
src
,
bool
)
{
bool
load
(
handle
src
,
bool
)
{
#if PY_MAJOR_VERSION < 3
#if PY_MAJOR_VERSION < 3
object
temp
;
object
temp
;
...
@@ -1050,11 +1062,16 @@ struct type_caster<std::basic_string<CharT, Traits, Allocator>, enable_if_t<is_s
...
@@ -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
);
size_t
length
=
(
size_t
)
PYBIND11_BYTES_SIZE
(
utfNbytes
.
ptr
())
/
sizeof
(
CharT
);
if
(
UTF_N
>
8
)
{
buffer
++
;
length
--
;
}
// Skip BOM for UTF-16/32
if
(
UTF_N
>
8
)
{
buffer
++
;
length
--
;
}
// Skip BOM for UTF-16/32
value
=
StringType
(
buffer
,
length
);
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
;
return
true
;
}
}
static
handle
cast
(
const
StringType
&
src
,
return_value_policy
/* policy */
,
handle
/* parent */
)
{
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
));
ssize_t
nbytes
=
ssize_t
(
src
.
size
()
*
sizeof
(
CharT
));
handle
s
=
decode_utfN
(
buffer
,
nbytes
);
handle
s
=
decode_utfN
(
buffer
,
nbytes
);
if
(
!
s
)
throw
error_already_set
();
if
(
!
s
)
throw
error_already_set
();
...
@@ -1064,6 +1081,8 @@ struct type_caster<std::basic_string<CharT, Traits, Allocator>, enable_if_t<is_s
...
@@ -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
));
PYBIND11_TYPE_CASTER
(
StringType
,
_
(
PYBIND11_STRING_NAME
));
private
:
private
:
object
view_into
;
static
handle
decode_utfN
(
const
char
*
buffer
,
ssize_t
nbytes
)
{
static
handle
decode_utfN
(
const
char
*
buffer
,
ssize_t
nbytes
)
{
#if !defined(PYPY_VERSION)
#if !defined(PYPY_VERSION)
return
return
...
@@ -1101,6 +1120,16 @@ private:
...
@@ -1101,6 +1120,16 @@ private:
bool
load_bytes
(
enable_if_t
<
sizeof
(
C
)
!=
1
,
handle
>
)
{
return
false
;
}
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
// 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).
// 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
>>
{
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) {
...
@@ -555,6 +555,21 @@ test_initializer python_types([](py::module &m) {
m
.
def
(
"nodefer_none_optional"
,
[](
py
::
none
)
{
return
false
;
});
m
.
def
(
"nodefer_none_optional"
,
[](
py
::
none
)
{
return
false
;
});
#endif
#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"
,
m
.
def
(
"return_capsule_with_destructor"
,
[]()
{
[]()
{
py
::
print
(
"creating capsule"
);
py
::
print
(
"creating capsule"
);
...
...
tests/test_python_types.py
View file @
f42af24a
...
@@ -2,7 +2,8 @@
...
@@ -2,7 +2,8 @@
import
pytest
import
pytest
import
pybind11_tests
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
():
def
test_repr
():
...
@@ -558,6 +559,48 @@ def test_bytes_to_string():
...
@@ -558,6 +559,48 @@ def test_bytes_to_string():
assert
string_length
(
u'💩'
.
encode
(
"utf8"
))
==
4
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
():
def
test_builtins_cast_return_none
():
"""Casters produced with PYBIND11_TYPE_CASTER() should convert nullptr to None"""
"""Casters produced with PYBIND11_TYPE_CASTER() should convert nullptr to None"""
import
pybind11_tests
as
m
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