Author: Amaury Forgeot d'Arc <[email protected]>
Branch: decimal-libmpdec
Changeset: r71456:8667f0db8c8c
Date: 2014-05-07 00:30 +0200
http://bitbucket.org/pypy/pypy/changeset/8667f0db8c8c/
Log: Decimal: More tests, more constructors.
diff --git a/pypy/module/_decimal/interp_context.py
b/pypy/module/_decimal/interp_context.py
--- a/pypy/module/_decimal/interp_context.py
+++ b/pypy/module/_decimal/interp_context.py
@@ -21,14 +21,16 @@
def descr_getitem(self, space, w_key):
flag = interp_signals.exception_as_flag(space, w_key)
- return space.wrap(bool(flag & self.flag_ptr[0]))
+ cur_flag = rffi.cast(lltype.Signed, self.flag_ptr[0])
+ return space.wrap(bool(flag & cur_flag))
def descr_setitem(self, space, w_key, w_value):
flag = interp_signals.exception_as_flag(space, w_key)
+ cur_flag = rffi.cast(lltype.Signed, self.flag_ptr[0])
if space.is_true(w_value):
- self.flag_ptr[0] |= flag
+ self.flag_ptr[0] = rffi.cast(rffi.UINT, cur_flag | flag)
else:
- self.flag_ptr[0] &= ~flag
+ self.flag_ptr[0] = rffi.cast(rffi.UINT, cur_flag & ~flag)
def new_signal_dict(space, flag_ptr):
diff --git a/pypy/module/_decimal/interp_decimal.py
b/pypy/module/_decimal/interp_decimal.py
--- a/pypy/module/_decimal/interp_decimal.py
+++ b/pypy/module/_decimal/interp_decimal.py
@@ -35,6 +35,20 @@
if self.data:
lltype.free(self.data, flavor='raw')
+ def apply(self, context, w_subtype=None):
+ # Apply the context to the input operand. Return a new W_Decimal.
+ if subtype:
+ w_result = space.allocate_instance(W_Decimal, w_subtype)
+ W_Decimal.__init__(w_result, space)
+ else:
+ w_result = W_Decimal(space)
+ with lltype.scoped_alloc(rffi.CArrayPtr(rffi.UINT).TO, 1) as
status_ptr:
+ rpmdec.mpd_qcopy(w_result.mpd, self.mpd, status_ptr)
+ context.addstatus(self.space, status_ptr[0])
+ rpmdec.mpd_qfinalize(w_result.mpd, context.ctx, status_ptr)
+ context.addstatus(self.space, status_ptr[0])
+ return w_result
+
def descr_str(self, space):
context = interp_context.getcontext(space)
with lltype.scoped_alloc(rffi.CCHARPP.TO, 1) as cp_ptr:
@@ -48,6 +62,9 @@
rmpdec.mpd_free(cp)
return space.wrap(result) # Convert bytes to unicode
+ def descr_bool(self, space):
+ return space.wrap(not rmpdec.mpd_iszero(self.mpd))
+
def compare(self, space, w_other, op):
if not isinstance(w_other, W_Decimal): # So far
return space.w_NotImplemented
@@ -145,12 +162,12 @@
# special
is_special = True
val = space.unicode_w(w_exponent)
- if val == 'F':
+ if val == u'F':
builder.append('Inf')
is_infinite = True
- elif val == 'n':
+ elif val == u'n':
builder.append('Nan')
- elif val == 'N':
+ elif val == u'N':
builder.append('sNan')
else:
raise oefmt(space.w_ValueError,
@@ -171,7 +188,7 @@
if not digits_w and not is_special:
# empty tuple: zero coefficient, except for special numbers
- strval += '0'
+ builder.append('0')
for w_digit in digits_w:
try:
digit = space.int_w(w_digit)
@@ -195,9 +212,35 @@
strval = builder.build()
return decimal_from_cstring(space, w_subtype, strval, context, exact=exact)
+def decimal_from_decimal(space, w_subtype, w_value, context, exact=True):
+ assert isinstance(w_value, W_Decimal)
+ if exact:
+ if space.is_w(w_subtype, space.gettypeobject(W_Decimal.typedef)):
+ return w_value
+ w_result = space.allocate_instance(W_Decimal, w_subtype)
+ W_Decimal.__init__(w_result, space)
+ with interp_context.ConvContext(
+ space, w_result.mpd, context, exact) as (ctx, status_ptr):
+ rmpdec.mpd_qcopy(w_result.mpd, w_value.mpd, status_ptr)
+ return w_result
+ else:
+ if (rmpdec.mpd_isnan(w_value.mpd) and
+ w_value.mpd.digits > (context.ctx.prec - context.ctx.clamp)):
+ # Special case: too many NaN payload digits
+ context.addstatus(space, rmpdec.MPD_Conversion_syntax)
+ w_result = space.allocate_instance(W_Decimal, w_subtype)
+ W_Decimal.__init__(w_result, space)
+ rmpdec.mpd_setspecial(w_result.mpd, rmpdec.MPD_POS, rmpdec.MPD_NAN)
+ else:
+ return w_value.apply(context)
+
+
def decimal_from_object(space, w_subtype, w_value, context, exact=True):
if w_value is None:
return decimal_from_ssize(space, w_subtype, 0, context, exact=exact)
+ elif isinstance(w_value, W_Decimal):
+ return decimal_from_decimal(space, w_subtype, w_value, context,
+ exact=exact)
elif space.isinstance_w(w_value, space.w_unicode):
return decimal_from_unicode(space, w_subtype, w_value, context,
exact=exact, strip_whitespace=exact)
@@ -222,5 +265,6 @@
'Decimal',
__new__ = interp2app(descr_new_decimal),
__str__ = interp2app(W_Decimal.descr_str),
+ __bool__ = interp2app(W_Decimal.descr_bool),
__eq__ = interp2app(W_Decimal.descr_eq),
)
diff --git a/pypy/module/_decimal/test/test_decimal.py
b/pypy/module/_decimal/test/test_decimal.py
--- a/pypy/module/_decimal/test/test_decimal.py
+++ b/pypy/module/_decimal/test/test_decimal.py
@@ -148,3 +148,34 @@
d = Decimal((1, [4, 3, 4, 9, 1, 3, 5, 3, 4], -25))
assert str(d) == '-4.34913534E-17'
+ def test_explicit_from_bool(self):
+ Decimal = self.decimal.Decimal
+
+ assert bool(Decimal(0)) is False
+ assert bool(Decimal(1)) is True
+ assert Decimal(False) == Decimal(0)
+ assert Decimal(True) == Decimal(1)
+
+ def test_explicit_from_Decimal(self):
+ Decimal = self.decimal.Decimal
+
+ #positive
+ d = Decimal(45)
+ e = Decimal(d)
+ assert str(e) == '45'
+
+ #very large positive
+ d = Decimal(500000123)
+ e = Decimal(d)
+ assert str(e) == '500000123'
+
+ #negative
+ d = Decimal(-45)
+ e = Decimal(d)
+ assert str(e) == '-45'
+
+ #zero
+ d = Decimal(0)
+ e = Decimal(d)
+ assert str(e) == '0'
+
diff --git a/pypy/module/_decimal/test/test_ztranslation.py
b/pypy/module/_decimal/test/test_ztranslation.py
--- a/pypy/module/_decimal/test/test_ztranslation.py
+++ b/pypy/module/_decimal/test/test_ztranslation.py
@@ -1,6 +1,9 @@
from pypy.objspace.fake.checkmodule import checkmodule
+from pypy.module._decimal import Module
def test_checkmodule():
+ Module.interpleveldefs['__hack'] = (
+ 'interp_decimal.unicodeobject.W_UnicodeObject(u"")')
checkmodule('_decimal')
diff --git a/rpython/rlib/rmpdec.py b/rpython/rlib/rmpdec.py
--- a/rpython/rlib/rmpdec.py
+++ b/rpython/rlib/rmpdec.py
@@ -36,11 +36,12 @@
libdir.join('memory.c'),
],
export_symbols=[
- "mpd_qset_ssize", "mpd_qset_string",
+ "mpd_qset_ssize", "mpd_qset_string", "mpd_qcopy", "mpd_setspecial",
"mpd_getprec", "mpd_getemin", "mpd_getemax", "mpd_getround",
"mpd_getclamp",
"mpd_qsetprec", "mpd_qsetemin", "mpd_qsetemax", "mpd_qsetround",
"mpd_qsetclamp",
"mpd_maxcontext",
"mpd_to_sci_size",
+ "mpd_iszero", "mpd_isnan",
"mpd_qcmp",
],
compile_extra=compile_extra,
@@ -71,6 +72,7 @@
# Flags
MPD_POS = platform.ConstantInteger('MPD_POS')
MPD_NEG = platform.ConstantInteger('MPD_NEG')
+ MPD_NAN = platform.ConstantInteger('MPD_NAN')
MPD_STATIC = platform.ConstantInteger('MPD_STATIC')
MPD_STATIC_DATA = platform.ConstantInteger('MPD_STATIC_DATA')
@@ -113,6 +115,10 @@
mpd_qimport_u32 = external(
'mpd_qimport_u32', [MPD_PTR, rffi.UINTP, rffi.SIZE_T,
rffi.UCHAR, rffi.UINT, MPD_CONTEXT_PTR, rffi.UINTP],
rffi.SIZE_T)
+mpd_qcopy = external(
+ 'mpd_qcopy', [MPD_PTR, MPD_PTR, rffi.UINTP], rffi.INT)
+mpd_setspecial = external(
+ 'mpd_setspecial', [MPD_PTR, rffi.UCHAR, rffi.UCHAR], lltype.Void)
# Context operations
mpd_getprec = external(
@@ -151,5 +157,9 @@
'mpd_to_sci_size', [rffi.CCHARPP, MPD_PTR, rffi.INT], rffi.SSIZE_T)
# Operations
+mpd_iszero = external(
+ 'mpd_iszero', [MPD_PTR], rffi.INT)
+mpd_isnan = external(
+ 'mpd_isnan', [MPD_PTR], rffi.INT)
mpd_qcmp = external(
'mpd_qcmp', [MPD_PTR, MPD_PTR, rffi.UINTP], rffi.INT)
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit