1
from pypy.annotation import model as annmodel
2
from pypy.rlib.rctypes.implementation import CTypeController, getcontroller
3
from pypy.rlib.rctypes import rctypesobject
4
from pypy.rpython.extregistry import ExtRegistryEntry
5
from pypy.rpython.lltypesystem import lltype
6
from pypy.rlib.unroll import unrolling_iterable
8
from ctypes import Structure
10
StructType = type(Structure)
13
class StructCTypeController(CTypeController):
15
def __init__(self, ctype):
16
CTypeController.__init__(self, ctype)
18
# Map the field names to their controllers
21
for name, field_ctype in ctype._fields_:
22
controller = getcontroller(field_ctype)
23
setattr(self, 'fieldcontroller_' + name, controller)
24
controllers.append((name, controller))
25
fields.append((name, controller.knowntype))
26
external = getattr(ctype, '_external_', False)
27
self.knowntype = rctypesobject.RStruct(ctype.__name__, fields,
28
c_external = external)
29
self.fieldcontrollers = controllers
31
# Build a custom new() method where the setting of the fields
33
unrolled_controllers = unrolling_iterable(controllers)
36
obj = self.knowntype.allocate()
37
if len(args) > len(fields):
38
raise ValueError("too many arguments for this structure")
39
for name, controller in unrolled_controllers:
43
if controller.is_box(value):
44
structsetboxattr(obj, name, value)
46
structsetattr(obj, name, value)
51
# Build custom getter and setter methods
52
def structgetattr(obj, attr):
53
controller = getattr(self, 'fieldcontroller_' + attr)
54
itemobj = getattr(obj, 'ref_' + attr)()
55
return controller.return_value(itemobj)
56
structgetattr._annspecialcase_ = 'specialize:arg(1)'
58
def structsetattr(obj, attr, value):
59
controller = getattr(self, 'fieldcontroller_' + attr)
60
itemobj = getattr(obj, 'ref_' + attr)()
61
controller.store_value(itemobj, value)
62
structsetattr._annspecialcase_ = 'specialize:arg(1)'
64
def structsetboxattr(obj, attr, valuebox):
65
controller = getattr(self, 'fieldcontroller_' + attr)
66
itemobj = getattr(obj, 'ref_' + attr)()
67
controller.store_box(itemobj, valuebox)
68
structsetboxattr._annspecialcase_ = 'specialize:arg(1)'
70
self.getattr = structgetattr
71
self.setattr = structsetattr
72
self.setboxattr = structsetboxattr
74
def initialize_prebuilt(self, obj, x):
75
for name, controller in self.fieldcontrollers:
76
fieldbox = controller.convert(getattr(x, name))
77
self.setboxattr(obj, name, fieldbox)
79
def insert_constructor_keywords(self, lst, prefix, kwds):
82
for index, (name, field_ctype) in enumerate(self.ctype._fields_):
83
if prefix+name in kwds:
84
value = kwds.pop(prefix+name)
85
while len(lst) <= index:
87
if lst[index] is not None:
88
from pypy.rpython.error import TyperError
89
raise TyperError("duplicate value for argument %r" % name)
92
from pypy.rpython.error import TyperError
93
raise TyperError("unknown keyword(s): %r" % (kwds.keys(),))
96
def ctrl_new_ex(self, bookkeeper, *args_s, **kwds_s):
98
args_s = self.insert_constructor_keywords(args_s, 's_', kwds_s)
99
for i in range(len(args_s)):
100
if args_s[i] is None:
101
name, controller = self.fieldcontrollers[i]
102
x = controller.default_ctype_value()
103
args_s[i] = bookkeeper.immutablevalue(x)
104
return CTypeController.ctrl_new(self, *args_s)
106
def rtype_new(self, hop, **kwds_i):
108
lst = range(hop.nb_args)
109
for key, index in kwds_i.items():
111
lst = self.insert_constructor_keywords(lst, 'i_', kwds_i)
113
hop2.nb_args = len(lst)
117
for i, index in enumerate(lst):
118
if index is not None:
119
v = hop.args_v[index]
120
s = hop.args_s[index]
121
r = hop.args_r[index]
123
# must insert a default value
124
from pypy.objspace.flow.model import Constant
125
name, controller = self.fieldcontrollers[i]
126
x = controller.default_ctype_value()
128
s = hop.rtyper.annotator.bookkeeper.immutablevalue(x)
129
r = hop.rtyper.getrepr(s)
130
hop2.args_v.append(v)
131
hop2.args_s.append(s)
132
hop2.args_r.append(r)
134
return CTypeController.rtype_new(self, hop)
137
StructCTypeController.register_for_metatype(StructType)
139
# ____________________________________________________________
141
def offsetof(Struct, fieldname):
142
"Utility function that returns the offset of a field in a structure."
143
return getattr(Struct, fieldname).offset
145
class OffsetOfFnEntry(ExtRegistryEntry):
146
"Annotation and rtyping of calls to offsetof()"
149
def compute_result_annotation(self, s_Struct, s_fieldname):
150
assert s_Struct.is_constant()
151
assert s_fieldname.is_constant()
152
ofs = offsetof(s_Struct.const, s_fieldname.const)
154
s_result = annmodel.SomeInteger(nonneg=True)
158
def specialize_call(self, hop):
159
ofs = hop.s_result.const
160
return hop.inputconst(lltype.Signed, ofs)