--- longobject.c 2004-09-20 02:14:54.000000000 -0400 +++ longobject_new.c 2004-12-17 23:51:47.419192000 -0500 @@ -2718,15 +2718,14 @@ switch (op) { case '^': if (maska != maskb) { - maska ^= MASK; + /* masks will not be used */ negz = -1; } break; case '&': if (maska && maskb) { op = '|'; - maska ^= MASK; - maskb ^= MASK; + /* masks will not be used */ negz = -1; } break; @@ -2739,7 +2738,8 @@ } break; } - + /* note: unless op == '&', maska, maskb are don't-care now */ + /* JRH: The original logic here was to allocate the result value (z) as the longer of the two operands. However, there are some cases where the result is guaranteed to be shorter than that: AND of two @@ -2752,27 +2752,65 @@ size_a = a->ob_size; size_b = b->ob_size; - size_z = op == '&' - ? (maska - ? size_b - : (maskb ? size_a : MIN(size_a, size_b))) - : MAX(size_a, size_b); + /* + * make size_a >= size_b; + */ + if( size_a < size_b ){ + digit tm; + PyLongObject *t = a; a = b; b = t; + tm = maska; maska = maskb; maskb = tm; + size_z = size_a; size_a = size_b; size_b= size_z; + } + size_z = (op == '&' && !maskb)? size_b: size_a; + z = _PyLong_New(size_z); - if (a == NULL || b == NULL || z == NULL) { + if ( z == NULL) { Py_XDECREF(a); Py_XDECREF(b); - Py_XDECREF(z); return NULL; } + /* + * switch on operation code, loop inside + */ + switch(op) { + case '&': + if( maska|maskb ){ + for (i = 0; i < size_b; ++i) { + diga = a->ob_digit[i] ^ maska; + digb = b->ob_digit[i] ^ maskb; + z->ob_digit[i] = diga & digb; + } + /* + * iob_digit[i] = a->ob_digit[i] ^ maska; + } + break; + } + for (i = 0; i < size_b; ++i) { + z->ob_digit[i] = a->ob_digit[i] & b->ob_digit[i]; + } + if( i < size_z ) goto copytail; + break; + + case '|': + for (i = 0; i < size_b; ++i) { + z->ob_digit[i] = a->ob_digit[i] | b->ob_digit[i]; + } + if( i < size_z ) goto copytail; + break; - for (i = 0; i < size_z; ++i) { - diga = (i < size_a ? a->ob_digit[i] : 0) ^ maska; - digb = (i < size_b ? b->ob_digit[i] : 0) ^ maskb; - switch (op) { - case '&': z->ob_digit[i] = diga & digb; break; - case '|': z->ob_digit[i] = diga | digb; break; - case '^': z->ob_digit[i] = diga ^ digb; break; + case '^': + for (i = 0; i < size_b; ++i) { + z->ob_digit[i] = a->ob_digit[i] ^ b->ob_digit[i]; } + if( i == size_z ) break; + + copytail: + memcpy( &z->ob_digit[i], &a->ob_digit[i], + (size_z-i)*sizeof(digit)); + break; } Py_DECREF(a);