def push_field(self, num, value): ptr = rffi.ptradd(self.ll_buffer, self.shape.ll_positions[num]) TP = lltype.typeOf(value) T = lltype.Ptr(rffi.CArray(TP)) # Handle bitfields for c in unroll_letters_for_numbers: if LL_TYPEMAP[c] is TP and self.shape.ll_bitsizes: # Modify the current value with the bitfield changed bitsize = self.shape.ll_bitsizes[num] numbits = NUM_BITS(bitsize) lowbit = LOW_BIT(bitsize) if numbits: value = widen(value) current = widen(rffi.cast(T, ptr)[0]) bitmask = BIT_MASK(numbits) current &= ~(bitmask << lowbit) current |= (value & bitmask) << lowbit value = rffi.cast(TP, current) break rffi.cast(T, ptr)[0] = value
def pack_float(fmtiter): doubleval = fmtiter.accept_float_arg() floatval = r_singlefloat(doubleval) value = longlong2float.singlefloat2uint(floatval) value = widen(value) if fmtiter.bigendian: for i in range_4_unroll: x = (value >> (8*i)) & 0xff fmtiter.result.append(chr(x)) else: for i in range_4_unroll: fmtiter.result.append(chr(value & 0xff)) value >>= 8
def pack_float(fmtiter): doubleval = fmtiter.accept_float_arg() floatval = r_singlefloat(doubleval) value = longlong2float.singlefloat2uint(floatval) value = widen(value) if fmtiter.bigendian: for i in range_4_unroll: x = (value >> (8 * i)) & 0xff fmtiter.result.append(chr(x)) else: for i in range_4_unroll: fmtiter.result.append(chr(value & 0xff)) value >>= 8
def push_field(self, num, value): ptr = rffi.ptradd(self.ll_buffer, self.shape.ll_positions[num]) TP = lltype.typeOf(value) T = lltype.Ptr(rffi.CArray(TP)) # Handle bitfields for c in unroll_letters_for_numbers: if LL_TYPEMAP[c] is TP and self.shape.ll_bitsizes: # Modify the current value with the bitfield changed bitsize = self.shape.ll_bitsizes[num] numbits = NUM_BITS(bitsize) lowbit = LOW_BIT(bitsize) if numbits: value = widen(value) current = widen(rffi.cast(T, ptr)[0]) bitmask = BIT_MASK(numbits) current &= ~ (bitmask << lowbit) current |= (value & bitmask) << lowbit value = rffi.cast(TP, current) break rffi.cast(T, ptr)[0] = value
def wrap(self, x): "Wraps the Python value 'x' into one of the wrapper classes." # You might notice that this function is rather conspicuously # not RPython. We can get away with this because the function # is specialized (see after the function body). Also worth # noting is that the isinstance's involving integer types # behave rather differently to how you might expect during # annotation (see pypy/annotation/builtin.py) if x is None: return self.w_None if isinstance(x, model.W_Object): raise TypeError, "attempt to wrap already wrapped object: %s" % ( x, ) if isinstance(x, OperationError): raise TypeError, ("attempt to wrap already wrapped exception: %s" % (x, )) if isinstance(x, int): if isinstance(x, bool): return self.newbool(x) else: return self.newint(x) if isinstance(x, str): return wrapstr(self, x) if isinstance(x, unicode): return wrapunicode(self, x) if isinstance(x, float): return W_FloatObject(x) if isinstance(x, Wrappable): w_result = x.__spacebind__(self) #print 'wrapping', x, '->', w_result return w_result if isinstance(x, base_int): if self.config.objspace.std.withsmalllong: from pypy.objspace.std.smalllongobject import W_SmallLongObject from pypy.rlib.rarithmetic import r_longlong, r_ulonglong from pypy.rlib.rarithmetic import longlongmax if (not isinstance(x, r_ulonglong) or x <= r_ulonglong(longlongmax)): return W_SmallLongObject(r_longlong(x)) x = widen(x) if isinstance(x, int): return self.newint(x) else: return W_LongObject.fromrarith_int(x) return self._wrap_not_rpython(x)
def ll_alloc_and_set(LIST, count, item): if count < 0: count = 0 l = LIST.ll_newlist(count) T = typeOf(item) if T is Char or T is UniChar: check = ord(item) elif isinstance(T, Number): check = widen(item) else: check = item if (not malloc_zero_filled) or check: # as long as malloc it is known to zero the allocated memory avoid zeroing twice i = 0 while i < count: l.ll_setitem_fast(i, item) i += 1 return l
def wrap(self, x): "Wraps the Python value 'x' into one of the wrapper classes." # You might notice that this function is rather conspicuously # not RPython. We can get away with this because the function # is specialized (see after the function body). Also worth # noting is that the isinstance's involving integer types # behave rather differently to how you might expect during # annotation (see pypy/annotation/builtin.py) if x is None: return self.w_None if isinstance(x, model.W_Object): raise TypeError, "attempt to wrap already wrapped object: %s"%(x,) if isinstance(x, OperationError): raise TypeError, ("attempt to wrap already wrapped exception: %s"% (x,)) if isinstance(x, int): if isinstance(x, bool): return self.newbool(x) else: return self.newint(x) if isinstance(x, str): return wrapstr(self, x) if isinstance(x, unicode): return wrapunicode(self, x) if isinstance(x, float): return W_FloatObject(x) if isinstance(x, Wrappable): w_result = x.__spacebind__(self) #print 'wrapping', x, '->', w_result return w_result if isinstance(x, base_int): if self.config.objspace.std.withsmalllong: from pypy.objspace.std.smalllongobject import W_SmallLongObject from pypy.rlib.rarithmetic import r_longlong, r_ulonglong from pypy.rlib.rarithmetic import longlongmax if (not isinstance(x, r_ulonglong) or x <= r_ulonglong(longlongmax)): return W_SmallLongObject(r_longlong(x)) x = widen(x) if isinstance(x, int): return self.newint(x) else: return W_LongObject.fromrarith_int(x) return self._wrap_not_rpython(x)
def ll_alloc_and_set(LIST, count, item): if count < 0: count = 0 l = LIST.ll_newlist(count) T = typeOf(item) if T is Char or T is UniChar: check = ord(item) elif isinstance(T, Number): check = widen(item) else: check = item if ( not malloc_zero_filled ) or check: # as long as malloc it is known to zero the allocated memory avoid zeroing twice i = 0 while i < count: l.ll_setitem_fast(i, item) i += 1 return l
def cast_pos(self, i, ll_t): pos = rffi.ptradd(self.ll_buffer, self.shape.ll_positions[i]) TP = lltype.Ptr(rffi.CArray(ll_t)) value = rffi.cast(TP, pos)[0] # Handle bitfields for c in unroll_letters_for_numbers: if LL_TYPEMAP[c] is ll_t and self.shape.ll_bitsizes: bitsize = self.shape.ll_bitsizes[i] numbits = NUM_BITS(bitsize) lowbit = LOW_BIT(bitsize) if numbits: value = widen(value) value >>= lowbit value &= BIT_MASK(numbits) if ll_t is lltype.Bool or signedtype(ll_t._type): sign = (value >> (numbits - 1)) & 1 if sign: value = value - (1 << numbits) value = rffi.cast(ll_t, value) break return value
def f(i): l = [r_short(0)] * 10 l[i + 1] = r_short(3) return rarithmetic.widen(l[i])
def str_format(self, item): return str(widen(self.unbox(item)))
def for_computation(self, v): return widen(v)
def make_array(mytype): W_ArrayBase = globals()['W_ArrayBase'] class W_Array(W_ArrayBase): itemsize = mytype.bytes typecode = mytype.typecode @staticmethod def register(typeorder): typeorder[W_Array] = [(W_ArrayBase, None)] def __init__(self, space): self.space = space self.len = 0 self.allocated = 0 self.buffer = lltype.nullptr(mytype.arraytype) def item_w(self, w_item): space = self.space unwrap = getattr(space, mytype.unwrap) item = unwrap(w_item) if mytype.unwrap == 'bigint_w': try: item = item.touint() except (ValueError, OverflowError): msg = 'unsigned %d-byte integer out of range' % \ mytype.bytes raise OperationError(space.w_OverflowError, space.wrap(msg)) return rffi.cast(mytype.itemtype, item) if mytype.unwrap == 'str_w' or mytype.unwrap == 'unicode_w': if len(item) != 1: msg = 'array item must be char' raise OperationError(space.w_TypeError, space.wrap(msg)) item = item[0] return rffi.cast(mytype.itemtype, item) # # "regular" case: it fits in an rpython integer (lltype.Signed) result = rffi.cast(mytype.itemtype, item) if mytype.canoverflow: if rffi.cast(lltype.Signed, result) != item: # overflow. build the correct message if item < 0: msg = ('signed %d-byte integer is less than minimum' % mytype.bytes) else: msg = ('signed %d-byte integer is greater than maximum' % mytype.bytes) if not mytype.signed: msg = 'un' + msg # 'signed' => 'unsigned' raise OperationError(space.w_OverflowError, space.wrap(msg)) return result def __del__(self): # note that we don't call clear_all_weakrefs here because # an array with freed buffer is ok to see - it's just empty with 0 # length self.setlen(0) def setlen(self, size, zero=False, overallocate=True): if size > 0: if size > self.allocated or size < self.allocated / 2: if overallocate: if size < 9: some = 3 else: some = 6 some += size >> 3 else: some = 0 self.allocated = size + some if zero: new_buffer = lltype.malloc(mytype.arraytype, self.allocated, flavor='raw', add_memory_pressure=True, zero=True) else: new_buffer = lltype.malloc(mytype.arraytype, self.allocated, flavor='raw', add_memory_pressure=True) for i in range(min(size, self.len)): new_buffer[i] = self.buffer[i] else: self.len = size return else: assert size == 0 self.allocated = 0 new_buffer = lltype.nullptr(mytype.arraytype) if self.buffer: lltype.free(self.buffer, flavor='raw') self.buffer = new_buffer self.len = size def fromsequence(self, w_seq): space = self.space oldlen = self.len try: new = space.len_w(w_seq) self.setlen(self.len + new) except OperationError: pass i = 0 try: if mytype.typecode == 'u': myiter = space.unpackiterable else: myiter = space.listview for w_i in myiter(w_seq): if oldlen + i >= self.len: self.setlen(oldlen + i + 1) self.buffer[oldlen + i] = self.item_w(w_i) i += 1 except OperationError: self.setlen(oldlen + i) raise self.setlen(oldlen + i) def fromstring(self, s): if len(s) % self.itemsize != 0: msg = 'string length not a multiple of item size' raise OperationError(self.space.w_ValueError, self.space.wrap(msg)) oldlen = self.len new = len(s) / mytype.bytes self.setlen(oldlen + new) cbuf = self._charbuf_start() for i in range(len(s)): cbuf[oldlen * mytype.bytes + i] = s[i] self._charbuf_stop() def fromlist(self, w_lst): s = self.len try: self.fromsequence(w_lst) except OperationError: self.setlen(s) raise def extend(self, w_iterable, accept_different_array=False): space = self.space if isinstance(w_iterable, W_Array): oldlen = self.len new = w_iterable.len self.setlen(self.len + new) i = 0 while i < new: if oldlen + i >= self.len: self.setlen(oldlen + i + 1) self.buffer[oldlen + i] = w_iterable.buffer[i] i += 1 self.setlen(oldlen + i) elif (not accept_different_array and isinstance(w_iterable, W_ArrayBase)): msg = "can only extend with array of same kind" raise OperationError(space.w_TypeError, space.wrap(msg)) else: self.fromsequence(w_iterable) def _charbuf_start(self): return rffi.cast(rffi.CCHARP, self.buffer) def _charbuf_stop(self): keepalive_until_here(self) def w_getitem(self, space, idx): item = self.buffer[idx] if mytype.typecode in 'bBhHil': item = rffi.cast(lltype.Signed, item) elif mytype.typecode == 'f': item = float(item) return space.wrap(item) # Basic get/set/append/extend methods def len__Array(space, self): return space.wrap(self.len) def getitem__Array_ANY(space, self, w_idx): idx, stop, step = space.decode_index(w_idx, self.len) assert step == 0 return self.w_getitem(space, idx) def getitem__Array_Slice(space, self, w_slice): start, stop, step, size = space.decode_index4(w_slice, self.len) w_a = mytype.w_class(self.space) w_a.setlen(size, overallocate=False) assert step != 0 j = 0 for i in range(start, stop, step): w_a.buffer[j] = self.buffer[i] j += 1 return w_a def getslice__Array_ANY_ANY(space, self, w_i, w_j): return space.getitem(self, space.newslice(w_i, w_j, space.w_None)) def setitem__Array_ANY_ANY(space, self, w_idx, w_item): idx, stop, step = space.decode_index(w_idx, self.len) if step != 0: msg = 'can only assign array to array slice' raise OperationError(self.space.w_TypeError, self.space.wrap(msg)) item = self.item_w(w_item) self.buffer[idx] = item def setitem__Array_Slice_Array(space, self, w_idx, w_item): start, stop, step, size = self.space.decode_index4(w_idx, self.len) assert step != 0 if w_item.len != size or self is w_item: # XXX this is a giant slow hack w_lst = array_tolist__Array(space, self) w_item = space.call_method(w_item, 'tolist') space.setitem(w_lst, w_idx, w_item) self.setlen(0) self.fromsequence(w_lst) else: j = 0 for i in range(start, stop, step): self.buffer[i] = w_item.buffer[j] j += 1 def setslice__Array_ANY_ANY_ANY(space, self, w_i, w_j, w_x): space.setitem(self, space.newslice(w_i, w_j, space.w_None), w_x) def array_append__Array_ANY(space, self, w_x): x = self.item_w(w_x) self.setlen(self.len + 1) self.buffer[self.len - 1] = x def array_extend__Array_ANY(space, self, w_iterable): self.extend(w_iterable) # List interface def array_count__Array_ANY(space, self, w_val): cnt = 0 for i in range(self.len): w_item = self.w_getitem(space, i) if space.is_true(space.eq(w_item, w_val)): cnt += 1 return space.wrap(cnt) def array_index__Array_ANY(space, self, w_val): cnt = 0 for i in range(self.len): w_item = self.w_getitem(space, i) if space.is_true(space.eq(w_item, w_val)): return space.wrap(i) msg = 'array.index(x): x not in list' raise OperationError(space.w_ValueError, space.wrap(msg)) def array_reverse__Array(space, self): b = self.buffer for i in range(self.len / 2): b[i], b[self.len - i - 1] = b[self.len - i - 1], b[i] def array_pop__Array_ANY(space, self, w_idx): i = space.int_w(w_idx) if i < 0: i += self.len if i < 0 or i >= self.len: msg = 'pop index out of range' raise OperationError(space.w_IndexError, space.wrap(msg)) w_val = self.w_getitem(space, i) while i < self.len - 1: self.buffer[i] = self.buffer[i + 1] i += 1 self.setlen(self.len - 1) return w_val def array_remove__Array_ANY(space, self, w_val): w_idx = array_index__Array_ANY(space, self, w_val) array_pop__Array_ANY(space, self, w_idx) def array_insert__Array_ANY_ANY(space, self, w_idx, w_val): idx = space.int_w(w_idx) if idx < 0: idx += self.len if idx < 0: idx = 0 if idx > self.len: idx = self.len val = self.item_w(w_val) self.setlen(self.len + 1) i = self.len - 1 while i > idx: self.buffer[i] = self.buffer[i - 1] i -= 1 self.buffer[i] = val def delitem__Array_ANY(space, self, w_idx): # XXX this is a giant slow hack w_lst = array_tolist__Array(space, self) space.delitem(w_lst, w_idx) self.setlen(0) self.fromsequence(w_lst) def delslice__Array_ANY_ANY(space, self, w_i, w_j): return space.delitem(self, space.newslice(w_i, w_j, space.w_None)) # Add and mul methods def add__Array_Array(space, self, other): a = mytype.w_class(space) a.setlen(self.len + other.len, overallocate=False) for i in range(self.len): a.buffer[i] = self.buffer[i] for i in range(other.len): a.buffer[i + self.len] = other.buffer[i] return a def inplace_add__Array_Array(space, self, other): oldlen = self.len otherlen = other.len self.setlen(oldlen + otherlen) for i in range(otherlen): self.buffer[oldlen + i] = other.buffer[i] return self def mul__Array_ANY(space, self, w_repeat): return _mul_helper(space, self, w_repeat, False) def mul__ANY_Array(space, w_repeat, self): return _mul_helper(space, self, w_repeat, False) def inplace_mul__Array_ANY(space, self, w_repeat): return _mul_helper(space, self, w_repeat, True) def _mul_helper(space, self, w_repeat, is_inplace): try: repeat = space.getindex_w(w_repeat, space.w_OverflowError) except OperationError, e: if e.match(space, space.w_TypeError): raise FailedToImplement raise repeat = max(repeat, 0) try: newlen = ovfcheck(self.len * repeat) except OverflowError: raise MemoryError oldlen = self.len if is_inplace: a = self start = 1 else: a = mytype.w_class(space) start = 0 # <a performance hack> if oldlen == 1: if mytype.unwrap == 'str_w' or mytype.unwrap == 'unicode_w': zero = not ord(self.buffer[0]) elif mytype.unwrap == 'int_w' or mytype.unwrap == 'bigint_w': zero = not widen(self.buffer[0]) #elif mytype.unwrap == 'float_w': # value = ...float(self.buffer[0]) xxx handle the case of -0.0 else: zero = False if zero: a.setlen(newlen, zero=True, overallocate=False) return a a.setlen(newlen, overallocate=False) item = self.buffer[0] for r in range(start, repeat): a.buffer[r] = item return a # </a performance hack> a.setlen(newlen, overallocate=False) for r in range(start, repeat): for i in range(oldlen): a.buffer[r * oldlen + i] = self.buffer[i] return a
def tagged_eq(x, y): # please rpython :( return rarithmetic.widen(x) == rarithmetic.widen(y)
def untag(value): value = rarithmetic.widen(value) tagbits = value&TAGMASK return value>>2, tagbits
def args_from_rarith_int(x): return args_from_rarith_int1(widen(x))