Skip to content

Commit

Permalink
Make any_container implicitly constructible from arithmetic values
Browse files Browse the repository at this point in the history
This further reduces the constructors required in buffer_info/numpy by
removing the need for the constructors that take a single size_t and
just forward it on via an initializer_list to the container-accepting
constructor.

Unfortunately, in `array` one of the constructors runs into an ambiguity
problem with the deprecated `array(handle, bool)` constructor (because
both the bool constructor and the any_container constructor involve an
implicit conversion, so neither has precedence), so a forwarding
constructor is kept there (until the deprecated constructor is
eventually removed).
  • Loading branch information
jagerman committed Apr 13, 2017
1 parent 5f38386 commit 201796d
Show file tree
Hide file tree
Showing 3 changed files with 15 additions and 13 deletions.
2 changes: 1 addition & 1 deletion include/pybind11/buffer_info.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ struct buffer_info {
}

buffer_info(void *ptr, size_t itemsize, const std::string &format, size_t size)
: buffer_info(ptr, itemsize, format, 1, { size }, { itemsize }) { }
: buffer_info(ptr, itemsize, format, 1, size, itemsize) { }

explicit buffer_info(Py_buffer *view, bool ownview_in = true)
: buffer_info(view->buf, (size_t) view->itemsize, view->format, (size_t) view->ndim,
Expand Down
8 changes: 7 additions & 1 deletion include/pybind11/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -660,7 +660,8 @@ static constexpr auto const_ = std::true_type{};
NAMESPACE_BEGIN(detail)

// Adaptor for converting arbitrary container arguments into a vector; implicitly convertible from
// any standard container (or C-style array) supporting std::begin/std::end.
// any standard container (or C-style array) supporting std::begin/std::end, any singleton
// arithmetic type (if T is arithmetic), or explicitly constructible from an iterator pair.
template <typename T>
class any_container {
std::vector<T> v;
Expand All @@ -680,6 +681,11 @@ class any_container {
template <typename TIn, typename = enable_if_t<std::is_convertible<TIn, T>::value>>
any_container(const std::initializer_list<TIn> &c) : any_container(c.begin(), c.end()) { }

// Implicit conversion constructor from any arithmetic type (only participates if T is also
// arithmetic).
template <typename TIn, typename = enable_if_t<std::is_arithmetic<T>::value && std::is_arithmetic<TIn>::value>>
any_container(TIn singleton) : v(1, static_cast<T>(singleton)) { }

// Avoid copying if given an rvalue vector of the correct type.
any_container(std::vector<T> &&v) : v(std::move(v)) { }

Expand Down
18 changes: 7 additions & 11 deletions include/pybind11/numpy.h
Original file line number Diff line number Diff line change
Expand Up @@ -463,7 +463,7 @@ class array : public buffer {
const void *ptr = nullptr, handle base = handle()) {

if (strides->empty())
strides = default_strides(*shape, dt.itemsize());
*strides = default_strides(*shape, dt.itemsize());

auto ndim = shape->size();
if (ndim != strides->size())
Expand Down Expand Up @@ -499,9 +499,12 @@ class array : public buffer {
array(const pybind11::dtype &dt, ShapeContainer shape, const void *ptr = nullptr, handle base = handle())
: array(dt, std::move(shape), {}, ptr, base) { }

array(const pybind11::dtype &dt, size_t count, const void *ptr = nullptr,
handle base = handle())
: array(dt, ShapeContainer{{ count }}, ptr, base) { }
// This constructor is only needed to avoid ambiguity with the deprecated (handle, bool)
// constructor that comes from PYBIND11_OBJECT_CVT; once that is gone, the above constructor can
// handle it (because ShapeContainer is implicitly constructible from arithmetic types)
template <typename T, typename = detail::enable_if_t<std::is_arithmetic<T>::value && !std::is_same<bool, T>::value>>
array(const pybind11::dtype &dt, T count)
: array(dt, count, nullptr) { }

template <typename T>
array(ShapeContainer shape, StridesContainer strides, const T *ptr, handle base = handle())
Expand All @@ -511,10 +514,6 @@ class array : public buffer {
array(ShapeContainer shape, const T *ptr, handle base = handle())
: array(std::move(shape), {}, ptr, base) { }

template <typename T>
array(size_t count, const T *ptr, handle base = handle())
: array({{ count }}, ptr, base) { }

explicit array(const buffer_info &info)
: array(pybind11::dtype(info), info.shape, info.strides, info.ptr) { }

Expand Down Expand Up @@ -739,9 +738,6 @@ template <typename T, int ExtraFlags = array::forcecast> class array_t : public
explicit array_t(ShapeContainer shape, const T *ptr = nullptr, handle base = handle())
: array(std::move(shape), ptr, base) { }

explicit array_t(size_t count, const T *ptr = nullptr, handle base = handle())
: array(count, ptr, base) { }

constexpr size_t itemsize() const {
return sizeof(T);
}
Expand Down

0 comments on commit 201796d

Please sign in to comment.