diff --git a/example/example17.ref b/example/example17.ref index 388e0f0d5..d54c85cef 100644 --- a/example/example17.ref +++ b/example/example17.ref @@ -8,4 +8,4 @@ A constructor A destructor A constructor A destructor -VectorA[A{1}, A{2}] \ No newline at end of file +VectorA[A{1}, A{2}] diff --git a/include/pybind11/stl_binders.h b/include/pybind11/stl_binders.h index 7fcf635a7..098713793 100644 --- a/include/pybind11/stl_binders.h +++ b/include/pybind11/stl_binders.h @@ -20,7 +20,7 @@ NAMESPACE_BEGIN(pybind11) - +NAMESPACE_BEGIN(detail) template constexpr auto has_equal_operator(int) -> decltype(std::declval() == std::declval(), bool()) { return true; } @@ -67,200 +67,196 @@ struct has_insertion_operator_s { }; +template::value >::type * = nullptr> +void vector_maybe_default_constructible(Class_ &cl) { + using size_type = typename Vector::size_type; + + cl.def(pybind11::init()); + cl.def("resize", (void (Vector::*)(size_type count)) &Vector::resize, "changes the number of elements stored"); + + /// Slicing protocol + cl.def("__getitem__", [](Vector const &v, pybind11::slice slice) -> Vector * { + pybind11::ssize_t start, stop, step, slicelength; + if(!slice.compute(v.size(), &start, &stop, &step, &slicelength)) + throw pybind11::error_already_set(); + Vector *seq = new Vector(slicelength); + for (int i=0; i::value >::type * = nullptr> +void vector_maybe_default_constructible(Class_ &) {} + + +template::value >::type * = nullptr> +void vector_maybe_copy_constructible(Class_ &cl) { + cl.def(pybind11::init< Vector const &>()); +} +template::value >::type * = nullptr> +void vector_maybe_copy_constructible(Class_ &) {} + + +template::value >::type * = nullptr> +void vector_maybe_has_equal_operator(Class_ &cl) { + using T = typename Vector::value_type; + + cl.def(pybind11::self == pybind11::self); + 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, T const &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."); + + cl.def("__contains__", [](Vector const &v, T const &t) { return std::find(v.begin(), v.end(), t) != v.end(); }, "return true if item in the container"); +} +template::value >::type * = nullptr> +void vector_maybe_has_equal_operator(Class_ &) {} + + +template::value >::type * = nullptr> +void vector_maybe_has_not_equal_operator(Class_ &cl) { + cl.def(pybind11::self != pybind11::self); +} +template::value >::type * = nullptr> +void vector_maybe_has_not_equal_operator(Class_ &) {} + + +template::value >::type * = nullptr> +void vector_maybe_has_insertion_operator(char const *name, Class_ &cl) { + using size_type = typename Vector::size_type; + + cl.def("__repr__", [name](Vector &v) { + std::ostringstream s; + s << name << '['; + for(size_type i=0; i::value >::type * = nullptr> +void vector_maybe_has_insertion_operator(char const *, Class_ &) {} + + +NAMESPACE_END(detail) + template , typename holder_type = std::unique_ptr< std::vector > > -class vector_binder { +pybind11::class_, holder_type > vector_binder(pybind11::module &m, char const *name, char const *doc=nullptr) { using Vector = std::vector; using SizeType = typename Vector::size_type; - using Class_ = pybind11::class_; - // template{} >::type * = nullptr> - // void maybe_constructible(Class_ &cl) { - // cl.def(pybind11::init<>()); - // } - // template{} >::type * = nullptr> - // void maybe_constructible(Class_ &cl) {} + Class_ cl(m, name, doc); - template::value >::type * = nullptr> - void maybe_default_constructible() { - cl.def(pybind11::init()); - cl.def("resize", (void (Vector::*)(SizeType count)) &Vector::resize, "changes the number of elements stored"); + cl.def(pybind11::init<>()); - /// Slicing protocol - cl.def("__getitem__", [](Vector const &v, pybind11::slice slice) -> Vector * { - pybind11::ssize_t start, stop, step, slicelength; - if(!slice.compute(v.size(), &start, &stop, &step, &slicelength)) - throw pybind11::error_already_set(); - Vector *seq = new Vector(slicelength); - for (int i=0; i::value >::type * = nullptr> - void maybe_default_constructible() {} + detail::vector_maybe_default_constructible(cl); + detail::vector_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"); - template::value >::type * = nullptr> - void maybe_copy_constructible() { - cl.def(pybind11::init< Vector const &>()); - } - template::value >::type * = nullptr> - void maybe_copy_constructible() {} + // Capacity, C++ style + cl.def("max_size", &Vector::max_size, "returns the maximum possible number of elements"); + cl.def("reserve", &Vector::reserve, "reserves storage"); + 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, C++ style + cl.def("clear", &Vector::clear, "clears the contents"); + cl.def("swap", &Vector::swap, "swaps the contents"); - template::value >::type * = nullptr> - void maybe_has_equal_operator() { - cl.def(pybind11::self == pybind11::self); - 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, T const &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."); - - cl.def("__contains__", [](Vector const &v, T const &t) { return std::find(v.begin(), v.end(), t) != v.end(); }, "return true if item in the container"); - } - template::value >::type * = nullptr> - void maybe_has_equal_operator() {} - - - template::value >::type * = nullptr> - void maybe_has_not_equal_operator() { - cl.def(pybind11::self != pybind11::self); - } - template::value >::type * = nullptr> - void maybe_has_not_equal_operator() {} - - - template::value >::type * = nullptr> - void maybe_has_insertion_operator(char const *name) { - cl.def("__repr__", [name](typename vector_binder::Vector &v) { - std::ostringstream s; - s << name << '['; - for(SizeType i=0; i::value >::type * = nullptr> - void maybe_has_insertion_operator(char const *) {} - - -public: - Class_ cl; - - vector_binder(pybind11::module &m, char const *name, char const *doc=nullptr) : cl(m, name, doc) { - cl.def(pybind11::init<>()); - - //maybe_constructible(cl); - maybe_default_constructible(); - maybe_copy_constructible(); - - // 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, C++ style - cl.def("max_size", &Vector::max_size, "returns the maximum possible number of elements"); - cl.def("reserve", &Vector::reserve, "reserves storage"); - 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, C++ style - cl.def("clear", &Vector::clear, "clears the contents"); - 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(); - }, "remove and return last item"); - - cl.def("pop", [](Vector &v, SizeType i) { - if(i >= v.size()) throw pybind11::index_error(); - T t = v[i]; - v.erase(v.begin() + i); + // 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; - }, "remove and return item at index"); + } + else throw pybind11::index_error(); + }, "remove and return last item"); - cl.def("erase", [](Vector &v, SizeType i) { - if(i >= v.size()) throw pybind11::index_error(); - v.erase(v.begin() + i); - }, "erases element at index"); + cl.def("pop", [](Vector &v, SizeType i) { + if(i >= v.size()) throw pybind11::index_error(); + T t = v[i]; + v.erase(v.begin() + i); + return t; + }, "remove and return item at index"); + + cl.def("erase", [](Vector &v, SizeType i) { + 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() != 0; }); // checks whether the container has any elements in it - #else - cl.def("__nonzero__", [](Vector &v) -> bool { return v.size() != 0; }); // checks whether the container has any elements in it - #endif + // Python friendly bindings + #ifdef PYTHON_ABI_VERSION // Python 3+ + 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() != 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]; - }); - - cl.def("__setitem__", [](Vector &v, SizeType i, T const & t) { - if(i >= v.size()) throw pybind11::index_error(); - v[i] = t; + cl.def("__getitem__", [](Vector const &v, SizeType i) { + if(i >= v.size()) throw pybind11::index_error(); + return v[i]; }); - cl.def("__len__", &Vector::size); + cl.def("__setitem__", [](Vector &v, SizeType i, T const & t) { + if(i >= v.size()) throw pybind11::index_error(); + v[i] = t; + }); - cl.def("__iter__", [](Vector &v) { return pybind11::make_iterator(v.begin(), v.end()); }, - pybind11::keep_alive<0, 1>() /* Essential: keep object alive while iterator exists */); + cl.def("__len__", &Vector::size); - /// Slicing protocol - cl.def("__setitem__", [](Vector &v, pybind11::slice slice, Vector const &value) { - pybind11::ssize_t start, stop, step, slicelength; - if(!slice.compute(v.size(), &start, &stop, &step, &slicelength)) - throw pybind11::error_already_set(); - if((size_t) slicelength != value.size()) - throw std::runtime_error("Left and right hand size of slice assignment have different sizes!"); - for(int i=0; i() /* Essential: keep object alive while iterator exists */); - // Comparisons - maybe_has_equal_operator(); - maybe_has_not_equal_operator(); + /// Slicing protocol + cl.def("__setitem__", [](Vector &v, pybind11::slice slice, Vector const &value) { + pybind11::ssize_t start, stop, step, slicelength; + if(!slice.compute(v.size(), &start, &stop, &step, &slicelength)) + throw pybind11::error_already_set(); + if((size_t) slicelength != value.size()) + throw std::runtime_error("Left and right hand size of slice assignment have different sizes!"); + for(int i=0; i(cl); + detail::vector_maybe_has_not_equal_operator(cl); - // C++ style functions deprecated, leaving it here as an example - //cl.def("empty", &Vector::empty, "checks whether the container is empty"); - //cl.def("size", &Vector::size, "returns the number of elements"); - //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"); - } -}; + // Printing + detail::vector_maybe_has_insertion_operator(name, cl); + + // C++ style functions deprecated, leaving it here as an example + //cl.def("empty", &Vector::empty, "checks whether the container is empty"); + //cl.def("size", &Vector::size, "returns the number of elements"); + //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"); + + return cl; +} NAMESPACE_END(pybind11)