Commit 9952d499 authored by Chris Toshok's avatar Chris Toshok

add __trunc__ to float, int, and long classes

parent e6c6f67e
......@@ -652,6 +652,36 @@ Box* floatRepr(BoxedFloat* self) {
return boxString(floatFmt(self->d, 16, 'g'));
}
Box* floatTrunc(BoxedFloat* self) {
if (!isSubclass(self->cls, float_cls))
raiseExcHelper(TypeError, "descriptor '__trunc__' requires a 'float' object but received a '%s'",
getTypeName(self));
double wholepart; /* integral portion of x, rounded toward 0 */
(void)modf(self->d, &wholepart);
/* Try to get out cheap if this fits in a Python int. The attempt
* to cast to long must be protected, as C doesn't define what
* happens if the double is too big to fit in a long. Some rare
* systems raise an exception then (RISCOS was mentioned as one,
* and someone using a non-default option on Sun also bumped into
* that). Note that checking for <= LONG_MAX is unsafe: if a long
* has more bits of precision than a double, casting LONG_MAX to
* double may yield an approximation, and if that's rounded up,
* then, e.g., wholepart=LONG_MAX+1 would yield true from the C
* expression wholepart<=LONG_MAX, despite that wholepart is
* actually greater than LONG_MAX. However, assuming a two's complement
* machine with no trap representation, LONG_MIN will be a power of 2 (and
* hence exactly representable as a double), and LONG_MAX = -1-LONG_MIN, so
* the comparisons with (double)LONG_MIN below should be safe.
*/
if ((double)LONG_MIN <= wholepart && wholepart < -(double)LONG_MIN) {
const long aslong = (long)wholepart;
return PyInt_FromLong(aslong);
}
return PyLong_FromDouble(wholepart);
}
extern "C" void printFloat(double d) {
std::string s = floatFmt(d, 12, 'g');
printf("%s", s.c_str());
......@@ -711,6 +741,9 @@ void setupFloat() {
// float_cls->giveAttr("__nonzero__", new BoxedFunction(boxRTFunction((void*)floatNonzero, NULL, 1)));
float_cls->giveAttr("__str__", new BoxedFunction(boxRTFunction((void*)floatStr, STR, 1)));
float_cls->giveAttr("__repr__", new BoxedFunction(boxRTFunction((void*)floatRepr, STR, 1)));
float_cls->giveAttr("__trunc__", new BoxedFunction(boxRTFunction((void*)floatTrunc, BOXED_INT, 1)));
float_cls->freeze();
}
......
......@@ -916,6 +916,14 @@ extern "C" Box* intOct(BoxedInt* self) {
return new BoxedString(std::string(buf, len));
}
extern "C" Box* intTrunc(BoxedInt* self) {
if (!isSubclass(self->cls, int_cls))
raiseExcHelper(TypeError, "descriptor '__trunc__' requires a 'int' object but received a '%s'",
getTypeName(self));
return self;
}
static Box* _intNew(Box* val, Box* base) {
if (isSubclass(val->cls, int_cls)) {
RELEASE_ASSERT(!base, "");
......@@ -1072,6 +1080,8 @@ void setupInt() {
int_cls->giveAttr("__hex__", new BoxedFunction(boxRTFunction((void*)intHex, STR, 1)));
int_cls->giveAttr("__oct__", new BoxedFunction(boxRTFunction((void*)intOct, STR, 1)));
int_cls->giveAttr("__trunc__", new BoxedFunction(boxRTFunction((void*)intTrunc, BOXED_INT, 1)));
int_cls->giveAttr(
"__new__", new BoxedFunction(boxRTFunction((void*)intNew, UNKNOWN, 3, 2, false, false), { boxInt(0), NULL }));
......
......@@ -1035,6 +1035,14 @@ Box* longHash(BoxedLong* self) {
return boxInt(n);
}
extern "C" Box* longTrunc(BoxedLong* self) {
if (!isSubclass(self->cls, long_cls))
raiseExcHelper(TypeError, "descriptor '__trunc__' requires a 'long' object but received a '%s'",
getTypeName(self));
return self;
}
void* customised_allocation(size_t alloc_size) {
return gc::gc_alloc(alloc_size, gc::GCKind::CONSERVATIVE);
}
......@@ -1097,6 +1105,8 @@ void setupLong() {
long_cls->giveAttr("__nonzero__", new BoxedFunction(boxRTFunction((void*)longNonzero, BOXED_BOOL, 1)));
long_cls->giveAttr("__hash__", new BoxedFunction(boxRTFunction((void*)longHash, BOXED_INT, 1)));
long_cls->giveAttr("__trunc__", new BoxedFunction(boxRTFunction((void*)longTrunc, UNKNOWN, 1)));
long_cls->freeze();
}
}
import math
def type_trunc(type, arg):
try:
print type.__trunc__(arg)
except TypeError as e:
print e
type_trunc(float, 5.25)
type_trunc(float, 5)
type_trunc(float, 5L)
type_trunc(float, "5")
type_trunc(int, 5.25)
type_trunc(int, 5)
type_trunc(int, 5L)
type_trunc(int, "5")
type_trunc(long, 5.25)
type_trunc(long, 5)
type_trunc(long, 5L)
type_trunc(long, "5")
class Test:
def __trunc__(self):
print "made it"
return 5
t = Test()
print math.trunc(t)
class TruncReturnsNonInt:
def __trunc__(self):
print "made it"
return "hi"
t2 = TruncReturnsNonInt()
print math.trunc(t2)
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