File: pointer.py

package info (click to toggle)
pypy 7.0.0%2Bdfsg-3
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 107,216 kB
  • sloc: python: 1,201,787; ansic: 62,419; asm: 5,169; cpp: 3,017; sh: 2,534; makefile: 545; xml: 243; lisp: 45; awk: 4
file content (194 lines) | stat: -rw-r--r-- 6,504 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194

import _rawffi
from _rawffi import alt as _ffi
from _ctypes.basics import _CData, _CDataMeta, cdata_from_address, ArgumentError
from _ctypes.basics import keepalive_key, store_reference, ensure_objects
from _ctypes.basics import sizeof, byref, as_ffi_pointer
from _ctypes.array import Array, array_get_slice_params, array_slice_getitem,\
     array_slice_setitem

try: from __pypy__ import builtinify
except ImportError: builtinify = lambda f: f

# This cache maps types to pointers to them.
_pointer_type_cache = {}

DEFAULT_VALUE = object()

class PointerType(_CDataMeta):
    def __new__(self, name, cls, typedict):
        d = dict(
            size       = _rawffi.sizeof('P'),
            align      = _rawffi.alignment('P'),
            length     = 1,
            _ffiargshape_ = 'P',
            _ffishape_  = 'P',
            _fficompositesize_ = None,
        )
        # XXX check if typedict['_type_'] is any sane
        # XXX remember about paramfunc
        obj = type.__new__(self, name, cls, typedict)
        for k, v in d.iteritems():
            setattr(obj, k, v)
        if '_type_' in typedict:
            self.set_type(obj, typedict['_type_'])
        else:
            def __init__(self, value=None):
                raise TypeError("%s has no type" % obj)
            obj.__init__ = __init__
        return obj

    def from_param(self, value):
        if value is None:
            return self(None)
        # If we expect POINTER(<type>), but receive a <type> instance, accept
        # it by calling byref(<type>).
        if isinstance(value, self._type_):
            return byref(value)
        # Array instances are also pointers when the item types are the same.
        if isinstance(value, (_Pointer, Array)):
            if issubclass(type(value)._type_, self._type_):
                return value
        return _CDataMeta.from_param(self, value)

    def _sizeofinstances(self):
        return _rawffi.sizeof('P')

    def _alignmentofinstances(self):
        return _rawffi.alignment('P')

    def _is_pointer_like(self):
        return True

    def set_type(self, TP):
        ffiarray = _rawffi.Array('P')
        def __init__(self, value=None):
            if not hasattr(self, '_buffer'):
                self._buffer = ffiarray(1, autofree=True)
            if value is not None:
                self.contents = value
        def _init_no_arg_(self):
            self._buffer = ffiarray(1, autofree=True)
        self._ffiarray = ffiarray
        self.__init__ = __init__
        self._init_no_arg_ = _init_no_arg_
        self._type_ = TP

    def _build_ffiargtype(self):
        return _ffi.types.Pointer(self._type_.get_ffi_argtype())

    def _deref_ffiargtype(self):
        return self._type_.get_ffi_argtype()

    from_address = cdata_from_address

class _Pointer(_CData):
    __metaclass__ = PointerType

    def getcontents(self):
        addr = self._buffer[0]
        if addr == 0:
            raise ValueError("NULL pointer access")
        instance = self._type_.from_address(addr)
        instance.__dict__['_base'] = self
        return instance

    def setcontents(self, value):
        if not isinstance(value, self._type_):
            raise TypeError("expected %s instead of %s" % (
                self._type_.__name__, type(value).__name__))
        self._objects = {keepalive_key(1):value}
        if value._ensure_objects() is not None:
            self._objects[keepalive_key(0)] = value._objects
        value = value._buffer
        self._buffer[0] = value

    _get_slice_params = array_get_slice_params
    _slice_getitem = array_slice_getitem

    def _subarray(self, index=0):
        """Return a _rawffi array of length 1 whose address is the same as
        the index'th item to which self is pointing."""
        address = self._buffer[0]
        address += index * sizeof(self._type_)
        return self._type_.from_address(address)._buffer

    def __getitem__(self, index):
        if isinstance(index, slice):
            return self._slice_getitem(index)
        return self._type_._CData_output(self._subarray(index), self, index)

    def __setitem__(self, index, value):
        cobj = self._type_.from_param(value)
        if ensure_objects(cobj) is not None:
            store_reference(self, index, cobj._objects)
        address = self._buffer[0]
        address += index * sizeof(self._type_)
        cobj._copy_to(address)

    def __nonzero__(self):
        return self._buffer[0] != 0

    contents = property(getcontents, setcontents)
    _obj = property(getcontents) # byref interface

    def _as_ffi_pointer_(self, ffitype):
        return as_ffi_pointer(self, ffitype)


def _cast_addr(obj, _, tp):
    if not (isinstance(tp, _CDataMeta) and tp._is_pointer_like()):
        raise TypeError("cast() argument 2 must be a pointer type, not %s"
                        % (tp,))
    result = tp._newowninstance_()
    if isinstance(obj, (int, long)):
        result._buffer[0] = obj
        return result
    elif obj is None:
        return result
    elif isinstance(obj, Array):
        result._buffer[0] = obj._buffer
    elif isinstance(obj, bytes):
        result._buffer[0] = buffer(obj)._pypy_raw_address()
        return result
    elif not (isinstance(obj, _CData) and type(obj)._is_pointer_like()):
        raise TypeError("cast() argument 1 must be a pointer, not %s"
                        % (type(obj),))
    else:
        result._buffer[0] = obj._buffer[0]

    # The casted objects '_objects' member:
    # From now on, both objects will use the same dictionary
    # It must certainly contain the source objects
    # It must contain the source object itself.
    if obj._ensure_objects() is not None:
        result._objects = obj._objects
        if isinstance(obj._objects, dict):
            result._objects[id(obj)] =  obj

    return result

@builtinify
def POINTER(cls):
    try:
        return _pointer_type_cache[cls]
    except KeyError:
        pass
    if type(cls) is str:
        klass = type(_Pointer)("LP_%s" % cls,
                               (_Pointer,),
                               {})
        _pointer_type_cache[id(klass)] = klass
        return klass
    else:
        name = "LP_%s" % cls.__name__
        klass = type(_Pointer)(name,
                               (_Pointer,),
                               {'_type_': cls})
        _pointer_type_cache[cls] = klass
    return klass

@builtinify
def pointer(inst):
    return POINTER(type(inst))(inst)