1

I'm looking to store 4 unsigned values, one boolean (or int), two integers with a max of (and including) 64 and one integer which can store at least 100,000. into a single hash.

Using information I found here

I can encode and decode between 2 - 4 integer's with a max of 255 like so

static int encode(int a, int b, int c, int d) {
    return a & 0xff | (b << 8) | (c << 16) + (d << 24);
}

static int[] decode(int encoded) {
    return new int[] {
            encoded & 0xff,
            (encoded >> 8 & 0xff),
            (encoded >> 16 & 0xff),
            (encoded >> 24 & 0xff)
    };
}

And using information found here I can encode and decode two 32 bit integers.

long hash = (long) a << 32 | b & 0xFFFFFFFFL;
int aBack = (int) (hash >> 32);
int bBack = (int) hash;

I just don't understand bitwise operators well enough to figure out how to mix and match to store integers of different sizes.

How can I use bit masks to encode 4 integers of different sizes into one integer and back?

Greg
  • 754
  • 9
  • 18

1 Answers1

2

I would not call this a hash exactly since it's designed to be reversible, but it could be used as a hash.

Assign some positions to the parts, for example (I've made the middle parts 7 bits each now, since they apparently go up to and including 64):

  • bit a (bit 0)
  • uint7 b (bits 1 through 7)
  • uint7 c (bits 8 through 14)
  • the rest d (15 through 31)

I will assume all values are meant to be non-negative since it seemed like that what you meant (for example specifying only upper limits).

To encode, shift every field left by its offset and combine, for example:

int res = a | (b << 1) | (c << 8) | (d << 15);

To decode, shift right by the field offset and mask:

a = x & 1;
b = (x >> 1) & 0x7F;
c = (x >> 8) & 0x7F;
d = (x >> 15) & 0x1FFFF;

d has 17 bits available to it, which is just enough for its range. For high values of d, res would be negative.

harold
  • 61,398
  • 6
  • 86
  • 164
  • Yes up to and including 64 and 0. Thanks for the terminology clarification too, is there a word I should use instead? You named your various res, is there any significance to it? To clarify, in your example you shift each value by the total number of bits of the previous value? a is 1 bit, b is shifted 1, b is 6 bits, c is shifted 7 etc... So to increase the middle to 7 bits. I did a | (b << 1) | (c << 8) | (d << 14), then increased the two AND operators to 0x4F but testing that means D has a value +1? – Greg Sep 24 '17 at 16:33
  • 1
    @Greg a mask for 7 bits would be `0x7F`, and the shifts should be by 8 and 15 (the field `c` is also 7 bits, so an extra bit is added). There is no significance to the names really. – harold Sep 24 '17 at 16:49