PageRenderTime 62ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/pypy/module/array/interp_array.py

https://bitbucket.org/pypy/pypy/
Python | 1062 lines | 961 code | 33 blank | 68 comment | 58 complexity | 080f9744c0590537d6262611353c47d7 MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
  1. from rpython.rlib import jit, rgc
  2. from rpython.rlib.buffer import Buffer
  3. from rpython.rlib.objectmodel import keepalive_until_here
  4. from rpython.rlib.rarithmetic import ovfcheck, widen
  5. from rpython.rlib.unroll import unrolling_iterable
  6. from rpython.rtyper.annlowlevel import llstr
  7. from rpython.rtyper.lltypesystem import lltype, rffi
  8. from rpython.rtyper.lltypesystem.rstr import copy_string_to_raw
  9. from pypy.interpreter.baseobjspace import W_Root
  10. from pypy.interpreter.error import OperationError, oefmt
  11. from pypy.interpreter.gateway import (
  12. interp2app, interpindirect2app, unwrap_spec)
  13. from pypy.interpreter.typedef import (
  14. GetSetProperty, TypeDef, make_weakref_descr)
  15. from pypy.module._file.interp_file import W_File
  16. @unwrap_spec(typecode=str)
  17. def w_array(space, w_cls, typecode, __args__):
  18. if len(__args__.arguments_w) > 1:
  19. raise oefmt(space.w_TypeError, "array() takes at most 2 arguments")
  20. if len(typecode) != 1:
  21. raise oefmt(space.w_TypeError,
  22. "array() argument 1 must be char, not str")
  23. typecode = typecode[0]
  24. if space.is_w(w_cls, space.gettypeobject(W_ArrayBase.typedef)):
  25. if __args__.keywords:
  26. raise oefmt(space.w_TypeError,
  27. "array.array() does not take keyword arguments")
  28. for tc in unroll_typecodes:
  29. if typecode == tc:
  30. a = space.allocate_instance(types[tc].w_class, w_cls)
  31. a.__init__(space)
  32. if len(__args__.arguments_w) > 0:
  33. w_initializer = __args__.arguments_w[0]
  34. if space.type(w_initializer) is space.w_str:
  35. a.descr_fromstring(space, w_initializer)
  36. elif space.type(w_initializer) is space.w_list:
  37. a.descr_fromlist(space, w_initializer)
  38. else:
  39. a.extend(w_initializer, True)
  40. break
  41. else:
  42. raise oefmt(space.w_ValueError,
  43. "bad typecode (must be c, b, B, u, h, H, i, I, l, L, f or "
  44. "d)")
  45. return a
  46. def descr_itemsize(space, self):
  47. return space.wrap(self.itemsize)
  48. def descr_typecode(space, self):
  49. return space.wrap(self.typecode)
  50. arr_eq_driver = jit.JitDriver(name='array_eq_driver', greens=['comp_func'],
  51. reds='auto')
  52. EQ, NE, LT, LE, GT, GE = range(6)
  53. def compare_arrays(space, arr1, arr2, comp_op):
  54. if not (isinstance(arr1, W_ArrayBase) and isinstance(arr2, W_ArrayBase)):
  55. return space.w_NotImplemented
  56. if comp_op == EQ and arr1.len != arr2.len:
  57. return space.w_False
  58. if comp_op == NE and arr1.len != arr2.len:
  59. return space.w_True
  60. lgt = min(arr1.len, arr2.len)
  61. for i in range(lgt):
  62. arr_eq_driver.jit_merge_point(comp_func=comp_op)
  63. w_elem1 = arr1.w_getitem(space, i)
  64. w_elem2 = arr2.w_getitem(space, i)
  65. if comp_op == EQ:
  66. res = space.is_true(space.eq(w_elem1, w_elem2))
  67. if not res:
  68. return space.w_False
  69. elif comp_op == NE:
  70. res = space.is_true(space.ne(w_elem1, w_elem2))
  71. if res:
  72. return space.w_True
  73. elif comp_op == LT or comp_op == GT:
  74. if comp_op == LT:
  75. res = space.is_true(space.lt(w_elem1, w_elem2))
  76. else:
  77. res = space.is_true(space.gt(w_elem1, w_elem2))
  78. if res:
  79. return space.w_True
  80. elif not space.is_true(space.eq(w_elem1, w_elem2)):
  81. return space.w_False
  82. else:
  83. if comp_op == LE:
  84. res = space.is_true(space.le(w_elem1, w_elem2))
  85. else:
  86. res = space.is_true(space.ge(w_elem1, w_elem2))
  87. if not res:
  88. return space.w_False
  89. elif not space.is_true(space.eq(w_elem1, w_elem2)):
  90. return space.w_True
  91. # we have some leftovers
  92. if comp_op == EQ:
  93. return space.w_True
  94. elif comp_op == NE:
  95. return space.w_False
  96. if arr1.len == arr2.len:
  97. if comp_op == LT or comp_op == GT:
  98. return space.w_False
  99. return space.w_True
  100. if comp_op == LT or comp_op == LE:
  101. if arr1.len < arr2.len:
  102. return space.w_True
  103. return space.w_False
  104. if arr1.len > arr2.len:
  105. return space.w_True
  106. return space.w_False
  107. UNICODE_ARRAY = lltype.Ptr(lltype.Array(lltype.UniChar,
  108. hints={'nolength': True}))
  109. class W_ArrayBase(W_Root):
  110. _attrs_ = ('space', 'len', 'allocated', '_lifeline_') # no buffer
  111. def __init__(self, space):
  112. self.space = space
  113. self.len = 0
  114. self.allocated = 0
  115. def readbuf_w(self, space):
  116. return ArrayBuffer(self, True)
  117. def writebuf_w(self, space):
  118. return ArrayBuffer(self, False)
  119. def descr_append(self, space, w_x):
  120. """ append(x)
  121. Append new value x to the end of the array.
  122. """
  123. raise NotImplementedError
  124. def descr_extend(self, space, w_x):
  125. """ extend(array or iterable)
  126. Append items to the end of the array.
  127. """
  128. self.extend(w_x)
  129. def descr_count(self, space, w_val):
  130. """ count(x)
  131. Return number of occurrences of x in the array.
  132. """
  133. raise NotImplementedError
  134. def descr_index(self, space, w_x):
  135. """ index(x)
  136. Return index of first occurrence of x in the array.
  137. """
  138. raise NotImplementedError
  139. def descr_reverse(self, space):
  140. """ reverse()
  141. Reverse the order of the items in the array.
  142. """
  143. raise NotImplementedError
  144. def descr_remove(self, space, w_val):
  145. """ remove(x)
  146. Remove the first occurrence of x in the array.
  147. """
  148. raise NotImplementedError
  149. @unwrap_spec(i=int)
  150. def descr_pop(self, space, i=-1):
  151. """ pop([i])
  152. Return the i-th element and delete it from the array. i defaults to -1.
  153. """
  154. raise NotImplementedError
  155. @unwrap_spec(idx=int)
  156. def descr_insert(self, space, idx, w_val):
  157. """ insert(i,x)
  158. Insert a new item x into the array before position i.
  159. """
  160. raise NotImplementedError
  161. def descr_tolist(self, space):
  162. """ tolist() -> list
  163. Convert array to an ordinary list with the same items.
  164. """
  165. w_l = space.newlist([])
  166. for i in range(self.len):
  167. w_l.append(self.w_getitem(space, i))
  168. return w_l
  169. def descr_fromlist(self, space, w_lst):
  170. """ fromlist(list)
  171. Append items to array from list.
  172. """
  173. if not space.isinstance_w(w_lst, space.w_list):
  174. raise oefmt(space.w_TypeError, "arg must be list")
  175. s = self.len
  176. try:
  177. self.fromsequence(w_lst)
  178. except OperationError:
  179. self.setlen(s)
  180. raise
  181. def descr_tostring(self, space):
  182. """ tostring() -> string
  183. Convert the array to an array of machine values and return the string
  184. representation.
  185. """
  186. size = self.len
  187. if size == 0:
  188. return space.newbytes('')
  189. cbuf = self._charbuf_start()
  190. s = rffi.charpsize2str(cbuf, size * self.itemsize)
  191. self._charbuf_stop()
  192. return self.space.newbytes(s)
  193. def descr_fromstring(self, space, w_s):
  194. """ fromstring(string)
  195. Appends items from the string, interpreting it as an array of machine
  196. values,as if it had been read from a file using the fromfile() method).
  197. """
  198. s = space.getarg_w('s#', w_s)
  199. if len(s) % self.itemsize != 0:
  200. raise oefmt(self.space.w_ValueError,
  201. "string length not a multiple of item size")
  202. oldlen = self.len
  203. new = len(s) / self.itemsize
  204. if not new:
  205. return
  206. self.setlen(oldlen + new)
  207. cbuf = self._charbuf_start()
  208. copy_string_to_raw(llstr(s), rffi.ptradd(cbuf, oldlen * self.itemsize),
  209. 0, len(s))
  210. self._charbuf_stop()
  211. @unwrap_spec(w_f=W_File, n=int)
  212. def descr_fromfile(self, space, w_f, n):
  213. """ fromfile(f, n)
  214. Read n objects from the file object f and append them to the end of the
  215. array. Also called as read.
  216. """
  217. try:
  218. size = ovfcheck(self.itemsize * n)
  219. except OverflowError:
  220. raise MemoryError
  221. w_item = space.call_method(w_f, 'read', space.wrap(size))
  222. item = space.bytes_w(w_item)
  223. if len(item) < size:
  224. n = len(item) % self.itemsize
  225. elems = max(0, len(item) - (len(item) % self.itemsize))
  226. if n != 0:
  227. item = item[0:elems]
  228. self.descr_fromstring(space, space.wrap(item))
  229. raise oefmt(space.w_EOFError, "not enough items in file")
  230. self.descr_fromstring(space, w_item)
  231. @unwrap_spec(w_f=W_File)
  232. def descr_tofile(self, space, w_f):
  233. """ tofile(f)
  234. Write all items (as machine values) to the file object f. Also
  235. called as write.
  236. """
  237. w_s = self.descr_tostring(space)
  238. space.call_method(w_f, 'write', w_s)
  239. def descr_fromunicode(self, space, w_ustr):
  240. """ fromunicode(ustr)
  241. Extends this array with data from the unicode string ustr.
  242. The array must be a type 'u' array; otherwise a ValueError
  243. is raised. Use array.fromstring(ustr.decode(...)) to
  244. append Unicode data to an array of some other type.
  245. """
  246. # XXX the following probable bug is not emulated:
  247. # CPython accepts a non-unicode string or a buffer, and then
  248. # behaves just like fromstring(), except that it strangely truncate
  249. # string arguments at multiples of the unicode byte size.
  250. # Let's only accept unicode arguments for now.
  251. if self.typecode == 'u':
  252. self.fromsequence(w_ustr)
  253. else:
  254. raise oefmt(space.w_ValueError,
  255. "fromunicode() may only be called on type 'u' arrays")
  256. def descr_tounicode(self, space):
  257. """ tounicode() -> unicode
  258. Convert the array to a unicode string. The array must be
  259. a type 'u' array; otherwise a ValueError is raised. Use
  260. array.tostring().decode() to obtain a unicode string from
  261. an array of some other type.
  262. """
  263. if self.typecode == 'u':
  264. buf = rffi.cast(UNICODE_ARRAY, self._buffer_as_unsigned())
  265. return space.wrap(rffi.wcharpsize2unicode(buf, self.len))
  266. else:
  267. raise oefmt(space.w_ValueError,
  268. "tounicode() may only be called on type 'u' arrays")
  269. def descr_buffer_info(self, space):
  270. """ buffer_info() -> (address, length)
  271. Return a tuple (address, length) giving the current memory address and
  272. the length in items of the buffer used to hold array's contents
  273. The length should be multiplied by the itemsize attribute to calculate
  274. the buffer length in bytes.
  275. """
  276. w_ptr = space.wrap(self._buffer_as_unsigned())
  277. w_len = space.wrap(self.len)
  278. return space.newtuple([w_ptr, w_len])
  279. def descr_reduce(self, space):
  280. """ Return state information for pickling.
  281. """
  282. if self.len > 0:
  283. w_s = self.descr_tostring(space)
  284. args = [space.wrap(self.typecode), w_s]
  285. else:
  286. args = [space.wrap(self.typecode)]
  287. try:
  288. w_dict = space.getattr(self, space.wrap('__dict__'))
  289. except OperationError:
  290. w_dict = space.w_None
  291. return space.newtuple([space.type(self), space.newtuple(args), w_dict])
  292. def descr_copy(self, space):
  293. """ copy(array)
  294. Return a copy of the array.
  295. """
  296. w_a = self.constructor(self.space)
  297. w_a.setlen(self.len, overallocate=False)
  298. rffi.c_memcpy(
  299. rffi.cast(rffi.VOIDP, w_a._buffer_as_unsigned()),
  300. rffi.cast(rffi.VOIDP, self._buffer_as_unsigned()),
  301. self.len * self.itemsize
  302. )
  303. return w_a
  304. def descr_byteswap(self, space):
  305. """ byteswap()
  306. Byteswap all items of the array. If the items in the array are
  307. not 1, 2, 4, or 8 bytes in size, RuntimeError is raised.
  308. """
  309. if self.itemsize not in [1, 2, 4, 8]:
  310. raise oefmt(space.w_RuntimeError,
  311. "byteswap not supported for this array")
  312. if self.len == 0:
  313. return
  314. bytes = self._charbuf_start()
  315. tmp = [bytes[0]] * self.itemsize
  316. for start in range(0, self.len * self.itemsize, self.itemsize):
  317. stop = start + self.itemsize - 1
  318. for i in range(self.itemsize):
  319. tmp[i] = bytes[start + i]
  320. for i in range(self.itemsize):
  321. bytes[stop - i] = tmp[i]
  322. self._charbuf_stop()
  323. def descr_len(self, space):
  324. return space.wrap(self.len)
  325. def descr_eq(self, space, w_arr2):
  326. "x.__eq__(y) <==> x==y"
  327. return compare_arrays(space, self, w_arr2, EQ)
  328. def descr_ne(self, space, w_arr2):
  329. "x.__ne__(y) <==> x!=y"
  330. return compare_arrays(space, self, w_arr2, NE)
  331. def descr_lt(self, space, w_arr2):
  332. "x.__lt__(y) <==> x<y"
  333. return compare_arrays(space, self, w_arr2, LT)
  334. def descr_le(self, space, w_arr2):
  335. "x.__le__(y) <==> x<=y"
  336. return compare_arrays(space, self, w_arr2, LE)
  337. def descr_gt(self, space, w_arr2):
  338. "x.__gt__(y) <==> x>y"
  339. return compare_arrays(space, self, w_arr2, GT)
  340. def descr_ge(self, space, w_arr2):
  341. "x.__ge__(y) <==> x>=y"
  342. return compare_arrays(space, self, w_arr2, GE)
  343. # Basic get/set/append/extend methods
  344. def descr_getitem(self, space, w_idx):
  345. "x.__getitem__(y) <==> x[y]"
  346. if not space.isinstance_w(w_idx, space.w_slice):
  347. idx, stop, step = space.decode_index(w_idx, self.len)
  348. assert step == 0
  349. return self.w_getitem(space, idx)
  350. else:
  351. return self.getitem_slice(space, w_idx)
  352. def descr_getslice(self, space, w_i, w_j):
  353. return space.getitem(self, space.newslice(w_i, w_j, space.w_None))
  354. def descr_setitem(self, space, w_idx, w_item):
  355. "x.__setitem__(i, y) <==> x[i]=y"
  356. if space.isinstance_w(w_idx, space.w_slice):
  357. self.setitem_slice(space, w_idx, w_item)
  358. else:
  359. self.setitem(space, w_idx, w_item)
  360. def descr_setslice(self, space, w_start, w_stop, w_item):
  361. self.setitem_slice(space,
  362. space.newslice(w_start, w_stop, space.w_None),
  363. w_item)
  364. def descr_delitem(self, space, w_idx):
  365. start, stop, step, size = self.space.decode_index4(w_idx, self.len)
  366. if step != 1:
  367. # I don't care about efficiency of that so far
  368. w_lst = self.descr_tolist(space)
  369. space.delitem(w_lst, w_idx)
  370. self.setlen(0)
  371. self.fromsequence(w_lst)
  372. return
  373. return self.delitem(space, start, stop)
  374. def descr_delslice(self, space, w_start, w_stop):
  375. self.descr_delitem(space, space.newslice(w_start, w_stop,
  376. space.w_None))
  377. def descr_iter(self, space):
  378. return space.newseqiter(self)
  379. def descr_add(self, space, w_other):
  380. raise NotImplementedError
  381. def descr_inplace_add(self, space, w_other):
  382. raise NotImplementedError
  383. def descr_mul(self, space, w_repeat):
  384. raise NotImplementedError
  385. def descr_inplace_mul(self, space, w_repeat):
  386. raise NotImplementedError
  387. def descr_radd(self, space, w_other):
  388. return self.descr_add(space, w_other)
  389. def descr_rmul(self, space, w_repeat):
  390. return self.descr_mul(space, w_repeat)
  391. # Misc methods
  392. def descr_repr(self, space):
  393. if self.len == 0:
  394. return space.wrap("array('%s')" % self.typecode)
  395. elif self.typecode == "c":
  396. r = space.repr(self.descr_tostring(space))
  397. s = "array('%s', %s)" % (self.typecode, space.str_w(r))
  398. return space.wrap(s)
  399. elif self.typecode == "u":
  400. r = space.repr(self.descr_tounicode(space))
  401. s = "array('%s', %s)" % (self.typecode, space.str_w(r))
  402. return space.wrap(s)
  403. else:
  404. r = space.repr(self.descr_tolist(space))
  405. s = "array('%s', %s)" % (self.typecode, space.str_w(r))
  406. return space.wrap(s)
  407. W_ArrayBase.typedef = TypeDef(
  408. 'array.array',
  409. __new__ = interp2app(w_array),
  410. __len__ = interp2app(W_ArrayBase.descr_len),
  411. __eq__ = interp2app(W_ArrayBase.descr_eq),
  412. __ne__ = interp2app(W_ArrayBase.descr_ne),
  413. __lt__ = interp2app(W_ArrayBase.descr_lt),
  414. __le__ = interp2app(W_ArrayBase.descr_le),
  415. __gt__ = interp2app(W_ArrayBase.descr_gt),
  416. __ge__ = interp2app(W_ArrayBase.descr_ge),
  417. __getitem__ = interp2app(W_ArrayBase.descr_getitem),
  418. __getslice__ = interp2app(W_ArrayBase.descr_getslice),
  419. __setitem__ = interp2app(W_ArrayBase.descr_setitem),
  420. __setslice__ = interp2app(W_ArrayBase.descr_setslice),
  421. __delitem__ = interp2app(W_ArrayBase.descr_delitem),
  422. __delslice__ = interp2app(W_ArrayBase.descr_delslice),
  423. __iter__ = interp2app(W_ArrayBase.descr_iter),
  424. __add__ = interpindirect2app(W_ArrayBase.descr_add),
  425. __iadd__ = interpindirect2app(W_ArrayBase.descr_inplace_add),
  426. __mul__ = interpindirect2app(W_ArrayBase.descr_mul),
  427. __imul__ = interpindirect2app(W_ArrayBase.descr_inplace_mul),
  428. __radd__ = interp2app(W_ArrayBase.descr_radd),
  429. __rmul__ = interp2app(W_ArrayBase.descr_rmul),
  430. __repr__ = interp2app(W_ArrayBase.descr_repr),
  431. itemsize = GetSetProperty(descr_itemsize),
  432. typecode = GetSetProperty(descr_typecode),
  433. __weakref__ = make_weakref_descr(W_ArrayBase),
  434. append = interpindirect2app(W_ArrayBase.descr_append),
  435. extend = interp2app(W_ArrayBase.descr_extend),
  436. count = interpindirect2app(W_ArrayBase.descr_count),
  437. index = interpindirect2app(W_ArrayBase.descr_index),
  438. reverse = interpindirect2app(W_ArrayBase.descr_reverse),
  439. remove = interpindirect2app(W_ArrayBase.descr_remove),
  440. pop = interpindirect2app(W_ArrayBase.descr_pop),
  441. insert = interpindirect2app(W_ArrayBase.descr_insert),
  442. tolist = interp2app(W_ArrayBase.descr_tolist),
  443. fromlist = interp2app(W_ArrayBase.descr_fromlist),
  444. tostring = interp2app(W_ArrayBase.descr_tostring),
  445. fromstring = interp2app(W_ArrayBase.descr_fromstring),
  446. tofile = interp2app(W_ArrayBase.descr_tofile),
  447. fromfile = interp2app(W_ArrayBase.descr_fromfile),
  448. fromunicode = interp2app(W_ArrayBase.descr_fromunicode),
  449. tounicode = interp2app(W_ArrayBase.descr_tounicode),
  450. buffer_info = interp2app(W_ArrayBase.descr_buffer_info),
  451. __copy__ = interp2app(W_ArrayBase.descr_copy),
  452. __reduce__ = interp2app(W_ArrayBase.descr_reduce),
  453. byteswap = interp2app(W_ArrayBase.descr_byteswap),
  454. )
  455. class TypeCode(object):
  456. def __init__(self, itemtype, unwrap, canoverflow=False, signed=False,
  457. method='__int__'):
  458. self.itemtype = itemtype
  459. self.bytes = rffi.sizeof(itemtype)
  460. self.arraytype = lltype.Array(itemtype, hints={'nolength': True})
  461. self.unwrap = unwrap
  462. self.signed = signed
  463. self.canoverflow = canoverflow
  464. self.w_class = None
  465. self.method = method
  466. def _freeze_(self):
  467. # hint for the annotator: track individual constant instances
  468. return True
  469. if rffi.sizeof(rffi.UINT) == rffi.sizeof(rffi.ULONG):
  470. # 32 bits: UINT can't safely overflow into a C long (rpython int)
  471. # via int_w, handle it like ULONG below
  472. _UINTTypeCode = \
  473. TypeCode(rffi.UINT, 'bigint_w')
  474. else:
  475. _UINTTypeCode = \
  476. TypeCode(rffi.UINT, 'int_w', True)
  477. types = {
  478. 'c': TypeCode(lltype.Char, 'str_w', method=''),
  479. 'u': TypeCode(lltype.UniChar, 'unicode_w', method=''),
  480. 'b': TypeCode(rffi.SIGNEDCHAR, 'int_w', True, True),
  481. 'B': TypeCode(rffi.UCHAR, 'int_w', True),
  482. 'h': TypeCode(rffi.SHORT, 'int_w', True, True),
  483. 'H': TypeCode(rffi.USHORT, 'int_w', True),
  484. 'i': TypeCode(rffi.INT, 'int_w', True, True),
  485. 'I': _UINTTypeCode,
  486. 'l': TypeCode(rffi.LONG, 'int_w', True, True),
  487. 'L': TypeCode(rffi.ULONG, 'bigint_w'), # Overflow handled by
  488. # rbigint.touint() which
  489. # corresponds to the
  490. # C-type unsigned long
  491. 'f': TypeCode(lltype.SingleFloat, 'float_w', method='__float__'),
  492. 'd': TypeCode(lltype.Float, 'float_w', method='__float__'),
  493. }
  494. for k, v in types.items():
  495. v.typecode = k
  496. unroll_typecodes = unrolling_iterable(types.keys())
  497. class ArrayBuffer(Buffer):
  498. _immutable_ = True
  499. def __init__(self, array, readonly):
  500. self.array = array
  501. self.readonly = readonly
  502. def getlength(self):
  503. return self.array.len * self.array.itemsize
  504. def getitem(self, index):
  505. array = self.array
  506. data = array._charbuf_start()
  507. char = data[index]
  508. array._charbuf_stop()
  509. return char
  510. def setitem(self, index, char):
  511. array = self.array
  512. data = array._charbuf_start()
  513. data[index] = char
  514. array._charbuf_stop()
  515. def getslice(self, start, stop, step, size):
  516. if size == 0:
  517. return ''
  518. if step == 1:
  519. data = self.array._charbuf_start()
  520. try:
  521. return rffi.charpsize2str(rffi.ptradd(data, start), size)
  522. finally:
  523. self.array._charbuf_stop()
  524. return Buffer.getslice(self, start, stop, step, size)
  525. def get_raw_address(self):
  526. return self.array._charbuf_start()
  527. def make_array(mytype):
  528. W_ArrayBase = globals()['W_ArrayBase']
  529. unpack_driver = jit.JitDriver(name='unpack_array',
  530. greens=['tp'],
  531. reds=['self', 'w_iterator'])
  532. class W_Array(W_ArrayBase):
  533. itemsize = mytype.bytes
  534. typecode = mytype.typecode
  535. _attrs_ = ('space', 'len', 'allocated', '_lifeline_', 'buffer')
  536. def __init__(self, space):
  537. W_ArrayBase.__init__(self, space)
  538. self.buffer = lltype.nullptr(mytype.arraytype)
  539. def item_w(self, w_item):
  540. space = self.space
  541. unwrap = getattr(space, mytype.unwrap)
  542. try:
  543. item = unwrap(w_item)
  544. except OperationError as e:
  545. if space.isinstance_w(w_item, space.w_float):
  546. # Odd special case from cpython
  547. raise
  548. if mytype.method != '' and e.match(space, space.w_TypeError):
  549. try:
  550. item = unwrap(space.call_method(w_item, mytype.method))
  551. except OperationError:
  552. raise oefmt(space.w_TypeError,
  553. "array item must be " + mytype.unwrap[:-2])
  554. else:
  555. raise
  556. if mytype.unwrap == 'bigint_w':
  557. try:
  558. item = item.touint()
  559. except (ValueError, OverflowError):
  560. raise oefmt(space.w_OverflowError,
  561. "unsigned %d-byte integer out of range",
  562. mytype.bytes)
  563. return rffi.cast(mytype.itemtype, item)
  564. if mytype.unwrap == 'str_w' or mytype.unwrap == 'unicode_w':
  565. if len(item) != 1:
  566. raise oefmt(space.w_TypeError, "array item must be char")
  567. item = item[0]
  568. return rffi.cast(mytype.itemtype, item)
  569. #
  570. # "regular" case: it fits in an rpython integer (lltype.Signed)
  571. # or it is a float
  572. return self.item_from_int_or_float(item)
  573. def item_from_int_or_float(self, item):
  574. result = rffi.cast(mytype.itemtype, item)
  575. if mytype.canoverflow:
  576. if rffi.cast(lltype.Signed, result) != item:
  577. # overflow. build the correct message
  578. if item < 0:
  579. msg = ('signed %d-byte integer is less than minimum' %
  580. mytype.bytes)
  581. else:
  582. msg = ('signed %d-byte integer is greater than maximum'
  583. % mytype.bytes)
  584. if not mytype.signed:
  585. msg = 'un' + msg # 'signed' => 'unsigned'
  586. raise OperationError(self.space.w_OverflowError,
  587. self.space.wrap(msg))
  588. return result
  589. @rgc.must_be_light_finalizer
  590. def __del__(self):
  591. if self.buffer:
  592. lltype.free(self.buffer, flavor='raw')
  593. def setlen(self, size, zero=False, overallocate=True):
  594. if size > 0:
  595. if size > self.allocated or size < self.allocated / 2:
  596. if overallocate:
  597. if size < 9:
  598. some = 3
  599. else:
  600. some = 6
  601. some += size >> 3
  602. else:
  603. some = 0
  604. self.allocated = size + some
  605. if zero:
  606. new_buffer = lltype.malloc(
  607. mytype.arraytype, self.allocated, flavor='raw',
  608. add_memory_pressure=True, zero=True)
  609. else:
  610. new_buffer = lltype.malloc(
  611. mytype.arraytype, self.allocated, flavor='raw',
  612. add_memory_pressure=True)
  613. for i in range(min(size, self.len)):
  614. new_buffer[i] = self.buffer[i]
  615. else:
  616. self.len = size
  617. return
  618. else:
  619. assert size == 0
  620. self.allocated = 0
  621. new_buffer = lltype.nullptr(mytype.arraytype)
  622. if self.buffer:
  623. lltype.free(self.buffer, flavor='raw')
  624. self.buffer = new_buffer
  625. self.len = size
  626. def fromsequence(self, w_seq):
  627. space = self.space
  628. oldlen = self.len
  629. newlen = oldlen
  630. # optimized case for arrays of integers or floats
  631. if mytype.unwrap == 'int_w':
  632. lst = space.listview_int(w_seq)
  633. elif mytype.unwrap == 'float_w':
  634. lst = space.listview_float(w_seq)
  635. else:
  636. lst = None
  637. if lst is not None:
  638. self.setlen(oldlen + len(lst))
  639. try:
  640. buf = self.buffer
  641. for num in lst:
  642. buf[newlen] = self.item_from_int_or_float(num)
  643. newlen += 1
  644. except OperationError:
  645. self.setlen(newlen)
  646. raise
  647. return
  648. # this is the common case: w_seq is a list or a tuple
  649. lst_w = space.listview_no_unpack(w_seq)
  650. if lst_w is not None:
  651. self.setlen(oldlen + len(lst_w))
  652. buf = self.buffer
  653. try:
  654. for w_num in lst_w:
  655. # note: self.item_w() might invoke arbitrary code.
  656. # In case it resizes the same array, then strange
  657. # things may happen, but as we don't reload 'buf'
  658. # we know that one is big enough for all items
  659. # (so at least we avoid crashes)
  660. buf[newlen] = self.item_w(w_num)
  661. newlen += 1
  662. except OperationError:
  663. if buf == self.buffer:
  664. self.setlen(newlen)
  665. raise
  666. return
  667. self._fromiterable(w_seq)
  668. def _fromiterable(self, w_seq):
  669. # a more careful case if w_seq happens to be a very large
  670. # iterable: don't copy the items into some intermediate list
  671. w_iterator = self.space.iter(w_seq)
  672. tp = self.space.type(w_iterator)
  673. while True:
  674. unpack_driver.jit_merge_point(tp=tp, self=self,
  675. w_iterator=w_iterator)
  676. space = self.space
  677. try:
  678. w_item = space.next(w_iterator)
  679. except OperationError as e:
  680. if not e.match(space, space.w_StopIteration):
  681. raise
  682. break # done
  683. self.descr_append(space, w_item)
  684. def extend(self, w_iterable, accept_different_array=False):
  685. space = self.space
  686. if isinstance(w_iterable, W_Array):
  687. oldlen = self.len
  688. new = w_iterable.len
  689. self.setlen(self.len + new)
  690. i = 0
  691. while i < new:
  692. if oldlen + i >= self.len:
  693. self.setlen(oldlen + i + 1)
  694. self.buffer[oldlen + i] = w_iterable.buffer[i]
  695. i += 1
  696. self.setlen(oldlen + i)
  697. elif (not accept_different_array
  698. and isinstance(w_iterable, W_ArrayBase)):
  699. raise oefmt(space.w_TypeError,
  700. "can only extend with array of same kind")
  701. else:
  702. self.fromsequence(w_iterable)
  703. def _charbuf_start(self):
  704. return rffi.cast(rffi.CCHARP, self.buffer)
  705. def _buffer_as_unsigned(self):
  706. return rffi.cast(lltype.Unsigned, self.buffer)
  707. def _charbuf_stop(self):
  708. keepalive_until_here(self)
  709. def w_getitem(self, space, idx):
  710. item = self.buffer[idx]
  711. if mytype.typecode in 'bBhHil':
  712. item = rffi.cast(lltype.Signed, item)
  713. elif mytype.typecode == 'f':
  714. item = float(item)
  715. return space.wrap(item)
  716. # interface
  717. def descr_append(self, space, w_x):
  718. x = self.item_w(w_x)
  719. index = self.len
  720. self.setlen(index + 1)
  721. self.buffer[index] = x
  722. # List interface
  723. def descr_count(self, space, w_val):
  724. cnt = 0
  725. for i in range(self.len):
  726. # XXX jitdriver
  727. w_item = self.w_getitem(space, i)
  728. if space.is_true(space.eq(w_item, w_val)):
  729. cnt += 1
  730. return space.wrap(cnt)
  731. def descr_index(self, space, w_val):
  732. for i in range(self.len):
  733. w_item = self.w_getitem(space, i)
  734. if space.is_true(space.eq(w_item, w_val)):
  735. return space.wrap(i)
  736. raise oefmt(space.w_ValueError, "array.index(x): x not in list")
  737. def descr_reverse(self, space):
  738. b = self.buffer
  739. for i in range(self.len / 2):
  740. b[i], b[self.len - i - 1] = b[self.len - i - 1], b[i]
  741. def descr_pop(self, space, i):
  742. if i < 0:
  743. i += self.len
  744. if i < 0 or i >= self.len:
  745. raise oefmt(space.w_IndexError, "pop index out of range")
  746. w_val = self.w_getitem(space, i)
  747. while i < self.len - 1:
  748. self.buffer[i] = self.buffer[i + 1]
  749. i += 1
  750. self.setlen(self.len - 1)
  751. return w_val
  752. def descr_remove(self, space, w_val):
  753. w_idx = self.descr_index(space, w_val)
  754. self.descr_pop(space, space.int_w(w_idx))
  755. def descr_insert(self, space, idx, w_val):
  756. if idx < 0:
  757. idx += self.len
  758. if idx < 0:
  759. idx = 0
  760. if idx > self.len:
  761. idx = self.len
  762. val = self.item_w(w_val)
  763. self.setlen(self.len + 1)
  764. i = self.len - 1
  765. while i > idx:
  766. self.buffer[i] = self.buffer[i - 1]
  767. i -= 1
  768. self.buffer[i] = val
  769. def getitem_slice(self, space, w_idx):
  770. start, stop, step, size = space.decode_index4(w_idx, self.len)
  771. w_a = mytype.w_class(self.space)
  772. w_a.setlen(size, overallocate=False)
  773. assert step != 0
  774. j = 0
  775. for i in range(start, stop, step):
  776. w_a.buffer[j] = self.buffer[i]
  777. j += 1
  778. return w_a
  779. def setitem(self, space, w_idx, w_item):
  780. idx, stop, step = space.decode_index(w_idx, self.len)
  781. if step != 0:
  782. raise oefmt(self.space.w_TypeError,
  783. "can only assign array to array slice")
  784. item = self.item_w(w_item)
  785. self.buffer[idx] = item
  786. def setitem_slice(self, space, w_idx, w_item):
  787. if not isinstance(w_item, W_Array):
  788. raise oefmt(space.w_TypeError,
  789. "can only assign to a slice array")
  790. start, stop, step, size = self.space.decode_index4(w_idx, self.len)
  791. assert step != 0
  792. if w_item.len != size or self is w_item:
  793. # XXX this is a giant slow hack
  794. w_lst = self.descr_tolist(space)
  795. w_item = space.call_method(w_item, 'tolist')
  796. space.setitem(w_lst, w_idx, w_item)
  797. self.setlen(0)
  798. self.fromsequence(w_lst)
  799. else:
  800. j = 0
  801. for i in range(start, stop, step):
  802. self.buffer[i] = w_item.buffer[j]
  803. j += 1
  804. def delitem(self, space, i, j):
  805. if i < 0:
  806. i += self.len
  807. if i < 0:
  808. i = 0
  809. if j < 0:
  810. j += self.len
  811. if j < 0:
  812. j = 0
  813. if j > self.len:
  814. j = self.len
  815. if i >= j:
  816. return None
  817. oldbuffer = self.buffer
  818. self.buffer = lltype.malloc(
  819. mytype.arraytype, max(self.len - (j - i), 0), flavor='raw',
  820. add_memory_pressure=True)
  821. if i:
  822. rffi.c_memcpy(
  823. rffi.cast(rffi.VOIDP, self.buffer),
  824. rffi.cast(rffi.VOIDP, oldbuffer),
  825. i * mytype.bytes
  826. )
  827. if j < self.len:
  828. rffi.c_memcpy(
  829. rffi.cast(rffi.VOIDP, rffi.ptradd(self.buffer, i)),
  830. rffi.cast(rffi.VOIDP, rffi.ptradd(oldbuffer, j)),
  831. (self.len - j) * mytype.bytes
  832. )
  833. self.len -= j - i
  834. self.allocated = self.len
  835. if oldbuffer:
  836. lltype.free(oldbuffer, flavor='raw')
  837. # Add and mul methods
  838. def descr_add(self, space, w_other):
  839. if not isinstance(w_other, W_Array):
  840. return space.w_NotImplemented
  841. a = mytype.w_class(space)
  842. a.setlen(self.len + w_other.len, overallocate=False)
  843. if self.len:
  844. rffi.c_memcpy(
  845. rffi.cast(rffi.VOIDP, a.buffer),
  846. rffi.cast(rffi.VOIDP, self.buffer),
  847. self.len * mytype.bytes
  848. )
  849. if w_other.len:
  850. rffi.c_memcpy(
  851. rffi.cast(rffi.VOIDP, rffi.ptradd(a.buffer, self.len)),
  852. rffi.cast(rffi.VOIDP, w_other.buffer),
  853. w_other.len * mytype.bytes
  854. )
  855. return a
  856. def descr_inplace_add(self, space, w_other):
  857. if not isinstance(w_other, W_Array):
  858. return space.w_NotImplemented
  859. oldlen = self.len
  860. otherlen = w_other.len
  861. self.setlen(oldlen + otherlen)
  862. if otherlen:
  863. rffi.c_memcpy(
  864. rffi.cast(rffi.VOIDP, rffi.ptradd(self.buffer, oldlen)),
  865. rffi.cast(rffi.VOIDP, w_other.buffer),
  866. otherlen * mytype.bytes
  867. )
  868. return self
  869. def descr_mul(self, space, w_repeat):
  870. return _mul_helper(space, self, w_repeat, False)
  871. def descr_inplace_mul(self, space, w_repeat):
  872. return _mul_helper(space, self, w_repeat, True)
  873. def _mul_helper(space, self, w_repeat, is_inplace):
  874. try:
  875. repeat = space.getindex_w(w_repeat, space.w_OverflowError)
  876. except OperationError as e:
  877. if e.match(space, space.w_TypeError):
  878. return space.w_NotImplemented
  879. raise
  880. repeat = max(repeat, 0)
  881. try:
  882. newlen = ovfcheck(self.len * repeat)
  883. except OverflowError:
  884. raise MemoryError
  885. oldlen = self.len
  886. if is_inplace:
  887. a = self
  888. start = 1
  889. else:
  890. a = mytype.w_class(space)
  891. start = 0
  892. # <a performance hack>
  893. if oldlen == 1:
  894. if mytype.unwrap == 'str_w' or mytype.unwrap == 'unicode_w':
  895. zero = not ord(self.buffer[0])
  896. elif mytype.unwrap == 'int_w' or mytype.unwrap == 'bigint_w':
  897. zero = not widen(self.buffer[0])
  898. #elif mytype.unwrap == 'float_w':
  899. # value = ...float(self.buffer[0]) xxx handle the case of -0.0
  900. else:
  901. zero = False
  902. if zero:
  903. a.setlen(newlen, zero=True, overallocate=False)
  904. return a
  905. a.setlen(newlen, overallocate=False)
  906. item = self.buffer[0]
  907. for r in range(start, repeat):
  908. a.buffer[r] = item
  909. return a
  910. # </a performance hack>
  911. a.setlen(newlen, overallocate=False)
  912. for r in range(start, repeat):
  913. for i in range(oldlen):
  914. a.buffer[r * oldlen + i] = self.buffer[i]
  915. return a
  916. mytype.w_class = W_Array
  917. W_Array.constructor = W_Array
  918. name = 'ArrayType' + mytype.typecode
  919. W_Array.__name__ = 'W_' + name
  920. for mytype in types.values():
  921. make_array(mytype)
  922. del mytype