Yeah with the bitmask approach it has to be a power-of-2 to ensure the mask has all relevant bits set.
Example
width of 256: 256-1 = 255 = $FF = %11111111 <- mask has all 1's
width of 100: 100-1 = 99 = $63 = %1100011 <- mask has some 0's, so it'll be screwed up
If you don't want a power of two, you can use the modulo which has more or less the same effect, but doesn't play as nice with negative numbers:
// want a width of 100:
x = x % 100;
Modulo effectively gives you the remainder after a division. So if 'x' is 537 going into the above code, 537 / 100 is 5 with a remainder of 37. So 537 % 100 = 37, effectively performing a wrap at the 100 bound.
The problem is modulo is ill-defined for negative numbers. For purposes of wrapping, you would want (-1)%100 to give you 99... but it might not depending on the implementation. I'm not sure how Java does it, but in C it's very much a "do not do this ever" situation.
You can be a trickster with math, though. Example, 1%100 is 1. And 100-1 is 99. So:
// to wrap with negative support
int width = 100; // <-wrap at 100
// to wrap at 100 (with negative support)
if(x >= 0)
{
// positive number, normal modulo works
x %= width;
}
else
{
// negative number
x = width - (-x % width); // this uses the above trickster logic
// x=-1 .... -x -> 1
// % width -> 1
// width - -> 99
// however this will not completely work for multiples of width.
// Ex: x=-100 ... -x -> 100
// % width -> 0
// width - -> 100 (we want 0, not 100)
// So we can do a final check here
if(x == width)
x = 0;
}
Another solution is to just ensure that you NEVER have a negative x... in which case you can just use modulo.
In any case, you can see how this is more work and more error prone, which is why wrapping maps on retro consoles pretty much were always power-of-2 sizes. It just makes them easier to work with.