diff --git a/example/example17.py b/example/example17.py index 538528022..d41a3254b 100644 --- a/example/example17.py +++ b/example/example17.py @@ -16,6 +16,9 @@ print( v_int != v_int2 ) v_int2.push_back(2) v_int2.push_back(3) +v_int2.insert(0, 1) +v_int2.insert(0, 2) +v_int2.insert(0, 3) print(v_int2) v_a = VectorA() diff --git a/example/example17.ref b/example/example17.ref index 09489f1d2..249fbabe5 100644 --- a/example/example17.ref +++ b/example/example17.ref @@ -2,4 +2,4 @@ True True True -VectorInt[0, 1, 2, 3] +VectorInt[3, 2, 1, 0, 1, 2, 3] diff --git a/include/pybind11/common.h b/include/pybind11/common.h index 38f8bc8c8..e60684fc2 100644 --- a/include/pybind11/common.h +++ b/include/pybind11/common.h @@ -305,6 +305,7 @@ NAMESPACE_END(detail) class error_already_set : public std::runtime_error { public: error_already_set() : std::runtime_error(detail::error_string()) {} }; PYBIND11_RUNTIME_EXCEPTION(stop_iteration) PYBIND11_RUNTIME_EXCEPTION(index_error) +PYBIND11_RUNTIME_EXCEPTION(value_error) PYBIND11_RUNTIME_EXCEPTION(cast_error) /// Thrown when pybind11::cast or handle::call fail due to a type casting error [[noreturn]] PYBIND11_NOINLINE inline void pybind11_fail(const char *reason) { throw std::runtime_error(reason); } diff --git a/include/pybind11/stl_binders.h b/include/pybind11/stl_binders.h index 4dbd0b61c..a2af0ac8f 100644 --- a/include/pybind11/stl_binders.h +++ b/include/pybind11/stl_binders.h @@ -21,6 +21,11 @@ NAMESPACE_BEGIN(pybind11) +#if (!defined _MSC_VER) || (_MSC_VER > 1900) + #define INSERTION_OPERATOR_IMPLEMENTATION +#endif + + template constexpr auto has_equal_operator(int) -> decltype( std::declval() == std::declval(), bool()) { return true; } template @@ -34,7 +39,7 @@ template constexpr bool has_not_equal_operator(...) { return false; } - +#ifdef INSERTION_OPERATOR_IMPLEMENTATION namespace has_insertion_operator_implementation { enum class False {}; struct any_type { @@ -48,6 +53,7 @@ constexpr bool has_insertion_operator() using namespace has_insertion_operator_implementation; return std::is_same< decltype( std::declval() << std::declval() ), std::ostream & >::value; } +#endif template , typename holder_type = std::unique_ptr< std::vector > > @@ -88,6 +94,12 @@ class vector_binder cl.def(pybind11::self != pybind11::self); cl.def("count", [](Vector const &v, T const & value) { return std::count(v.begin(), v.end(), value); }, "counts the elements that are equal to value"); + + cl.def("remove", [](Vector &v, const T&t) { + auto p = std::find(v.begin(), v.end(), t); + if( p != v.end() ) v.erase(p); + else throw pybind11::value_error(); + }, "Remove the first item from the list whose value is x. It is an error if there is no such item."); } template(0) >::type * = nullptr> void maybe_has_equal_operator(Class_ &) {} @@ -101,6 +113,7 @@ class vector_binder void maybe_has_not_equal_operator(Class_ &) {} + #ifdef INSERTION_OPERATOR_IMPLEMENTATION template() >::type * = nullptr> void maybe_has_insertion_operator(Class_ &cl, std::string name) { cl.def("__repr__", [name](typename vector_binder::Vector &v) { @@ -117,7 +130,7 @@ class vector_binder } template() >::type * = nullptr> void maybe_has_insertion_operator(Class_ &, char const *) {} - + #endif @@ -131,6 +144,18 @@ public: maybe_default_constructible(cl); maybe_copy_constructible(cl); + // Element access + cl.def("front", [](Vector &v) { + if( v.size() ) return v.front(); + else throw pybind11::index_error(); + }, "access the first element"); + cl.def("back", [](Vector &v) { + if( v.size() ) return v.back(); + else throw pybind11::index_error(); + }, "access the last element "); + // Not needed, the operator[] is already providing bounds checking cl.def("at", (T& (Vector::*)(SizeType i)) &Vector::at, "access specified element with bounds checking"); + + // Capacity cl.def("empty", &Vector::empty, "checks whether the container is empty"); cl.def("size", &Vector::size, "returns the number of elements"); @@ -139,32 +164,47 @@ public: cl.def("capacity", &Vector::capacity, "returns the number of elements that can be held in currently allocated storage"); cl.def("shrink_to_fit", &Vector::shrink_to_fit, "reduces memory usage by freeing unused memory"); - // Modifiers - cl.def("clear", &Vector::clear, "clears the contents"); - cl.def("push_back", (void (Vector::*)(const T&)) &Vector::push_back, "adds an element to the end"); - cl.def("pop_back", &Vector::pop_back, "removes the last element"); - cl.def("swap", &Vector::swap, "swaps the contents"); + // Modifiers, C++ style + cl.def("clear", &Vector::clear, "clears the contents"); + cl.def("push_back", (void (Vector::*)(const T&)) &Vector::push_back, "adds an element to the end"); + cl.def("pop_back", &Vector::pop_back, "removes the last element"); + cl.def("swap", &Vector::swap, "swaps the contents"); + + + // Modifiers, Python style + cl.def("append", (void (Vector::*)(const T&)) &Vector::push_back, "adds an element to the end"); + cl.def("insert", [](Vector &v, SizeType i, const T&t) {v.insert(v.begin()+i, t);}, "insert an item at a given position"); + cl.def("pop", [](Vector &v) { + if( v.size() ) { + T t = v.back(); + v.pop_back(); + return t; + } + else throw pybind11::index_error(); + }, "insert an item at a given position"); + cl.def("erase", [](Vector &v, SizeType i) { - if (i >= v.size()) throw pybind11::index_error(); - v.erase( v.begin() + i ); - }, "erases element at index"); + if( i >= v.size() ) throw pybind11::index_error(); + v.erase( v.begin() + i ); + }, "erases element at index"); + // Python friendly bindings #ifdef PYTHON_ABI_VERSION // Python 3+ - cl.def("__bool__", [](Vector &v) -> bool { return v.size(); }); // checks whether the container has any elements in it + cl.def("__bool__", [](Vector &v) -> bool { return v.size() != 0; }); // checks whether the container has any elements in it #else - cl.def("__nonzero__", [](Vector &v) -> bool { return v.size(); }); // checks whether the container has any elements in it + cl.def("__nonzero__", [](Vector &v) -> bool { return v.size() != 0; }); // checks whether the container has any elements in it #endif cl.def("__getitem__", [](Vector const &v, SizeType i) { - if (i >= v.size()) throw pybind11::index_error(); - return v[i]; - }); + if( i >= v.size() ) throw pybind11::index_error(); + return v[i]; + }); cl.def("__setitem__", [](Vector &v, SizeType i, T const & t) { - if (i >= v.size()) throw pybind11::index_error(); - v[i] = t; + if( i >= v.size() ) throw pybind11::index_error(); + v[i] = t; }); cl.def("__len__", &Vector::size); @@ -174,7 +214,9 @@ public: maybe_has_not_equal_operator(cl); // Printing + #ifdef INSERTION_OPERATOR_IMPLEMENTATION maybe_has_insertion_operator(cl, name); + #endif } };