Source

pypy / pypy / objspace / std / longobject.py

The branch 'bigint-with-int' does not exist.
Full commit
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
import sys
from pypy.interpreter.error import OperationError
from pypy.objspace.std import model, newformat
from pypy.objspace.std.model import registerimplementation, W_Object
from pypy.objspace.std.register_all import register_all
from pypy.objspace.std.multimethod import FailedToImplementArgs
from pypy.objspace.std.intobject import W_IntObject
from pypy.objspace.std.noneobject import W_NoneObject
from rpython.rlib.rbigint import rbigint
from pypy.objspace.std.longtype import long_typedef, W_AbstractLongObject


class W_LongObject(W_AbstractLongObject):
    """This is a wrapper of rbigint."""
    _immutable_fields_ = ['num']

    typedef = long_typedef

    def __init__(w_self, l):
        w_self.num = l # instance of rbigint

    def fromint(space, intval):
        return W_LongObject(rbigint.fromint(intval))
    fromint = staticmethod(fromint)

    def longval(self):
        return self.num.tolong()

    def tofloat(self, space):
        try:
            return self.num.tofloat()
        except OverflowError:
            raise OperationError(space.w_OverflowError,
                    space.wrap("long int too large to convert to float"))

    def toint(self):
        return self.num.toint()

    def fromfloat(space, f):
        return newlong(space, rbigint.fromfloat(f))
    fromfloat = staticmethod(fromfloat)

    def fromlong(l):
        return W_LongObject(rbigint.fromlong(l))
    fromlong = staticmethod(fromlong)

    def fromrarith_int(i):
        return W_LongObject(rbigint.fromrarith_int(i))
    fromrarith_int._annspecialcase_ = "specialize:argtype(0)"
    fromrarith_int = staticmethod(fromrarith_int)

    def int_w(w_self, space):
        try:
            return w_self.num.toint()
        except OverflowError:
            raise OperationError(space.w_OverflowError, space.wrap(
                "long int too large to convert to int"))

    def uint_w(w_self, space):
        try:
            return w_self.num.touint()
        except ValueError:
            raise OperationError(space.w_ValueError, space.wrap(
                "cannot convert negative integer to unsigned int"))
        except OverflowError:
            raise OperationError(space.w_OverflowError, space.wrap(
                "long int too large to convert to unsigned int"))

    def bigint_w(w_self, space):
        return w_self.num

    def float_w(self, space):
        return self.tofloat(space)

    def int(self, space):
        if (type(self) is not W_LongObject and
            space.is_overloaded(self, space.w_long, '__int__')):
            return W_Object.int(self, space)
        try:
            return space.newint(self.num.toint())
        except OverflowError:
            return long__Long(space, self)

    def __repr__(self):
        return '<W_LongObject(%d)>' % self.num.tolong()

registerimplementation(W_LongObject)

def newlong(space, bigint):
    """Turn the bigint into a W_LongObject.  If withsmalllong is enabled,
    check if the bigint would fit in a smalllong, and return a
    W_SmallLongObject instead if it does.
    """
    if space.config.objspace.std.withsmalllong:
        try:
            z = bigint.tolonglong()
        except OverflowError:
            pass
        else:
            from pypy.objspace.std.smalllongobject import W_SmallLongObject
            return W_SmallLongObject(z)
    return W_LongObject(bigint)


# bool-to-long
def delegate_Bool2Long(space, w_bool):
    return W_LongObject(rbigint.frombool(space.is_true(w_bool)))

# int-to-long delegation
def delegate_Int2Long(space, w_intobj):
    return W_LongObject.fromint(space, w_intobj.intval)


# long__Long is supposed to do nothing, unless it has
# a derived long object, where it should return
# an exact one.
def long__Long(space, w_long1):
    if space.is_w(space.type(w_long1), space.w_long):
        return w_long1
    l = w_long1.num
    return W_LongObject(l)
trunc__Long = long__Long

def long__Int(space, w_intobj):
    return space.newlong(w_intobj.intval)

def index__Long(space, w_value):
    return long__Long(space, w_value)

def float__Long(space, w_longobj):
    return space.newfloat(w_longobj.tofloat(space))

def repr__Long(space, w_long):
    return space.wrap(w_long.num.repr())

def str__Long(space, w_long):
    return space.wrap(w_long.num.str())

def format__Long_ANY(space, w_long, w_format_spec):
    return newformat.run_formatter(space, w_format_spec, "format_int_or_long",
                                   w_long, newformat.LONG_KIND)


def lt__Long_Long(space, w_long1, w_long2):
    return space.newbool(w_long1.num.lt(w_long2.num))
def le__Long_Long(space, w_long1, w_long2):
    return space.newbool(w_long1.num.le(w_long2.num))
def eq__Long_Long(space, w_long1, w_long2):
    return space.newbool(w_long1.num.eq(w_long2.num))
def ne__Long_Long(space, w_long1, w_long2):
    return space.newbool(w_long1.num.ne(w_long2.num))
def gt__Long_Long(space, w_long1, w_long2):
    return space.newbool(w_long1.num.gt(w_long2.num))
def ge__Long_Long(space, w_long1, w_long2):
    return space.newbool(w_long1.num.ge(w_long2.num))

def lt__Long_Int(space, w_long1, w_int2):
    return space.newbool(w_long1.num.int_lt(w_int2.intval))
def le__Long_Int(space, w_long1, w_int2):
    return space.newbool(w_long1.num.int_le(w_int2.intval))
def eq__Long_Int(space, w_long1, w_int2):
    return space.newbool(w_long1.num.int_eq(w_int2.intval))
def ne__Long_Int(space, w_long1, w_int2):
    return space.newbool(w_long1.num.int_ne(w_int2.intval))
def gt__Long_Int(space, w_long1, w_int2):
    return space.newbool(w_long1.num.int_gt(w_int2.intval))
def ge__Long_Int(space, w_long1, w_int2):
    return space.newbool(w_long1.num.int_ge(w_int2.intval))

def lt__Int_Long(space, w_int1, w_long2):
    return space.newbool(w_long2.num.int_gt(w_int1.intval))
def le__Int_Long(space, w_int1, w_long2):
    return space.newbool(w_long2.num.int_ge(w_int1.intval))
def eq__Int_Long(space, w_int1, w_long2):
    return space.newbool(not w_long2.num.int_ne(w_int1.intval))
def ne__Int_Long(space, w_int1, w_long2):
    return space.newbool(not w_long2.num.int_eq(w_int1.intval))
def gt__Int_Long(space, w_int1, w_long2):
    return space.newbool(w_long2.num.int_lt(w_int1.intval))
def ge__Int_Long(space, w_int1, w_long2):
    return space.newbool(w_long2.num.int_le(w_int1.intval))


def hash__Long(space, w_value):
    return space.wrap(w_value.num.hash())

# coerce
def coerce__Long_Long(space, w_long1, w_long2):
    return space.newtuple([w_long1, w_long2])


def add__Long_Long(space, w_long1, w_long2):
    return W_LongObject(w_long1.num.add(w_long2.num))

def add__Long_Int(space, w_long1, w_int2):
    return W_LongObject(w_long1.num.int_add(w_int2.intval))

def sub__Long_Long(space, w_long1, w_long2):
    return W_LongObject(w_long1.num.sub(w_long2.num))

def sub__Long_Int(space, w_long1, w_int2):
    return W_LongObject(w_long1.num.int_sub(w_int2.intval))

def mul__Long_Long(space, w_long1, w_long2):
    return W_LongObject(w_long1.num.mul(w_long2.num))

def mul__Long_Int(space, w_long1, w_int2):
    return W_LongObject(w_long1.num.int_mul(w_int2.intval))

def truediv__Long_Long(space, w_long1, w_long2):
    try:
        f = w_long1.num.truediv(w_long2.num)
    except ZeroDivisionError:
        raise OperationError(space.w_ZeroDivisionError,
                             space.wrap("long division or modulo by zero"))
    except OverflowError:
        raise OperationError(space.w_OverflowError,
                             space.wrap("long/long too large for a float"))
    return space.newfloat(f)

def floordiv__Long_Long(space, w_long1, w_long2):
    try:
        z = w_long1.num.floordiv(w_long2.num)
    except ZeroDivisionError:
        raise OperationError(space.w_ZeroDivisionError,
                             space.wrap("long division or modulo by zero"))
    return newlong(space, z)

def floordiv__Long_Int(space, w_long1, w_int2):
    try:
        z = w_long1.num.int_floordiv(w_int2.intval)
    except ZeroDivisionError:
        raise OperationError(space.w_ZeroDivisionError,
                             space.wrap("long division or modulo by zero"))
    return newlong(space, z)


def div__Long_Long(space, w_long1, w_long2):
    return floordiv__Long_Long(space, w_long1, w_long2)

def div__Long_Int(space, w_long1, w_int2):
    return floordiv__Long_Int(space, w_long1, w_int2)

def mod__Long_Long(space, w_long1, w_long2):
    try:
        z = w_long1.num.mod(w_long2.num)
    except ZeroDivisionError:
        raise OperationError(space.w_ZeroDivisionError,
                             space.wrap("long division or modulo by zero"))
    return newlong(space, z)

def mod__Long_Int(space, w_long1, w_int2):
    try:
        z = w_long1.num.int_mod(w_int2.intval)
    except ZeroDivisionError:
        raise OperationError(space.w_ZeroDivisionError,
                             space.wrap("long division or modulo by zero"))
    return newlong(space, z)

def divmod__Long_Long(space, w_long1, w_long2):
    try:
        div, mod = w_long1.num.divmod(w_long2.num)
    except ZeroDivisionError:
        raise OperationError(space.w_ZeroDivisionError,
                             space.wrap("long division or modulo by zero"))
    return space.newtuple([newlong(space, div), newlong(space, mod)])

def divmod__Long_Int(space, w_long1, w_int2):
    try:
        div, mod = w_long1.num.int_divmod(w_int2.intval)
    except ZeroDivisionError:
        raise OperationError(space.w_ZeroDivisionError,
                             space.wrap("long division or modulo by zero"))
    return space.newtuple([newlong(space, div), newlong(space, mod)])

def pow__Long_Long_Long(space, w_long1, w_long2, w_long3):
    # XXX need to replicate some of the logic, to get the errors right
    if w_long2.num.sign < 0:
        raise OperationError(
            space.w_TypeError,
            space.wrap(
                "pow() 2nd argument "
                "cannot be negative when 3rd argument specified"))
    try:
        return W_LongObject(w_long1.num.pow(w_long2.num, w_long3.num))
    except ValueError:
        raise OperationError(space.w_ValueError,
                             space.wrap("pow 3rd argument cannot be 0"))

def pow__Long_Long_None(space, w_long1, w_long2, w_long3):
    # XXX need to replicate some of the logic, to get the errors right
    if w_long2.num.sign < 0:
        raise FailedToImplementArgs(
            space.w_ValueError,
            space.wrap("long pow() too negative"))
    return W_LongObject(w_long1.num.pow(w_long2.num, None))

def neg__Long(space, w_long1):
    return W_LongObject(w_long1.num.neg())

def pos__Long(space, w_long):
    return long__Long(space, w_long)

def abs__Long(space, w_long):
    return W_LongObject(w_long.num.abs())

def nonzero__Long(space, w_long):
    return space.newbool(w_long.num.tobool())

def invert__Long(space, w_long):
    return W_LongObject(w_long.num.invert())

def lshift__Long_Long(space, w_long1, w_long2):
    # XXX need to replicate some of the logic, to get the errors right
    if w_long2.num.sign < 0:
        raise OperationError(space.w_ValueError,
                             space.wrap("negative shift count"))
    try:
        shift = w_long2.num.toint()
    except OverflowError:   # b too big
        raise OperationError(space.w_OverflowError,
                             space.wrap("shift count too large"))
    return W_LongObject(w_long1.num.lshift(shift))

def lshift__Long_Int(space, w_long1, w_int2):
    # XXX need to replicate some of the logic, to get the errors right
    if w_int2.intval < 0:
        raise OperationError(space.w_ValueError,
                             space.wrap("negative shift counnt"))

    return W_LongObject(w_long1.num.lshift(w_int2.intval))

def rshift__Long_Long(space, w_long1, w_long2):
    # XXX need to replicate some of the logic, to get the errors right
    if w_long2.num.sign < 0:
        raise OperationError(space.w_ValueError,
                             space.wrap("negative shift count"))
    try:
        shift = w_long2.num.toint()
    except OverflowError:   # b too big # XXX maybe just return 0L instead?
        raise OperationError(space.w_OverflowError,
                             space.wrap("shift count too large"))
    return newlong(space, w_long1.num.rshift(shift))

def rshift__Long_Int(space, w_long1, w_int2):
    # XXX need to replicate some of the logic, to get the errors right
    if w_int2.intval < 0:
        raise OperationError(space.w_ValueError,
                             space.wrap("negative shift count"))
    
    return newlong(space, w_long1.num.rshift(w_int2.intval))

def and__Long_Long(space, w_long1, w_long2):
    return newlong(space, w_long1.num.and_(w_long2.num))

def and__Long_Int(space, w_long1, w_int2):
    return newlong(space, w_long1.num.int_and_(w_int2.intval))

def xor__Long_Long(space, w_long1, w_long2):
    return W_LongObject(w_long1.num.xor(w_long2.num))

def xor__Long_Int(space, w_long1, w_int2):
    return W_LongObject(w_long1.num.int_xor(w_int2.intval))

def or__Long_Long(space, w_long1, w_long2):
    return W_LongObject(w_long1.num.or_(w_long2.num))

def or__Long_Int(space, w_long1, w_int2):
    return W_LongObject(w_long1.num.int_or_(w_int2.intval))

def oct__Long(space, w_long1):
    return space.wrap(w_long1.num.oct())

def hex__Long(space, w_long1):
    return space.wrap(w_long1.num.hex())

def getnewargs__Long(space, w_long1):
    return space.newtuple([W_LongObject(w_long1.num)])

register_all(vars())

# register implementations of ops that recover int op overflows
def recover_with_smalllong(space):
    # True if there is a chance that a SmallLong would fit when an Int does not
    return (space.config.objspace.std.withsmalllong and
            sys.maxint == 2147483647)

# binary ops
for opname in ['add', 'sub', 'mul', 'div', 'floordiv', 'truediv', 'mod', 'divmod', 'lshift']:
    exec compile("""
def %(opname)s_ovr__Int_Int(space, w_int1, w_int2):
    if recover_with_smalllong(space) and %(opname)r != 'truediv':
        from pypy.objspace.std.smalllongobject import %(opname)s_ovr
        return %(opname)s_ovr(space, w_int1, w_int2)
    w_long1 = delegate_Int2Long(space, w_int1)
    return %(opname)s__Long_Int(space, w_long1, w_int2)
""" % {'opname': opname}, '', 'exec')

    getattr(model.MM, opname).register(globals()['%s_ovr__Int_Int' % opname],
                                       W_IntObject, W_IntObject, order=1)

# unary ops
for opname in ['neg', 'abs']:
    exec """
def %(opname)s_ovr__Int(space, w_int1):
    if recover_with_smalllong(space):
        from pypy.objspace.std.smalllongobject import %(opname)s_ovr
        return %(opname)s_ovr(space, w_int1)
    w_long1 = delegate_Int2Long(space, w_int1)
    return %(opname)s__Long(space, w_long1)
""" % {'opname': opname}

    getattr(model.MM, opname).register(globals()['%s_ovr__Int' % opname],
                                       W_IntObject, order=1)

# pow
def pow_ovr__Int_Int_None(space, w_int1, w_int2, w_none3):
    if recover_with_smalllong(space):
        from pypy.objspace.std.smalllongobject import pow_ovr
        return pow_ovr(space, w_int1, w_int2)
    w_long1 = delegate_Int2Long(space, w_int1)
    w_long2 = delegate_Int2Long(space, w_int2)
    return pow__Long_Long_None(space, w_long1, w_long2, w_none3)

def pow_ovr__Int_Int_Long(space, w_int1, w_int2, w_long3):
    w_long1 = delegate_Int2Long(space, w_int1)
    w_long2 = delegate_Int2Long(space, w_int2)
    return pow__Long_Long_Long(space, w_long1, w_long2, w_long3)

model.MM.pow.register(pow_ovr__Int_Int_None, W_IntObject, W_IntObject,
                      W_NoneObject, order=1)
model.MM.pow.register(pow_ovr__Int_Int_Long, W_IntObject, W_IntObject,
                      W_LongObject, order=1)