Commit f1575546 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Merge pull request #933 from Daetalus/long_improvements

some long improvements
parents 1e1fa481 45b5197c
...@@ -404,6 +404,15 @@ extern "C" PyAPI_FUNC(PyObject*) _PyLong_Format(PyObject* aa, int base, int addL ...@@ -404,6 +404,15 @@ extern "C" PyAPI_FUNC(PyObject*) _PyLong_Format(PyObject* aa, int base, int addL
} }
extern "C" PyObject* PyLong_FromDouble(double v) noexcept { extern "C" PyObject* PyLong_FromDouble(double v) noexcept {
if (isnan(v)) {
PyErr_SetString(PyExc_ValueError, "cannot convert float NaN to integer");
return NULL;
}
if (isinf(v)) {
PyErr_SetString(PyExc_OverflowError, "cannot convert float infinity to integer");
return NULL;
}
BoxedLong* rtn = new BoxedLong(); BoxedLong* rtn = new BoxedLong();
mpz_init_set_d(rtn->n, v); mpz_init_set_d(rtn->n, v);
return rtn; return rtn;
...@@ -640,68 +649,106 @@ extern "C" PyObject* PyLong_FromUnsignedLongLong(unsigned long long ival) noexce ...@@ -640,68 +649,106 @@ extern "C" PyObject* PyLong_FromUnsignedLongLong(unsigned long long ival) noexce
return rtn; return rtn;
} }
BoxedLong* _longNew(Box* val, Box* _base) { template <ExceptionStyle S> Box* _longNew(Box* val, Box* _base) noexcept(S == CAPI) {
BoxedLong* rtn = new BoxedLong(); int base = 10;
if (_base) { if (_base) {
if (!PyInt_Check(_base)) if (S == CAPI) {
raiseExcHelper(TypeError, "an integer is required"); if (!PyInt_Check(_base)) {
int base = static_cast<BoxedInt*>(_base)->n; PyErr_Format(PyExc_TypeError, "integer argument expected, got %s", getTypeName(_base));
return NULL;
}
if (!PyString_Check(val)) if (val == None) {
raiseExcHelper(TypeError, "long() can't convert non-string with explicit base"); PyErr_SetString(PyExc_TypeError, "long() missing string argument");
BoxedString* s = static_cast<BoxedString*>(val); return NULL;
}
rtn = (BoxedLong*)PyLong_FromString(s->data(), NULL, base); if (!PyString_Check(val) && !PyUnicode_Check(val)) {
checkAndThrowCAPIException(); PyErr_SetString(PyExc_TypeError, "long() can't convert non-string with explicit base");
} else { return NULL;
if (PyLong_Check(val)) { }
BoxedLong* l = static_cast<BoxedLong*>(val);
if (val->cls == long_cls)
return l;
BoxedLong* rtn = new BoxedLong();
mpz_init_set(rtn->n, l->n);
return rtn;
} else if (PyInt_Check(val)) {
mpz_init_set_si(rtn->n, static_cast<BoxedInt*>(val)->n);
} else if (val->cls == str_cls) {
llvm::StringRef s = static_cast<BoxedString*>(val)->s();
assert(s.data()[s.size()] == '\0');
int r = mpz_init_set_str(rtn->n, s.data(), 10);
RELEASE_ASSERT(r == 0, "");
} else if (val->cls == float_cls) {
mpz_init_set_d(rtn->n, static_cast<BoxedFloat*>(val)->d);
} else { } else {
static BoxedString* long_str = internStringImmortal("__long__"); if (!PyInt_Check(_base))
CallattrFlags callattr_flags{.cls_only = true, .null_on_nonexistent = true, .argspec = ArgPassSpec(0) }; raiseExcHelper(TypeError, "integer argument expected, got %s", getTypeName(_base));
Box* r = callattr(val, long_str, callattr_flags, NULL, NULL, NULL, NULL, NULL);
if (!r) { if (val == None)
raiseExcHelper(TypeError, "TypeError: long() argument must be a string or a number, not '%s'\n", raiseExcHelper(TypeError, "long() missing string argument");
getTypeName(val));
} if (!PyString_Check(val) && !PyUnicode_Check(val))
raiseExcHelper(TypeError, "long() can't convert non-string with explicit base");
}
base = static_cast<BoxedInt*>(_base)->n;
} else {
if (val == None)
return PyLong_FromLong(0L);
Box* r = PyNumber_Long(val);
if (!r) {
if (S == CAPI) {
return NULL;
} else
throwCAPIException();
}
return r;
}
if (PyString_Check(val)) {
BoxedString* s = static_cast<BoxedString*>(val);
if (PyInt_Check(r)) { if (s->size() != strlen(s->data())) {
mpz_init_set_si(rtn->n, static_cast<BoxedInt*>(r)->n); Box* srepr = PyObject_Repr(val);
} else if (!PyLong_Check(r)) { if (S == CAPI) {
raiseExcHelper(TypeError, "__long__ returned non-long (type %s)", r->cls->tp_name); PyErr_Format(PyExc_ValueError, "invalid literal for long() with base %d: %s", base,
PyString_AS_STRING(srepr));
return NULL;
} else { } else {
return static_cast<BoxedLong*>(r); raiseExcHelper(ValueError, "invalid literal for long() with base %d: %s", base,
PyString_AS_STRING(srepr));
} }
} }
Box* r = PyLong_FromString(s->data(), NULL, base);
if (!r) {
if (S == CAPI)
return NULL;
else
throwCAPIException();
}
return r;
} else {
// only for unicode and its subtype, other type will be filtered out in above
Box* r = PyLong_FromUnicode(PyUnicode_AS_UNICODE(val), PyUnicode_GET_SIZE(val), base);
if (!r) {
if (S == CAPI)
return NULL;
else
throwCAPIException();
}
return r;
} }
return rtn;
} }
extern "C" Box* longNew(Box* _cls, Box* val, Box* _base) { template <ExceptionStyle S> Box* longNew(Box* _cls, Box* val, Box* base) noexcept(S == CAPI) {
if (!PyType_Check(_cls)) if (!PyType_Check(_cls)) {
raiseExcHelper(TypeError, "long.__new__(X): X is not a type object (%s)", getTypeName(_cls)); if (S == CAPI) {
PyErr_Format(TypeError, "long.__new__(X): X is not a type object (%s)", getTypeName(_cls));
return NULL;
} else
raiseExcHelper(TypeError, "long.__new__(X): X is not a type object (%s)", getTypeName(_cls));
}
BoxedClass* cls = static_cast<BoxedClass*>(_cls); BoxedClass* cls = static_cast<BoxedClass*>(_cls);
if (!isSubclass(cls, long_cls)) if (!isSubclass(cls, long_cls)) {
raiseExcHelper(TypeError, "long.__new__(%s): %s is not a subtype of long", getNameOfClass(cls), if (S == CAPI) {
getNameOfClass(cls)); PyErr_Format(TypeError, "long.__new__(%s): %s is not a subtype of long", getNameOfClass(cls),
getNameOfClass(cls));
return NULL;
} else
raiseExcHelper(TypeError, "long.__new__(%s): %s is not a subtype of long", getNameOfClass(cls),
getNameOfClass(cls));
}
BoxedLong* l = (BoxedLong*)_longNew<S>(val, base);
BoxedLong* l = _longNew(val, _base);
if (cls == long_cls) if (cls == long_cls)
return l; return l;
...@@ -718,9 +765,11 @@ Box* longInt(Box* v) { ...@@ -718,9 +765,11 @@ Box* longInt(Box* v) {
int overflow = 0; int overflow = 0;
long n = PyLong_AsLongAndOverflow(v, &overflow); long n = PyLong_AsLongAndOverflow(v, &overflow);
static_assert(sizeof(BoxedInt::n) == sizeof(long), ""); static_assert(sizeof(BoxedInt::n) == sizeof(long), "");
if (overflow) if (overflow) {
return v; BoxedLong* rtn = new BoxedLong();
else mpz_init_set(rtn->n, ((BoxedLong*)v)->n);
return rtn;
} else
return new BoxedInt(n); return new BoxedInt(n);
} }
...@@ -1386,6 +1435,10 @@ extern "C" Box* longBitLength(BoxedLong* self) noexcept { ...@@ -1386,6 +1435,10 @@ extern "C" Box* longBitLength(BoxedLong* self) noexcept {
if (!PyLong_Check(self)) if (!PyLong_Check(self))
raiseExcHelper(TypeError, "descriptor 'bit_length' requires a 'long' object but received a '%s'", raiseExcHelper(TypeError, "descriptor 'bit_length' requires a 'long' object but received a '%s'",
getTypeName(self)); getTypeName(self));
if (mpz_sgn(self->n) == 0) {
return boxLong(0);
}
size_t bits = mpz_sizeinbase(self->n, 2); size_t bits = mpz_sizeinbase(self->n, 2);
return boxLong(bits); return boxLong(bits);
} }
...@@ -1460,8 +1513,10 @@ void setupLong() { ...@@ -1460,8 +1513,10 @@ void setupLong() {
mp_set_memory_functions(customised_allocation, customised_realloc, customised_free); mp_set_memory_functions(customised_allocation, customised_realloc, customised_free);
_addFuncPow("__pow__", UNKNOWN, (void*)longPowFloat, (void*)longPow); _addFuncPow("__pow__", UNKNOWN, (void*)longPowFloat, (void*)longPow);
long_cls->giveAttr("__new__", auto long_new
new BoxedFunction(boxRTFunction((void*)longNew, UNKNOWN, 3, false, false), { boxInt(0), NULL })); = boxRTFunction((void*)longNew<CXX>, UNKNOWN, 3, false, false, ParamNames({ "", "x", "base" }, "", ""), CXX);
addRTFunction(long_new, (void*)longNew<CAPI>, UNKNOWN, CAPI);
long_cls->giveAttr("__new__", new BoxedFunction(long_new, { boxInt(0), NULL }));
long_cls->giveAttr("__mul__", new BoxedFunction(boxRTFunction((void*)longMul, UNKNOWN, 2))); long_cls->giveAttr("__mul__", new BoxedFunction(boxRTFunction((void*)longMul, UNKNOWN, 2)));
long_cls->giveAttr("__rmul__", long_cls->getattr(internStringMortal("__mul__"))); long_cls->giveAttr("__rmul__", long_cls->getattr(internStringMortal("__mul__")));
......
...@@ -122,3 +122,27 @@ a = 2389134823414823408429384238403228392384028439480234823 ...@@ -122,3 +122,27 @@ a = 2389134823414823408429384238403228392384028439480234823
print +a print +a
print +long.__new__(C, 5L) print +long.__new__(C, 5L)
print type(+long.__new__(C, 5L)) print type(+long.__new__(C, 5L))
print((0L).bit_length())
values = ['inf', '-inf', 'nan']
for v in values:
try:
long(float(v))
except Exception as e:
print(e.message)
class long2(long):
pass
# Overflowing int conversion must return long not long subtype.
x = long2(1L << 100)
y = int(x)
print(type(y))
print(long(unicode("-3")))
print(long(x=10))
print(long(x="10", base=10))
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment