I have a working solution to my problem, but I'm less than satisfied with the result, both when it comes to style and performance.
In short, I need to be able to shift 256 bits of data, say an array of 4 64 bit integer, by n bit, right and left. If other type are easier to work with for some reason, it's really all the same to me.
My current implementation, which seems to work:
void shl( uint64_t * const b, uint_fast8_t n )
{
for( int i = 3-(n/64); i >= 0 && n >=64; --i )
b[i+n/64] = b[i];
for( int i = n/64-1; i >= 0; --i)
b[i] = 0;
for( int_fast8_t i = 3; i > 0 && (n%64); --i )
b[i] = (b[i] << (n%64)) | (b[i-1] >> (64-(n%64)));
b[0] <<= n%64;
}
void shr( uint64_t * const b, uint_fast8_t n )
{
for( int i = 0; i < 4-(n/64) && n >=64; ++i )
b[i] = b[i+n/64];
for( int i = 4-n/64; i < 4; ++i )
b[i] = 0;
for( int i = 0; i < 3 && (n%64); ++i )
b[i] = (b[i] >> (n%64)) | (b[i+1] << (64-(n%64)));
b[3] >>= n%64;
}
I have no need for a general solution, and in case it matters, I need not shift more than 192 bits in a given direction.
Anyway, what I have made, is absolutely awful. I have been searching for alternatives, but what little I've found has been limited to work within the width of the chosen type, in this case 64, or it has simply not been working. I'm sure the above can be optimized, but frankly, I'd prefer a different solution all together.
My first thought was to mess around with pointers, but I have yet to come up with with how that would actually work, so I've got nothing.
I would very much appreciate any ideas.
Also, I did just find one mistake, which has been corrected, so there may be more.
Update: Another approach, that is really the same, though slightly more efficient:
void shl( uint64_t * const b, const uint_fast8_t n )
{
// If n != 0, we run through the 4 elements descending.
for( int i = 3; n && i >= 0; --i )
// Do we need to assign current element a value?
if( i >= n/64 )
{
b[i] = b[i - n/64] << ( n%64 );
// Check to avoid OOB and special case where n is a multiple of 64.
if( i > n/64 && n%64 )
b[i] |= b[i - n/64 - 1] >> ( 64 - ( n%64 ) );
}
// if not, value should be zero.
else b[i] = 0;
}
void shr( uint64_t * const b, const uint_fast8_t n )
{
// If n != 0, we run through the 4 elements ascending.
for( int i = 0; n && i < 4; ++i )
// Do we need to assign current element a value?
if( i < 4 - n/64 )
{
b[i] = b[i + n/64] >> ( n%64 );
// Check to avoid OOB and special case where n is a multiple of 64.
if( i < 4 - n/64 - 1 < 4 && n%64 )
b[i] |= b[i + n/64 + 1] << ( 64 - ( n%64 ) );
}
// if not, value should be zero.
else b[i] = 0;
}
It seems to work, and unlike the other version, I can live with this, but still, there must be another way.