PageRenderTime 46ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 1ms

/pypy/objspace/std/smalllongobject.py

https://bitbucket.org/pypy/pypy/
Python | 413 lines | 401 code | 6 blank | 6 comment | 8 complexity | 2731e5cbc127cf8c3596ef34e0b7b6e0 MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
  1. """
  2. Implementation of 'small' longs, stored as a r_longlong.
  3. Useful for 32-bit applications manipulating values a bit larger than
  4. fits in an 'int'.
  5. """
  6. import operator
  7. from rpython.rlib.rarithmetic import LONGLONG_BIT, intmask, r_longlong, r_uint
  8. from rpython.rlib.rbigint import rbigint
  9. from rpython.tool.sourcetools import func_renamer, func_with_new_name
  10. from pypy.interpreter.error import oefmt
  11. from pypy.interpreter.gateway import WrappedDefault, unwrap_spec
  12. from pypy.objspace.std.intobject import W_AbstractIntObject
  13. from pypy.objspace.std.longobject import W_AbstractLongObject, W_LongObject
  14. from pypy.objspace.std.util import COMMUTATIVE_OPS
  15. # XXX: breaks translation
  16. #LONGLONG_MIN = r_longlong(-1 << (LONGLONG_BIT - 1))
  17. class W_SmallLongObject(W_AbstractLongObject):
  18. _immutable_fields_ = ['longlong']
  19. def __init__(self, value):
  20. assert isinstance(value, r_longlong)
  21. self.longlong = value
  22. @staticmethod
  23. def fromint(value):
  24. return W_SmallLongObject(r_longlong(value))
  25. @staticmethod
  26. def frombigint(bigint):
  27. return W_SmallLongObject(bigint.tolonglong())
  28. def asbigint(self):
  29. return rbigint.fromrarith_int(self.longlong)
  30. def longval(self):
  31. return self.longlong
  32. def __repr__(self):
  33. return '<W_SmallLongObject(%d)>' % self.longlong
  34. def _int_w(self, space):
  35. a = self.longlong
  36. b = intmask(a)
  37. if b == a:
  38. return b
  39. raise oefmt(space.w_OverflowError,
  40. "long int too large to convert to int")
  41. def uint_w(self, space):
  42. a = self.longlong
  43. if a < 0:
  44. raise oefmt(space.w_ValueError,
  45. "cannot convert negative integer to unsigned int")
  46. b = r_uint(a)
  47. if r_longlong(b) == a:
  48. return b
  49. raise oefmt(space.w_OverflowError,
  50. "long int too large to convert to unsigned int")
  51. def bigint_w(self, space, allow_conversion=True):
  52. return self.asbigint()
  53. def _bigint_w(self, space):
  54. return self.asbigint()
  55. def _float_w(self, space):
  56. return float(self.longlong)
  57. def int(self, space):
  58. a = self.longlong
  59. b = intmask(a)
  60. return space.newint(b) if b == a else self
  61. def descr_long(self, space):
  62. if space.is_w(space.type(self), space.w_long):
  63. return self
  64. return W_SmallLongObject(self.longlong)
  65. descr_index = descr_trunc = descr_pos = descr_long
  66. def descr_float(self, space):
  67. return space.newfloat(float(self.longlong))
  68. def descr_neg(self, space):
  69. a = self.longlong
  70. try:
  71. if a == r_longlong(-1 << (LONGLONG_BIT-1)):
  72. raise OverflowError
  73. x = -a
  74. except OverflowError:
  75. self = _small2long(space, self)
  76. return self.descr_neg(space)
  77. return W_SmallLongObject(x)
  78. def descr_abs(self, space):
  79. return self if self.longlong >= 0 else self.descr_neg(space)
  80. def descr_nonzero(self, space):
  81. return space.newbool(bool(self.longlong))
  82. def descr_invert(self, space):
  83. x = ~self.longlong
  84. return W_SmallLongObject(x)
  85. @unwrap_spec(w_modulus=WrappedDefault(None))
  86. def descr_pow(self, space, w_exponent, w_modulus=None):
  87. if isinstance(w_exponent, W_AbstractLongObject):
  88. self = _small2long(space, self)
  89. return self.descr_pow(space, w_exponent, w_modulus)
  90. elif not isinstance(w_exponent, W_AbstractIntObject):
  91. return space.w_NotImplemented
  92. x = self.longlong
  93. y = space.int_w(w_exponent)
  94. if space.is_none(w_modulus):
  95. try:
  96. return _pow(space, x, y, r_longlong(0))
  97. except ValueError:
  98. self = self.descr_float(space)
  99. return space.pow(self, w_exponent, space.w_None)
  100. except OverflowError:
  101. self = _small2long(space, self)
  102. return self.descr_pow(space, w_exponent, w_modulus)
  103. elif isinstance(w_modulus, W_AbstractIntObject):
  104. w_modulus = _int2small(space, w_modulus)
  105. elif not isinstance(w_modulus, W_AbstractLongObject):
  106. return space.w_NotImplemented
  107. elif not isinstance(w_modulus, W_SmallLongObject):
  108. self = _small2long(space, self)
  109. return self.descr_pow(space, w_exponent, w_modulus)
  110. z = w_modulus.longlong
  111. if z == 0:
  112. raise oefmt(space.w_ValueError, "pow() 3rd argument cannot be 0")
  113. try:
  114. return _pow(space, x, y, z)
  115. except ValueError:
  116. self = self.descr_float(space)
  117. return space.pow(self, w_exponent, w_modulus)
  118. except OverflowError:
  119. self = _small2long(space, self)
  120. return self.descr_pow(space, w_exponent, w_modulus)
  121. @unwrap_spec(w_modulus=WrappedDefault(None))
  122. def descr_rpow(self, space, w_base, w_modulus=None):
  123. if isinstance(w_base, W_AbstractIntObject):
  124. # Defer to w_base<W_SmallLongObject>.descr_pow
  125. w_base = _int2small(space, w_base)
  126. elif not isinstance(w_base, W_AbstractLongObject):
  127. return space.w_NotImplemented
  128. return w_base.descr_pow(space, self, w_modulus)
  129. def _make_descr_cmp(opname):
  130. op = getattr(operator, opname)
  131. bigint_op = getattr(rbigint, opname)
  132. @func_renamer('descr_' + opname)
  133. def descr_cmp(self, space, w_other):
  134. if isinstance(w_other, W_AbstractIntObject):
  135. result = op(self.longlong, w_other.int_w(space))
  136. elif not isinstance(w_other, W_AbstractLongObject):
  137. return space.w_NotImplemented
  138. elif isinstance(w_other, W_SmallLongObject):
  139. result = op(self.longlong, w_other.longlong)
  140. else:
  141. result = bigint_op(self.asbigint(), w_other.asbigint())
  142. return space.newbool(result)
  143. return descr_cmp
  144. descr_lt = _make_descr_cmp('lt')
  145. descr_le = _make_descr_cmp('le')
  146. descr_eq = _make_descr_cmp('eq')
  147. descr_ne = _make_descr_cmp('ne')
  148. descr_gt = _make_descr_cmp('gt')
  149. descr_ge = _make_descr_cmp('ge')
  150. def _make_descr_binop(func, ovf=True):
  151. opname = func.__name__[1:]
  152. descr_name, descr_rname = 'descr_' + opname, 'descr_r' + opname
  153. long_op = getattr(W_LongObject, descr_name)
  154. @func_renamer(descr_name)
  155. def descr_binop(self, space, w_other):
  156. if isinstance(w_other, W_AbstractIntObject):
  157. w_other = _int2small(space, w_other)
  158. elif not isinstance(w_other, W_AbstractLongObject):
  159. return space.w_NotImplemented
  160. elif not isinstance(w_other, W_SmallLongObject):
  161. self = _small2long(space, self)
  162. return long_op(self, space, w_other)
  163. if ovf:
  164. try:
  165. return func(self, space, w_other)
  166. except OverflowError:
  167. self = _small2long(space, self)
  168. w_other = _small2long(space, w_other)
  169. return long_op(self, space, w_other)
  170. else:
  171. return func(self, space, w_other)
  172. if opname in COMMUTATIVE_OPS:
  173. @func_renamer(descr_rname)
  174. def descr_rbinop(self, space, w_other):
  175. return descr_binop(self, space, w_other)
  176. return descr_binop, descr_rbinop
  177. long_rop = getattr(W_LongObject, descr_rname)
  178. @func_renamer(descr_rname)
  179. def descr_rbinop(self, space, w_other):
  180. if isinstance(w_other, W_AbstractIntObject):
  181. w_other = _int2small(space, w_other)
  182. elif not isinstance(w_other, W_AbstractLongObject):
  183. return space.w_NotImplemented
  184. elif not isinstance(w_other, W_SmallLongObject):
  185. self = _small2long(space, self)
  186. return long_rop(self, space, w_other)
  187. if ovf:
  188. try:
  189. return func(w_other, space, self)
  190. except OverflowError:
  191. self = _small2long(space, self)
  192. w_other = _small2long(space, w_other)
  193. return long_rop(self, space, w_other)
  194. else:
  195. return func(w_other, space, self)
  196. return descr_binop, descr_rbinop
  197. def _add(self, space, w_other):
  198. x = self.longlong
  199. y = w_other.longlong
  200. z = x + y
  201. if ((z ^ x) & (z ^ y)) < 0:
  202. raise OverflowError
  203. return W_SmallLongObject(z)
  204. descr_add, descr_radd = _make_descr_binop(_add)
  205. def _sub(self, space, w_other):
  206. x = self.longlong
  207. y = w_other.longlong
  208. z = x - y
  209. if ((z ^ x) & (z ^ ~y)) < 0:
  210. raise OverflowError
  211. return W_SmallLongObject(z)
  212. descr_sub, descr_rsub = _make_descr_binop(_sub)
  213. def _mul(self, space, w_other):
  214. x = self.longlong
  215. y = w_other.longlong
  216. z = _llong_mul_ovf(x, y)
  217. return W_SmallLongObject(z)
  218. descr_mul, descr_rmul = _make_descr_binop(_mul)
  219. def _floordiv(self, space, w_other):
  220. x = self.longlong
  221. y = w_other.longlong
  222. try:
  223. if y == -1 and x == r_longlong(-1 << (LONGLONG_BIT-1)):
  224. raise OverflowError
  225. z = x // y
  226. except ZeroDivisionError:
  227. raise oefmt(space.w_ZeroDivisionError, "integer division by zero")
  228. return W_SmallLongObject(z)
  229. descr_floordiv, descr_rfloordiv = _make_descr_binop(_floordiv)
  230. _div = func_with_new_name(_floordiv, '_div')
  231. descr_div, descr_rdiv = _make_descr_binop(_div)
  232. def _mod(self, space, w_other):
  233. x = self.longlong
  234. y = w_other.longlong
  235. try:
  236. if y == -1 and x == r_longlong(-1 << (LONGLONG_BIT-1)):
  237. raise OverflowError
  238. z = x % y
  239. except ZeroDivisionError:
  240. raise oefmt(space.w_ZeroDivisionError, "integer modulo by zero")
  241. return W_SmallLongObject(z)
  242. descr_mod, descr_rmod = _make_descr_binop(_mod)
  243. def _divmod(self, space, w_other):
  244. x = self.longlong
  245. y = w_other.longlong
  246. try:
  247. if y == -1 and x == r_longlong(-1 << (LONGLONG_BIT-1)):
  248. raise OverflowError
  249. z = x // y
  250. except ZeroDivisionError:
  251. raise oefmt(space.w_ZeroDivisionError, "integer divmod by zero")
  252. # no overflow possible
  253. m = x % y
  254. return space.newtuple([W_SmallLongObject(z), W_SmallLongObject(m)])
  255. descr_divmod, descr_rdivmod = _make_descr_binop(_divmod)
  256. def _lshift(self, space, w_other):
  257. a = self.longlong
  258. # May overflow
  259. b = space.int_w(w_other)
  260. if r_uint(b) < LONGLONG_BIT: # 0 <= b < LONGLONG_BIT
  261. c = a << b
  262. if a != (c >> b):
  263. raise OverflowError
  264. return W_SmallLongObject(c)
  265. if b < 0:
  266. raise oefmt(space.w_ValueError, "negative shift count")
  267. # b >= LONGLONG_BIT
  268. if a == 0:
  269. return self
  270. raise OverflowError
  271. descr_lshift, descr_rlshift = _make_descr_binop(_lshift)
  272. def _rshift(self, space, w_other):
  273. a = self.longlong
  274. # May overflow
  275. b = space.int_w(w_other)
  276. if r_uint(b) >= LONGLONG_BIT: # not (0 <= b < LONGLONG_BIT)
  277. if b < 0:
  278. raise oefmt(space.w_ValueError, "negative shift count")
  279. # b >= LONGLONG_BIT
  280. if a == 0:
  281. return self
  282. a = -1 if a < 0 else 0
  283. else:
  284. a = a >> b
  285. return W_SmallLongObject(a)
  286. descr_rshift, descr_rrshift = _make_descr_binop(_rshift, ovf=False)
  287. def _and(self, space, w_other):
  288. a = self.longlong
  289. b = w_other.longlong
  290. res = a & b
  291. return W_SmallLongObject(res)
  292. descr_and, descr_rand = _make_descr_binop(_and, ovf=False)
  293. def _or(self, space, w_other):
  294. a = self.longlong
  295. b = w_other.longlong
  296. res = a | b
  297. return W_SmallLongObject(res)
  298. descr_or, descr_ror = _make_descr_binop(_or, ovf=False)
  299. def _xor(self, space, w_other):
  300. a = self.longlong
  301. b = w_other.longlong
  302. res = a ^ b
  303. return W_SmallLongObject(res)
  304. descr_xor, descr_rxor = _make_descr_binop(_xor, ovf=False)
  305. def _llong_mul_ovf(a, b):
  306. # xxx duplication of the logic from translator/c/src/int.h
  307. longprod = a * b
  308. doubleprod = float(a) * float(b)
  309. doubled_longprod = float(longprod)
  310. # Fast path for normal case: small multiplicands, and no info
  311. # is lost in either method.
  312. if doubled_longprod == doubleprod:
  313. return longprod
  314. # Somebody somewhere lost info. Close enough, or way off? Note
  315. # that a != 0 and b != 0 (else doubled_longprod == doubleprod == 0).
  316. # The difference either is or isn't significant compared to the
  317. # true value (of which doubleprod is a good approximation).
  318. diff = doubled_longprod - doubleprod
  319. absdiff = abs(diff)
  320. absprod = abs(doubleprod)
  321. # absdiff/absprod <= 1/32 iff
  322. # 32 * absdiff <= absprod -- 5 good bits is "close enough"
  323. if 32.0 * absdiff <= absprod:
  324. return longprod
  325. raise OverflowError("integer multiplication")
  326. def _int2small(space, w_int):
  327. # XXX: W_IntObject.descr_long should probably return W_SmallLongs
  328. return W_SmallLongObject.fromint(w_int.int_w(space))
  329. def _small2long(space, w_small):
  330. return W_LongObject(w_small.asbigint())
  331. def _pow(space, iv, iw, iz):
  332. if iw < 0:
  333. if iz != 0:
  334. raise oefmt(space.w_TypeError,
  335. "pow() 2nd argument cannot be negative when 3rd "
  336. "argument specified")
  337. raise ValueError
  338. temp = iv
  339. ix = r_longlong(1)
  340. while iw > 0:
  341. if iw & 1:
  342. ix = _llong_mul_ovf(ix, temp)
  343. iw >>= 1 # Shift exponent down by 1 bit
  344. if iw == 0:
  345. break
  346. temp = _llong_mul_ovf(temp, temp) # Square the value of temp
  347. if iz:
  348. # If we did a multiplication, perform a modulo
  349. ix %= iz
  350. temp %= iz
  351. if iz:
  352. ix %= iz
  353. return W_SmallLongObject(ix)