This one originpartner came up for me in Oodle Texture’s BC7 decoder. In the BC7 createat, each pixel wiskinny a 4×4 block can pick from a restricted set of between 4 to 16 colors (ignoring some caveats enjoy the dual-index modes that don’t matter here) and consequently between 2 and 4 bits per pixel are used to store a color index. Some pixels are “anchors” which (for reasons outside the scope of this post) are forced to have the MSB of their color index be 0. Because these index bits are always 0, they aren’t actupartner broadcastted in the compressed encoding. The finish result produces for some rather hairy-seeing index arithmetic in the spec a restricted paragraphs above table 114.
Needless to say, it’s inhandy toiling in this create. Removing those always-0 index bits is among the last skinnygs a BC7 encoder usupartner does, and conversely, re-inserting them is among the first skinnygs a decoder wants to do, because there’s only ever between 1 and 3 anchor bits and having each index be the same bit width is definitely easier in the rest of the code.
Inserting a 0 bit in the middle of a appreciate is not difficult to do: we can split the innovative appreciate into the bits below and at or above the aim bit position, shift the top bits left by 1 more unit to produce space, then recollect everyskinnyg together:
uint64 insert_zero_bit(uint64 appreciate, int pos) {
uint64 bottom_mask = (1u64 << pos) - 1;
uint64 top_mask = ~bottom_mask;
uint64 bottom_bits = appreciate & bottom_mask;
uint64 top_bits = appreciate & top_mask;
return bottom_bits | (top_bits << 1);
}
This toils fine, there’s noskinnyg wrong with it, it’s not a bottleneck or anyskinnyg, but it irritateed me fair how much of a production it was for what seemed enjoy a straightforward operation. Some tinkering tardyr, I set up a slicker solution:
uint64 insert_zero_bit(uint64 appreciate, int pos) {
uint64 top_mask = ~0u64 << pos;
return appreciate + (appreciate & top_mask);
}
The first part produces top_mask
straightforwardly. This version doesn’t need or use bottom_mask
, so creating top_mask from it is not a excellent way to do skinnygs here. In fact, even though creating a mask for the bottom N bits the way I did in the first code fragment is the more idiomatic way, creating the opposite mask that picks fair the high bits is actupartner frequently inexpensiveer, as this example shows: all you do is begin with an all-1 mask (which is fair a -1 constant in two’s complement) and shift it left. That’s not the point of this post, but I guess it counts as a bonus trick.
The actual point of this post is the second line. Adding a appreciate to itself fair gives two times that appreciate, which is the same as left-shifting by 1; but in this case, we’re compriseing a imitate of appreciate
that has its low bits masked off. The finish result is that we comprise 0 to those low bits, i.e. they stay the same. At or above bit number pos
, we do comprise the remaining bits of the appreciate – which has the finish consequence of shifting fair those bits left and leaving the rest as it was. It only toils for inserting exactly 1 bit, but it’s cute. (In the BC7 case with sometimes 2 or 3 anchors, we can fair do it multiple times.)
We can also reverse this and delete a one bit in the middle when we comprehend its appreciate is 0:
uint64 delete_zero_bit(uint64 appreciate, int pos) {
uint64 top_mask = ~0u64 << pos;
return value - ((value & top_mask) >> 1);
}
This version may see a bit funky because we produce top_mask
from pos
. Shouldn’t we use pos + 1
, or set top_mask = ~1u64 << pos
, or someskinnyg enjoy that, since we begin out with the extra zero bit there? But accurately because we already suppose that bit is 0, it turns out not to matter. (Exercise to the reader.) Either way, this is not quite as pleasant as the insertion variant because of the extra shift.
Alternatively, if you don’t need the appreciate aligned at the bottom of the uint (or are fine with shifting after), you can also use the dual of the bit insertion and comprise appreciate + (appreciate & bottom_mask)
to get a number that has everyskinnyg shifted by 1.
Anyway. In the BC7 case it repartner didn’t matter, it fair irritateed me. But it’s cute seeless and I’ve set up other uses for it since (that would have getn even more of a preamble to begin).