Skip to content

Commit ae266ad

Browse files
committed
implement c
1 parent bb0a5eb commit ae266ad

File tree

1 file changed

+23
-8
lines changed

1 file changed

+23
-8
lines changed

mypyc/lib-rt/int_ops.c

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -584,21 +584,36 @@ double CPyTagged_TrueDivide(CPyTagged x, CPyTagged y) {
584584

585585
// int.bit_length()
586586
CPyTagged CPyTagged_BitLength(CPyTagged self) {
587+
// Handle zero
588+
if (self == 0) {
589+
return 0;
590+
}
591+
592+
// Fast path for small (tagged) ints
593+
if (CPyTagged_CheckShort(self)) {
594+
Py_ssize_t val = CPyTagged_ShortAsSsize_t(self);
595+
Py_ssize_t absval = val < 0 ? -val : val;
596+
int bits = 0;
597+
while (absval) {
598+
absval >>= 1;
599+
bits++;
600+
}
601+
return bits << 1;
602+
}
603+
604+
// Slow path for big ints
587605
PyObject *pyint = CPyTagged_StealAsObject(self);
588606
if (!PyLong_Check(pyint)) {
589607
Py_DECREF(pyint);
590608
PyErr_SetString(PyExc_TypeError, "self must be int");
591609
return CPY_INT_TAG;
592610
}
593-
PyObject *res = PyObject_CallMethod(pyint, "bit_length", NULL);
611+
int bits = _PyLong_NumBits((PyLongObject *)pyint);
594612
Py_DECREF(pyint);
595-
if (!res) {
596-
return CPY_INT_TAG;
597-
}
598-
long value = PyLong_AsLong(res);
599-
Py_DECREF(res);
600-
if (value == -1 && PyErr_Occurred()) {
613+
if (bits < 0) {
614+
// _PyLong_NumBits sets an error on failure
601615
return CPY_INT_TAG;
602616
}
603-
return value << 1;
617+
return bits << 1;
604618
}
619+

0 commit comments

Comments
 (0)