2013-10-28 8 views
8

Pythonのctypesで128ビット整数(現在は__uint128_t)をサポートする最良の方法は何ですか?ctypesを持つ128ビット整数の扱い

おそらく2つのuint64_tのユーザー定義構造体ですが、これは必要な箇所で整列問題を作成します。

なぜctypesが128ビット整数をサポートするように拡張されていないのか?

+0

パックされた構造体(_pack_ = 1)は、少なくとも整列の問題を解決します。 – epx

+0

実際には、これらのベクトルは、最高のパフォーマンスを得るために16バイトのメモリに保持する必要があります。 – Fil

+2

注: '__uint128_t'はGCCエクステンションのようです:http://stackoverflow.com/a/18531871/2419207 – iljau

答えて

1

実際に128ビットのの整数を使用したい場合、アラインメントについて心配する必要はありません。現在のアーキテクチャはなく、Pythonを実行するマシンもなく、128ビットのネイティブ整数算術をサポートしています。だから、128ビットの整数を16バイトに整列させることを必要としたり、恩恵を受けるマシンはありません。そのユーザー定義の構造体を使用すれば、うまくいくでしょう。

あなたが本当に求めているのは、128ビットのベクトルタイプのサポートであれば、おそらくそれらを整列させる必要があります。つまり、Pythonコードで作成し、C/C++コードを参照して渡す場合は、それらを整列させる必要があります。値を確実に渡すことはできません。スタック上にctypesを適切に配置する方法はありません(アーキテクチャABIで必要な場合)。 C/C++からPythonに渡されるベクトルはおそらく既に適切に整列されています。だから、すべてのベクトルがC/C++コードで割り当てられるように配列することができれば、ユーザー定義の構造体もうまくいくはずです。

実際には、Pythonコードで整列したベクトルを作成する必要があると仮定し、整列されたctypes配列のコードを含めました。私は、他のctypes型を、コードサイズに合わないものに合わせるためのコードも用意しています。配列はほとんどの目的に十分でなければなりません。これらの整列された配列にはいくつかの制限があります。 C/C++関数に値を渡したり、構造体または共用体のメンバーとしてそれらを含めると、それらは正しく整列されません。 *演算子を使用して、配列された配列の配列を整列させることができます。

aligned_array_type(ctypes-type, length, alignment)を使用すると、新しい配列型を作成できます。既に存在するアレイタイプの整列バージョンを作成するにはaligned_type(ctypes-type, alignment)を使用してください。

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) 
関連する問題