#include "mpn_pylong.h"
#if SHIFT >= GMP_NUMB_BITS
#error "Python limb larger than GMP limb !!!"
#endif
static const
unsigned char
__sizebits_tab[128] =
{
0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7
};
#if GMP_LIMB_BITS > 64
#error "word size > 64 unsupported"
#endif
static inline
unsigned long
mpn_sizebits(mp_ptr up, mp_size_t un) {
unsigned long cnt;
mp_limb_t x;
if (un==0) return 0;
cnt = (un - 1) * GMP_NUMB_BITS;
x = up[un - 1];
#if GMP_LIMB_BITS > 32
if ((x >> 32) != 0) { x >>= 32; cnt += 32; }
#endif
#if GMP_LIMB_BITS > 16
if ((x >> 16) != 0) { x >>= 16; cnt += 16; }
#endif
#if GMP_LIMB_BITS > 8
if ((x >> 8) != 0) { x >>= 8; cnt += 8; }
#endif
return cnt + ((x & 0x80) ? 8 : __sizebits_tab[x]);
}
static inline
unsigned long
pylong_sizebits(digit *digits, py_size_t size) {
unsigned long cnt;
digit x;
if (size==0) return 0;
cnt = (size - 1) * SHIFT;
x = digits[size - 1];
#if SHIFT > 32
if ((x >> 32) != 0) { x >>= 32; cnt += 32; }
#endif
#if SHIFT > 16
if ((x >> 16) != 0) { x >>= 16; cnt += 16; }
#endif
#if SHIFT > 8
if ((x >> 8) != 0) { x >>= 8; cnt += 8; }
#endif
return cnt + ((x & 0x80) ? 8 : __sizebits_tab[x]);
}
int
mpn_pylong_size (mp_ptr up, mp_size_t un)
{
return (mpn_sizebits(up, un) + SHIFT - 1) / SHIFT;
}
void
mpn_get_pylong (digit *digits, py_size_t size, mp_ptr up, mp_size_t un)
{
mp_limb_t n1, n0;
mp_size_t i;
int bit_pos;
digit * s = digits + size;
if (un == 0) {
while (size) digits[--size]=0;
return;
}
i = un - 1;
n1 = up[i];
bit_pos = size * SHIFT - i * GMP_NUMB_BITS;
for (;;)
{
bit_pos -= SHIFT;
while (bit_pos >= 0)
{
*--s = (n1 >> bit_pos) & MASK;
bit_pos -= SHIFT;
}
if (i == 0)
break;
n0 = (n1 << -bit_pos) & MASK;
n1 = up[--i];
bit_pos += GMP_NUMB_BITS;
*--s = n0 | (n1 >> bit_pos);
}
}
mp_size_t
mpn_size_from_pylong (digit *digits, py_size_t size)
{
return (pylong_sizebits(digits, size) + GMP_NUMB_BITS - 1) / GMP_NUMB_BITS;
}
void
mpn_set_pylong (mp_ptr up, mp_size_t un, digit *digits, py_size_t size)
{
mp_limb_t n1, d;
mp_size_t i;
int bit_pos;
digit * s = digits + size;
if (size == 0) {
while (un) up[--un]=0;
return;
}
i = un - 1;
n1 = 0;
bit_pos = size * SHIFT - i * GMP_NUMB_BITS;
for (;;)
{
bit_pos -= SHIFT;
while (bit_pos >= 0)
{
d = (mp_limb_t) *--s;
n1 |= (d << bit_pos) & GMP_NUMB_MASK;
bit_pos -= SHIFT;
}
if (i == 0)
break;
d = (mp_limb_t) *--s;
up[i--] = n1 | (d & MASK) >> -bit_pos;
bit_pos += GMP_NUMB_BITS;
n1 = (d << bit_pos) & GMP_NUMB_MASK;
}
up[0] = n1;
}
long
mpn_pythonhash (mp_ptr up, mp_size_t un)
{
mp_limb_t h = 0;
mp_limb_t h0;
mp_size_t i;
for (i = 0; i < un; i++)
{
h0 = h;
h += up[i];
if (h < h0) h++;
}
return h;
}