| 625 | |
| 626 | /// buffer_protocol: Fill in the view as specified by flags. |
| 627 | extern "C" inline int pybind11_getbuffer(PyObject *obj, Py_buffer *view, int flags) { |
| 628 | // Look for a `get_buffer` implementation in this type's info or any bases (following MRO). |
| 629 | type_info *tinfo = nullptr; |
| 630 | for (auto type : reinterpret_borrow<tuple>(Py_TYPE(obj)->tp_mro)) { |
| 631 | tinfo = get_type_info((PyTypeObject *) type.ptr()); |
| 632 | if (tinfo && tinfo->get_buffer) { |
| 633 | break; |
| 634 | } |
| 635 | } |
| 636 | if (view == nullptr || !tinfo || !tinfo->get_buffer) { |
| 637 | if (view) { |
| 638 | view->obj = nullptr; |
| 639 | } |
| 640 | set_error(PyExc_BufferError, "pybind11_getbuffer(): Internal error"); |
| 641 | return -1; |
| 642 | } |
| 643 | std::memset(view, 0, sizeof(Py_buffer)); |
| 644 | std::unique_ptr<buffer_info> info = nullptr; |
| 645 | try { |
| 646 | info.reset(tinfo->get_buffer(obj, tinfo->get_buffer_data)); |
| 647 | } catch (...) { |
| 648 | try_translate_exceptions(); |
| 649 | raise_from(PyExc_BufferError, "Error getting buffer"); |
| 650 | return -1; |
| 651 | } |
| 652 | if (info == nullptr) { |
| 653 | pybind11_fail("FATAL UNEXPECTED SITUATION: tinfo->get_buffer() returned nullptr."); |
| 654 | } |
| 655 | |
| 656 | if ((flags & PyBUF_WRITABLE) == PyBUF_WRITABLE && info->readonly) { |
| 657 | // view->obj = nullptr; // Was just memset to 0, so not necessary |
| 658 | set_error(PyExc_BufferError, "Writable buffer requested for readonly storage"); |
| 659 | return -1; |
| 660 | } |
| 661 | |
| 662 | // Fill in all the information, and then downgrade as requested by the caller, or raise an |
| 663 | // error if that's not possible. |
| 664 | view->itemsize = info->itemsize; |
| 665 | view->len = view->itemsize; |
| 666 | for (auto s : info->shape) { |
| 667 | view->len *= s; |
| 668 | } |
| 669 | view->ndim = static_cast<int>(info->ndim); |
| 670 | view->shape = info->shape.data(); |
| 671 | view->strides = info->strides.data(); |
| 672 | view->readonly = static_cast<int>(info->readonly); |
| 673 | if ((flags & PyBUF_FORMAT) == PyBUF_FORMAT) { |
| 674 | view->format = const_cast<char *>(info->format.c_str()); |
| 675 | } |
| 676 | |
| 677 | // Note, all contiguity flags imply PyBUF_STRIDES and lower. |
| 678 | if ((flags & PyBUF_C_CONTIGUOUS) == PyBUF_C_CONTIGUOUS) { |
| 679 | if (PyBuffer_IsContiguous(view, 'C') == 0) { |
| 680 | std::memset(view, 0, sizeof(Py_buffer)); |
| 681 | set_error(PyExc_BufferError, |
| 682 | "C-contiguous buffer requested for discontiguous storage"); |
| 683 | return -1; |
| 684 | } |
nothing calls this directly
no test coverage detected