PageRenderTime 46ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/lib_pypy/_collections.py

https://bitbucket.org/pypy/pypy/
Python | 434 lines | 340 code | 55 blank | 39 comment | 94 complexity | f883214908ff1a5a66aa8a59e31a3e9a MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
  1. """High performance data structures
  2. """
  3. #
  4. # Copied and completed from the sandbox of CPython
  5. # (nondist/sandbox/collections/pydeque.py rev 1.1, Raymond Hettinger)
  6. #
  7. # Note that PyPy also contains a built-in module '_collections' which will hide
  8. # this one if compiled in.
  9. try:
  10. from threading import _get_ident as _thread_ident
  11. except ImportError:
  12. def _thread_ident():
  13. return -1
  14. n = 30
  15. LFTLNK = n
  16. RGTLNK = n+1
  17. BLOCKSIZ = n+2
  18. # The deque's size limit is d.maxlen. The limit can be zero or positive, or
  19. # None. After an item is added to a deque, we check to see if the size has
  20. # grown past the limit. If it has, we get the size back down to the limit by
  21. # popping an item off of the opposite end. The methods that can trigger this
  22. # are append(), appendleft(), extend(), and extendleft().
  23. class deque(object):
  24. def __new__(cls, iterable=(), *args, **kw):
  25. self = super(deque, cls).__new__(cls, *args, **kw)
  26. self.clear()
  27. return self
  28. def __init__(self, iterable=(), maxlen=None):
  29. self.clear()
  30. if maxlen is not None:
  31. if maxlen < 0:
  32. raise ValueError("maxlen must be non-negative")
  33. self._maxlen = maxlen
  34. add = self.append
  35. for elem in iterable:
  36. add(elem)
  37. @property
  38. def maxlen(self):
  39. return self._maxlen
  40. def clear(self):
  41. self.right = self.left = [None] * BLOCKSIZ
  42. self.rightndx = n//2 # points to last written element
  43. self.leftndx = n//2+1
  44. self.length = 0
  45. self.state = 0
  46. def append(self, x):
  47. self.state += 1
  48. self.rightndx += 1
  49. if self.rightndx == n:
  50. newblock = [None] * BLOCKSIZ
  51. self.right[RGTLNK] = newblock
  52. newblock[LFTLNK] = self.right
  53. self.right = newblock
  54. self.rightndx = 0
  55. self.length += 1
  56. self.right[self.rightndx] = x
  57. if self.maxlen is not None and self.length > self.maxlen:
  58. self.popleft()
  59. def appendleft(self, x):
  60. self.state += 1
  61. self.leftndx -= 1
  62. if self.leftndx == -1:
  63. newblock = [None] * BLOCKSIZ
  64. self.left[LFTLNK] = newblock
  65. newblock[RGTLNK] = self.left
  66. self.left = newblock
  67. self.leftndx = n-1
  68. self.length += 1
  69. self.left[self.leftndx] = x
  70. if self.maxlen is not None and self.length > self.maxlen:
  71. self.pop()
  72. def extend(self, iterable):
  73. if iterable is self:
  74. iterable = list(iterable)
  75. for elem in iterable:
  76. self.append(elem)
  77. def extendleft(self, iterable):
  78. if iterable is self:
  79. iterable = list(iterable)
  80. for elem in iterable:
  81. self.appendleft(elem)
  82. def pop(self):
  83. if self.left is self.right and self.leftndx > self.rightndx:
  84. raise IndexError("pop from an empty deque")
  85. x = self.right[self.rightndx]
  86. self.right[self.rightndx] = None
  87. self.length -= 1
  88. self.rightndx -= 1
  89. self.state += 1
  90. if self.rightndx == -1:
  91. prevblock = self.right[LFTLNK]
  92. if prevblock is None:
  93. # the deque has become empty; recenter instead of freeing block
  94. self.rightndx = n//2
  95. self.leftndx = n//2+1
  96. else:
  97. prevblock[RGTLNK] = None
  98. self.right[LFTLNK] = None
  99. self.right = prevblock
  100. self.rightndx = n-1
  101. return x
  102. def popleft(self):
  103. if self.left is self.right and self.leftndx > self.rightndx:
  104. raise IndexError("pop from an empty deque")
  105. x = self.left[self.leftndx]
  106. self.left[self.leftndx] = None
  107. self.length -= 1
  108. self.leftndx += 1
  109. self.state += 1
  110. if self.leftndx == n:
  111. prevblock = self.left[RGTLNK]
  112. if prevblock is None:
  113. # the deque has become empty; recenter instead of freeing block
  114. self.rightndx = n//2
  115. self.leftndx = n//2+1
  116. else:
  117. prevblock[LFTLNK] = None
  118. self.left[RGTLNK] = None
  119. self.left = prevblock
  120. self.leftndx = 0
  121. return x
  122. def count(self, value):
  123. c = 0
  124. for item in self:
  125. if item == value:
  126. c += 1
  127. return c
  128. def remove(self, value):
  129. # Need to defend mutating or failing comparisons
  130. i = 0
  131. try:
  132. for i in range(len(self)):
  133. if self[0] == value:
  134. self.popleft()
  135. return
  136. self.append(self.popleft())
  137. i += 1
  138. raise ValueError("deque.remove(x): x not in deque")
  139. finally:
  140. self.rotate(i)
  141. def rotate(self, n=1):
  142. length = len(self)
  143. if length <= 1:
  144. return
  145. halflen = length >> 1
  146. if n > halflen or n < -halflen:
  147. n %= length
  148. if n > halflen:
  149. n -= length
  150. elif n < -halflen:
  151. n += length
  152. while n > 0:
  153. self.appendleft(self.pop())
  154. n -= 1
  155. while n < 0:
  156. self.append(self.popleft())
  157. n += 1
  158. def reverse(self):
  159. "reverse *IN PLACE*"
  160. leftblock = self.left
  161. rightblock = self.right
  162. leftindex = self.leftndx
  163. rightindex = self.rightndx
  164. for i in range(self.length // 2):
  165. # Validate that pointers haven't met in the middle
  166. assert leftblock != rightblock or leftindex < rightindex
  167. # Swap
  168. (rightblock[rightindex], leftblock[leftindex]) = (
  169. leftblock[leftindex], rightblock[rightindex])
  170. # Advance left block/index pair
  171. leftindex += 1
  172. if leftindex == n:
  173. leftblock = leftblock[RGTLNK]
  174. assert leftblock is not None
  175. leftindex = 0
  176. # Step backwards with the right block/index pair
  177. rightindex -= 1
  178. if rightindex == -1:
  179. rightblock = rightblock[LFTLNK]
  180. assert rightblock is not None
  181. rightindex = n - 1
  182. def __repr__(self):
  183. threadlocalattr = '__repr' + str(_thread_ident())
  184. if threadlocalattr in self.__dict__:
  185. return 'deque([...])'
  186. else:
  187. self.__dict__[threadlocalattr] = True
  188. try:
  189. if self.maxlen is not None:
  190. return 'deque(%r, maxlen=%s)' % (list(self), self.maxlen)
  191. else:
  192. return 'deque(%r)' % (list(self),)
  193. finally:
  194. del self.__dict__[threadlocalattr]
  195. def __iter__(self):
  196. return deque_iterator(self, self._iter_impl)
  197. def _iter_impl(self, original_state, giveup):
  198. if self.state != original_state:
  199. giveup()
  200. block = self.left
  201. while block:
  202. l, r = 0, n
  203. if block is self.left:
  204. l = self.leftndx
  205. if block is self.right:
  206. r = self.rightndx + 1
  207. for elem in block[l:r]:
  208. yield elem
  209. if self.state != original_state:
  210. giveup()
  211. block = block[RGTLNK]
  212. def __reversed__(self):
  213. return deque_iterator(self, self._reversed_impl)
  214. def _reversed_impl(self, original_state, giveup):
  215. if self.state != original_state:
  216. giveup()
  217. block = self.right
  218. while block:
  219. l, r = 0, n
  220. if block is self.left:
  221. l = self.leftndx
  222. if block is self.right:
  223. r = self.rightndx + 1
  224. for elem in reversed(block[l:r]):
  225. yield elem
  226. if self.state != original_state:
  227. giveup()
  228. block = block[LFTLNK]
  229. def __len__(self):
  230. #sum = 0
  231. #block = self.left
  232. #while block:
  233. # sum += n
  234. # block = block[RGTLNK]
  235. #return sum + self.rightndx - self.leftndx + 1 - n
  236. return self.length
  237. def __getref(self, index):
  238. if index >= 0:
  239. block = self.left
  240. while block:
  241. l, r = 0, n
  242. if block is self.left:
  243. l = self.leftndx
  244. if block is self.right:
  245. r = self.rightndx + 1
  246. span = r-l
  247. if index < span:
  248. return block, l+index
  249. index -= span
  250. block = block[RGTLNK]
  251. else:
  252. block = self.right
  253. while block:
  254. l, r = 0, n
  255. if block is self.left:
  256. l = self.leftndx
  257. if block is self.right:
  258. r = self.rightndx + 1
  259. negative_span = l-r
  260. if index >= negative_span:
  261. return block, r+index
  262. index -= negative_span
  263. block = block[LFTLNK]
  264. raise IndexError("deque index out of range")
  265. def __getitem__(self, index):
  266. block, index = self.__getref(index)
  267. return block[index]
  268. def __setitem__(self, index, value):
  269. block, index = self.__getref(index)
  270. block[index] = value
  271. def __delitem__(self, index):
  272. length = len(self)
  273. if index >= 0:
  274. if index >= length:
  275. raise IndexError("deque index out of range")
  276. self.rotate(-index)
  277. self.popleft()
  278. self.rotate(index)
  279. else:
  280. index = ~index
  281. if index >= length:
  282. raise IndexError("deque index out of range")
  283. self.rotate(index)
  284. self.pop()
  285. self.rotate(-index)
  286. def __reduce_ex__(self, proto):
  287. return type(self), (list(self), self.maxlen)
  288. __hash__ = None
  289. def __copy__(self):
  290. return self.__class__(self, self.maxlen)
  291. # XXX make comparison more efficient
  292. def __eq__(self, other):
  293. if isinstance(other, deque):
  294. return list(self) == list(other)
  295. else:
  296. return NotImplemented
  297. def __ne__(self, other):
  298. if isinstance(other, deque):
  299. return list(self) != list(other)
  300. else:
  301. return NotImplemented
  302. def __lt__(self, other):
  303. if isinstance(other, deque):
  304. return list(self) < list(other)
  305. else:
  306. return NotImplemented
  307. def __le__(self, other):
  308. if isinstance(other, deque):
  309. return list(self) <= list(other)
  310. else:
  311. return NotImplemented
  312. def __gt__(self, other):
  313. if isinstance(other, deque):
  314. return list(self) > list(other)
  315. else:
  316. return NotImplemented
  317. def __ge__(self, other):
  318. if isinstance(other, deque):
  319. return list(self) >= list(other)
  320. else:
  321. return NotImplemented
  322. def __iadd__(self, other):
  323. self.extend(other)
  324. return self
  325. class deque_iterator(object):
  326. def __init__(self, deq, itergen):
  327. self.counter = len(deq)
  328. def giveup():
  329. self.counter = 0
  330. raise RuntimeError("deque mutated during iteration")
  331. self._gen = itergen(deq.state, giveup)
  332. def next(self):
  333. res = next(self._gen)
  334. self.counter -= 1
  335. return res
  336. def __iter__(self):
  337. return self
  338. class defaultdict(dict):
  339. def __init__(self, *args, **kwds):
  340. if len(args) > 0:
  341. default_factory = args[0]
  342. args = args[1:]
  343. if not callable(default_factory) and default_factory is not None:
  344. raise TypeError("first argument must be callable")
  345. else:
  346. default_factory = None
  347. self.default_factory = default_factory
  348. super(defaultdict, self).__init__(*args, **kwds)
  349. def __missing__(self, key):
  350. # from defaultdict docs
  351. if self.default_factory is None:
  352. raise KeyError(key)
  353. self[key] = value = self.default_factory()
  354. return value
  355. def __repr__(self, recurse=set()):
  356. if id(self) in recurse:
  357. return "defaultdict(...)"
  358. try:
  359. recurse.add(id(self))
  360. return "defaultdict(%s, %s)" % (repr(self.default_factory), super(defaultdict, self).__repr__())
  361. finally:
  362. recurse.remove(id(self))
  363. def copy(self):
  364. return type(self)(self.default_factory, self)
  365. def __copy__(self):
  366. return self.copy()
  367. def __reduce__(self):
  368. """
  369. __reduce__ must return a 5-tuple as follows:
  370. - factory function
  371. - tuple of args for the factory function
  372. - additional state (here None)
  373. - sequence iterator (here None)
  374. - dictionary iterator (yielding successive (key, value) pairs
  375. This API is used by pickle.py and copy.py.
  376. """
  377. return (type(self), (self.default_factory,), None, None, self.iteritems())