ctypes

2013-10-28 14 views
8

के साथ 128-बिट पूर्णांक हैंडलिंग पाइथन ctypes के साथ 128-बिट पूर्णांक (वर्तमान में __uint128_t) का समर्थन करने का सबसे अच्छा तरीका क्या है?ctypes

शायद उपयोगकर्ता की परिभाषित संरचना दो uint64_t की है, लेकिन यह संरेखण के मुद्दों को बनाएगा जहां इसकी आवश्यकता है।

128-बिट पूर्णांक का समर्थन करने के लिए ctypes को क्यों नहीं बढ़ाया गया है इस पर कोई विचार?

+0

एक पैक की गई संरचना (_pack_ = 1) कम से कम संरेखण समस्या को हल करेगी। – epx

+0

वास्तव में, इन वैक्टरों को सर्वश्रेष्ठ प्रदर्शन के लिए 16 बाइट्स के साथ गठित स्मृति पर आयोजित करने की आवश्यकता नहीं है। – Fil

+2

नोट: http://stackoverflow.com/a/18531871/2419207 – iljau

उत्तर

1

यदि आप वास्तव में 128-बिट पूर्णांक के साथ काम करना चाहते हैं तो आपको संरेखण के बारे में चिंता करने की आवश्यकता नहीं है। कोई वर्तमान आर्किटेक्चर नहीं, कोई मशीन जो पायथन चलती है, 128-बिट देशी पूर्णांक अंकगणितीय का समर्थन करती है। तो 128-बिट पूर्णांक 16-बाइट गठबंधन होने से कोई मशीन की आवश्यकता या लाभ नहीं होगा। बस उस उपयोगकर्ता परिभाषित संरचना का उपयोग करें और आप ठीक हो जाएंगे।

यदि आप वास्तव में पूछ रहे हैं तो 128-बिट वेक्टर प्रकारों के लिए समर्थन है तो आपको शायद उन्हें गठबंधन करने की आवश्यकता होगी। यही है, यदि आप उन्हें पायथन कोड में बना रहे हैं और उन्हें सी/सी ++ कोड के संदर्भ में पास कर रहे हैं तो आपको उन्हें गठबंधन करने की आवश्यकता है। आप उन्हें मूल्य से विश्वसनीय रूप से पास नहीं कर सकते हैं, स्टैच पर उन्हें ठीक से संरेखित करने के लिए सीटीपीएस प्राप्त करने का कोई तरीका नहीं है (यदि यह आर्किटेक्चर एबीआई द्वारा आवश्यक है)। सी/सी ++ से पायथन तक पारित वेक्टर संभवतः पहले ही ठीक से संरेखित किए जाएंगे। इसलिए, यदि आप इसे व्यवस्थित कर सकते हैं तो आपके सभी वैक्टर सी/सी ++ कोड में आवंटित किए गए हैं, आपको अपने उपयोगकर्ता परिभाषित संरचना के साथ भी ठीक होना चाहिए।

मान लीजिए कि आपको वास्तव में पाइथन कोड में गठबंधन वैक्टर बनाने की आवश्यकता है तो मैंने गठबंधन ctypes सरणी के लिए कोड शामिल किया है। मेरे पास अन्य प्रकार के प्रकारों को संरेखित करने के लिए कोड भी है जिन्हें मैंने कोड आकार में उचित रूप से शामिल नहीं किया है। अधिकांश उद्देश्यों के लिए Arrays पर्याप्त होना चाहिए। इन गठबंधन सरणी में कुछ सीमाएं हैं। यदि आप उन्हें सी/सी ++ कार्यों के मूल्य से पास करते हैं या यदि आप उन्हें संरचना या संघ में सदस्य के रूप में शामिल करते हैं तो उन्हें ठीक से संरेखित नहीं किया जाएगा। आप * ऑपरेटर का उपयोग करके गठबंधन सरणी के गठबंधन सरणी बना सकते हैं।

नए संरेखित सरणी प्रकार बनाने के लिए 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)