2013-10-28 19 views
8

Cách tốt nhất để hỗ trợ các số nguyên 128 bit (hiện tại là __uint128_t) với Python ctypes là gì?Xử lý các số nguyên 128 bit với ctypes

Một cấu trúc do người dùng xác định có thể là hai uint64_t, nhưng điều này sẽ tạo ra các vấn đề căn chỉnh khi cần.

Bất kỳ suy nghĩ nào về lý do tại sao ctypes chưa được mở rộng để hỗ trợ các số nguyên 128 bit?

+0

Cấu trúc đóng gói (_pack_ = 1) sẽ giải quyết vấn đề căn chỉnh ít nhất. – epx

+0

Không thực sự, các vectơ này cần phải được giữ ở bộ nhớ liên kết với 16 byte để có hiệu suất tốt nhất. – Fil

+2

Lưu ý: '__uint128_t' dường như là phần mở rộng GCC: http://stackoverflow.com/a/18531871/2419207 – iljau

Trả lời

1

Nếu bạn thực sự muốn làm việc với các số nguyên 128 bit thì bạn không cần phải lo lắng về căn chỉnh. Không có kiến ​​trúc hiện tại, không có máy mà Python chạy trên, hỗ trợ số học nguyên nguyên 128 bit. Vì vậy, không có máy nào yêu cầu hoặc hưởng lợi từ việc có các số nguyên 128 bit được căn chỉnh 16 byte. Chỉ cần sử dụng cấu trúc do người dùng định nghĩa đó và bạn sẽ ổn.

Nếu những gì bạn thực sự yêu cầu là hỗ trợ cho các loại 1282 bit vector thì có thể bạn sẽ cần phải căn chỉnh chúng. Tức là, bạn cần chúng liên kết nếu bạn đang tạo chúng trong mã Python và chuyển chúng bằng tham chiếu đến mã C/C++. Bạn không thể vượt qua chúng một cách đáng tin cậy bởi giá trị không có cách nào để có được ctypes để sắp xếp chúng đúng cách trên stack (nếu đó là yêu cầu của kiến ​​trúc ABI). Các vectơ được chuyển từ C/C++ sang Python có lẽ đã được căn chỉnh đúng cách. Vì vậy, nếu bạn có thể sắp xếp nó để tất cả các vectơ của bạn được cấp phát trong mã C/C++, bạn cũng nên sử dụng cấu trúc do người dùng định nghĩa của bạn.

Giả sử bạn thực sự cần phải tạo các vectơ liên kết trong mã Python sau đó tôi đã bao gồm mã cho các mảng ctypes liên kết. Tôi cũng có mã để sắp xếp các loại ctypes khác mà tôi chưa đưa vào kích thước mã hợp lý. Mảng nên là đủ cho hầu hết các mục đích. Các mảng liên kết này có một số hạn chế. Chúng sẽ không được căn chỉnh đúng cách nếu bạn chuyển chúng theo giá trị tới các hàm C/C++ hoặc nếu bạn gộp chúng thành các thành viên trong một cấu trúc hoặc liên kết. Bạn có thể tạo các mảng liên kết của các mảng được liên kết bằng cách sử dụng toán tử *.

Sử dụng aligned_array_type(ctypes-type, length, alignment) để tạo các loại mảng được căn chỉnh mới. Sử dụng aligned_type(ctypes-type, alignment) để tạo phiên bản được sắp xếp của loại mảng đã tồn tại.

import ctypes 

ArrayType = type(ctypes.Array) 

class _aligned_array_type(ArrayType): 
    def __mul__(self, length): 
     return aligned_array_type(self._type_ * self._length_, 
         length, self._alignment_) 

    def __init__(self, name, bases, d): 
     self._alignment_ = max(getattr(self, "_alignment_", 1), 
         ctypes.alignment(self)) 

def _aligned__new__(cls): 
    a = cls._baseclass_.__new__(cls) 
    align = cls._alignment_ 
    if ctypes.addressof(a) % align == 0: 
     return a 
    cls._baseclass_.__init__(a) # dunno if necessary 
    ctypes.resize(a, ctypes.sizeof(a) + align - 1) 
    addr = ctypes.addressof(a) 
    aligned = (addr + align - 1) // align * align 
    return cls.from_buffer(a, aligned - addr) 

class aligned_base(object): 
    @classmethod 
    def from_address(cls, addr): 
     if addr % cls._alignment_ != 0: 
      raise ValueError, ("address must be %d byte aligned" 
         % cls._alignment_) 
     return cls._baseclass_.from_address(cls, addr) 

    @classmethod 
    def from_param(cls, addr): 
     raise ValueError, ("%s objects may not be passed by value" 
        % cls.__name__) 

class aligned_array(ctypes.Array, aligned_base): 
    _baseclass_ = ctypes.Array 
    _type_ = ctypes.c_byte 
    _length_ = 1 
    __new__ = _aligned__new__ 

_aligned_type_cache = {} 

def aligned_array_type(typ, length, alignment = None): 
    """Create a ctypes array type with an alignment greater than natural""" 

    natural = ctypes.alignment(typ) 
    if alignment == None: 
     alignment = typ._alignment_ 
    else: 
     alignment = max(alignment, getattr(typ, "_alignment_", 1)) 

    if natural % alignment == 0: 
     return typ * length 
    eltsize = ctypes.sizeof(typ) 
    eltalign = getattr(typ, "_alignment_", 1) 
    if eltsize % eltalign != 0: 
     raise TypeError("type %s can't have element alignment %d" 
       " in an array" % (typ.__name__, alignment)) 
    key = (_aligned_array_type, (typ, length), alignment) 
    ret = _aligned_type_cache.get(key) 
    if ret == None: 
     name = "%s_array_%d_aligned_%d" % (typ.__name__, length, 
          alignment) 
     d = {"_type_": typ, 
      "_length_": length, 
      "_alignment_": alignment} 
     ret = _aligned_array_type(name, (aligned_array,), d) 
     _aligned_type_cache[key] = ret 
    return ret 

def aligned_type(typ, alignment): 
    """Create a ctypes type with an alignment greater than natural""" 

    if ctypes.alignment(typ) % alignment == 0: 
     return typ 
    if issubclass(typ, ctypes.Array): 
     return aligned_array_type(typ._type_, typ._length_, 
         alignment) 
    else: 
     raise TypeError("unsupported type %s" % typ) 
Các vấn đề liên quan