mirror of
https://github.com/pybind/pybind11.git
synced 2024-11-21 20:55:11 +00:00
Support more natural syntax for vector extend
This commit is contained in:
parent
1aa8dd1745
commit
22859bb8fc
@ -94,6 +94,11 @@ v2.2.4 (September 11, 2018)
|
||||
* A few minor typo fixes and improvements to the test suite, and
|
||||
patches that silence compiler warnings.
|
||||
|
||||
* Vectors now support construction from generators, as well as ``extend()`` from a
|
||||
list or generator.
|
||||
`#1496 <https://github.com/pybind/pybind11/pull/1496>`_.
|
||||
|
||||
|
||||
v2.2.3 (April 29, 2018)
|
||||
-----------------------------------------------------
|
||||
|
||||
|
@ -1346,6 +1346,21 @@ inline size_t len(handle h) {
|
||||
return (size_t) result;
|
||||
}
|
||||
|
||||
inline size_t len_hint(handle h) {
|
||||
#if PY_VERSION_HEX >= 0x03040000
|
||||
ssize_t result = PyObject_LengthHint(h.ptr(), 0);
|
||||
#else
|
||||
ssize_t result = PyObject_Length(h.ptr());
|
||||
#endif
|
||||
if (result < 0) {
|
||||
// Sometimes a length can't be determined at all (eg generators)
|
||||
// In which case simply return 0
|
||||
PyErr_Clear();
|
||||
return 0;
|
||||
}
|
||||
return (size_t) result;
|
||||
}
|
||||
|
||||
inline str repr(handle h) {
|
||||
PyObject *str_value = PyObject_Repr(h.ptr());
|
||||
if (!str_value) throw error_already_set();
|
||||
|
@ -122,7 +122,7 @@ void vector_modifiers(enable_if_t<is_copy_constructible<typename Vector::value_t
|
||||
|
||||
cl.def(init([](iterable it) {
|
||||
auto v = std::unique_ptr<Vector>(new Vector());
|
||||
v->reserve(len(it));
|
||||
v->reserve(len_hint(it));
|
||||
for (handle h : it)
|
||||
v->push_back(h.cast<T>());
|
||||
return v.release();
|
||||
@ -136,6 +136,28 @@ void vector_modifiers(enable_if_t<is_copy_constructible<typename Vector::value_t
|
||||
"Extend the list by appending all the items in the given list"
|
||||
);
|
||||
|
||||
cl.def("extend",
|
||||
[](Vector &v, iterable it) {
|
||||
const size_t old_size = v.size();
|
||||
v.reserve(old_size + len_hint(it));
|
||||
try {
|
||||
for (handle h : it) {
|
||||
v.push_back(h.cast<T>());
|
||||
}
|
||||
} catch (const cast_error &) {
|
||||
v.erase(v.begin() + static_cast<typename Vector::difference_type>(old_size), v.end());
|
||||
try {
|
||||
v.shrink_to_fit();
|
||||
} catch (const std::exception &) {
|
||||
// Do nothing
|
||||
}
|
||||
throw;
|
||||
}
|
||||
},
|
||||
arg("L"),
|
||||
"Extend the list by appending all the items in the given list"
|
||||
);
|
||||
|
||||
cl.def("insert",
|
||||
[](Vector &v, SizeType i, const T &x) {
|
||||
if (i > v.size())
|
||||
|
@ -11,6 +11,10 @@ def test_vector_int():
|
||||
assert len(v_int) == 2
|
||||
assert bool(v_int) is True
|
||||
|
||||
# test construction from a generator
|
||||
v_int1 = m.VectorInt(x for x in range(5))
|
||||
assert v_int1 == m.VectorInt([0, 1, 2, 3, 4])
|
||||
|
||||
v_int2 = m.VectorInt([0, 0])
|
||||
assert v_int == v_int2
|
||||
v_int2[1] = 1
|
||||
@ -33,6 +37,22 @@ def test_vector_int():
|
||||
del v_int2[0]
|
||||
assert v_int2 == m.VectorInt([0, 99, 2, 3])
|
||||
|
||||
v_int2.extend(m.VectorInt([4, 5]))
|
||||
assert v_int2 == m.VectorInt([0, 99, 2, 3, 4, 5])
|
||||
|
||||
v_int2.extend([6, 7])
|
||||
assert v_int2 == m.VectorInt([0, 99, 2, 3, 4, 5, 6, 7])
|
||||
|
||||
# test error handling, and that the vector is unchanged
|
||||
with pytest.raises(RuntimeError):
|
||||
v_int2.extend([8, 'a'])
|
||||
|
||||
assert v_int2 == m.VectorInt([0, 99, 2, 3, 4, 5, 6, 7])
|
||||
|
||||
# test extending from a generator
|
||||
v_int2.extend(x for x in range(5))
|
||||
assert v_int2 == m.VectorInt([0, 99, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4])
|
||||
|
||||
|
||||
# related to the PyPy's buffer protocol.
|
||||
@pytest.unsupported_on_pypy
|
||||
|
Loading…
Reference in New Issue
Block a user