summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Objects/longobject.c48
1 files changed, 22 insertions, 26 deletions
diff --git a/Objects/longobject.c b/Objects/longobject.c
index 8de5456..123d570 100644
--- a/Objects/longobject.c
+++ b/Objects/longobject.c
@@ -1214,10 +1214,11 @@ long_lshift(a, b)
longobject *a;
longobject *b;
{
+ /* This version due to Tim Peters */
longobject *z;
long shiftby;
- int newsize, wordshift, loshift, hishift, i, j;
- digit lomask, himask;
+ int oldsize, newsize, wordshift, remshift, i, j;
+ twodigits accum;
shiftby = getlongvalue((object *)b);
if (shiftby == -1L && err_occurred())
@@ -1226,26 +1227,18 @@ long_lshift(a, b)
err_setstr(ValueError, "negative shift count");
return NULL;
}
- if (shiftby > MASK) {
+ if ((long)(int)shiftby != shiftby) {
err_setstr(ValueError, "outrageous left shift count");
return NULL;
}
- if (shiftby % SHIFT == 0) {
- wordshift = shiftby / SHIFT;
- loshift = 0;
- hishift = SHIFT;
- newsize = ABS(a->ob_size) + wordshift;
- lomask = MASK;
- himask = 0;
- }
- else {
- wordshift = shiftby / SHIFT + 1;
- loshift = SHIFT - shiftby%SHIFT;
- hishift = shiftby % SHIFT;
- newsize = ABS(a->ob_size) + wordshift;
- lomask = ((digit)1 << hishift) - 1;
- himask = MASK ^ lomask;
- }
+ /* wordshift, remshift = divmod(shiftby, SHIFT) */
+ wordshift = (int)shiftby / SHIFT;
+ remshift = (int)shiftby - wordshift * SHIFT;
+
+ oldsize = ABS(a->ob_size);
+ newsize = oldsize + wordshift;
+ if (remshift)
+ ++newsize;
z = alloclongobject(newsize);
if (z == NULL)
return NULL;
@@ -1253,13 +1246,16 @@ long_lshift(a, b)
z->ob_size = -(z->ob_size);
for (i = 0; i < wordshift; i++)
z->ob_digit[i] = 0;
- for (i = wordshift, j = 0; i < newsize; i++, j++) {
- if (i > 0)
- z->ob_digit[i-1] |=
- (a->ob_digit[j] << hishift) & himask;
- z->ob_digit[i] =
- (a->ob_digit[j] >> loshift) & lomask;
- }
+ accum = 0;
+ for (i = wordshift, j = 0; j < oldsize; i++, j++) {
+ accum |= a->ob_digit[j] << remshift;
+ z->ob_digit[i] = (digit)(accum & MASK);
+ accum >>= SHIFT;
+ }
+ if (remshift)
+ z->ob_digit[newsize-1] = (digit)accum;
+ else
+ assert(!accum);
return (object *) long_normalize(z);
}