Việc hiển thị số điện thoại dưới dạng memoryview
yêu cầu tạo số Py_buffer
trước tiên. Trong Python 3.3+ có một chức năng trợ giúp thuận tiện, PyMemoryView_FromMemory
mà có rất nhiều công việc cho chúng tôi. Trong các phiên bản trước đó mặc dù chúng tôi sẽ cần phải thực hiện một vài bước mở rộng, vì vậy typemap cơ bản ra chúng tôi trông giống như:
%typemap(out) std::vector<uint8_t>&, const std::vector<uint8_t>& {
Py_buffer *buf=(Py_buffer*)malloc(sizeof *buf);
const bool ro = info<$1_type>::is_readonly();
if (PyBuffer_FillInfo(buf, NULL, &((*$1)[0]), (*$1).size(), ro, PyBUF_ND)) {
// error, handle
}
$result = PyMemoryView_FromBuffer(buf);
}
Ở đây chúng ta đang cơ bản phân bổ một số bộ nhớ cho các Py_buffer
. Điều này chỉ chứa các chi tiết của bộ đệm bên trong cho Python. Bộ nhớ mà chúng tôi phân bổ sẽ thuộc sở hữu của đối tượng memoryview
sau khi được tạo. Thật không may kể từ khi nó sẽ được phát hành với một cuộc gọi đến free()
chúng ta cần phải phân bổ nó với malloc()
, mặc dù nó là mã C + +.
Bên cạnh Py_buffer
và một tùy chọn Py_Object
PyBuffer_FillInfo
mất một void*
(bộ đệm riêng của mình), kích thước của bộ đệm, một boolean chỉ ra nếu nó có khả năng ghi và một lá cờ. Trong trường hợp này lá cờ của chúng tôi chỉ đơn giản chỉ ra rằng chúng tôi đã cung cấp bộ nhớ tiếp giáp kiểu C cho bộ đệm.
Để quyết định xem nó có chỉ đọc hay không, chúng tôi đã sử dụng biến được xây dựng trong biến số $n_type
của SWIG và một trình trợ giúp (có thể là đặc điểm kiểu C++ 11 nếu chúng ta muốn).
Để hoàn thành giao diện SWIG chúng ta cần cung cấp helper đó và bao gồm các tập tin tiêu đề, vì vậy toàn bộ điều trở thành:
%module test
%{
#include "test.hh"
namespace {
template <typename T>
struct info {
static bool is_readonly() {
return false;
}
};
template <typename T>
struct info<const T&> {
static bool is_readonly() {
return true;
}
};
}
%}
%typemap(out) std::vector<uint8_t>&, const std::vector<uint8_t>& {
Py_buffer *buf=(Py_buffer*)malloc(sizeof *buf);
const bool ro = info<$1_type>::is_readonly();
if (PyBuffer_FillInfo(buf, NULL, &((*$1)[0]), (*$1).size(), ro, PyBUF_ND)) {
// error, handle
}
$result = PyMemoryView_FromBuffer(buf);
}
%include "test.hh"
Sau đó chúng tôi có thể thử nghiệm nó với:
import test
print test.vec()
print len(test.vec())
print test.vec()[0]
print test.vec().readonly
test.vec()[0]='z'
print test.vec()[0]
print "This should fail:"
test.cvec()[0] = 0
nào làm việc như mong đợi, được thử nghiệm bằng Python 2.7.
So với chỉ gói nó bằng cách sử dụng std_vector.i phương pháp này không có một số hạn chế. Lớn nhất là chúng tôi không thể thay đổi kích cỡ véc tơ, hoặc chuyển đổi nó trở lại một vector sau này tầm thường. Chúng ta có thể làm việc xung quanh điều đó, ít nhất một phần bằng cách tạo một proxy SWIG cho vectơ như bình thường và sử dụng tham số thứ hai của PyBuffer_FillInfo
để lưu trữ nó trong nội bộ. (Điều này cũng sẽ cần thiết nếu chúng ta phải quản lý quyền sở hữu của vectơ chẳng hạn).