diff options
Diffstat (limited to 'node_modules/tailwindcss/src/lib/remap-bitfield.js')
| -rw-r--r-- | node_modules/tailwindcss/src/lib/remap-bitfield.js | 82 |
1 files changed, 82 insertions, 0 deletions
diff --git a/node_modules/tailwindcss/src/lib/remap-bitfield.js b/node_modules/tailwindcss/src/lib/remap-bitfield.js new file mode 100644 index 0000000..3ddaf20 --- /dev/null +++ b/node_modules/tailwindcss/src/lib/remap-bitfield.js @@ -0,0 +1,82 @@ +// @ts-check + +/** + * We must remap all the old bits to new bits for each set variant + * Only arbitrary variants are considered as those are the only + * ones that need to be re-sorted at this time + * + * An iterated process that removes and sets individual bits simultaneously + * will not work because we may have a new bit that is also a later old bit + * This means that we would be removing a previously set bit which we don't + * want to do + * + * For example (assume `bN` = `1<<N`) + * Given the "total" mapping `[[b1, b3], [b2, b4], [b3, b1], [b4, b2]]` + * The mapping is "total" because: + * 1. Every input and output is accounted for + * 2. All combinations are unique + * 3. No one input maps to multiple outputs and vice versa + * And, given an offset with all bits set: + * V = b1 | b2 | b3 | b4 + * + * Let's explore the issue with removing and setting bits simultaneously: + * V & ~b1 | b3 = b2 | b3 | b4 + * V & ~b2 | b4 = b3 | b4 + * V & ~b3 | b1 = b1 | b4 + * V & ~b4 | b2 = b1 | b2 + * + * As you can see, we end up with the wrong result. + * This is because we're removing a bit that was previously set. + * And, thus the final result is missing b3 and b4. + * + * Now, let's explore the issue with removing the bits first: + * V & ~b1 = b2 | b3 | b4 + * V & ~b2 = b3 | b4 + * V & ~b3 = b4 + * V & ~b4 = 0 + * + * And then setting the bits: + * V | b3 = b3 + * V | b4 = b3 | b4 + * V | b1 = b1 | b3 | b4 + * V | b2 = b1 | b2 | b3 | b4 + * + * We get the correct result because we're not removing any bits that were + * previously set thus properly remapping the bits to the new order + * + * To collect this into a single operation that can be done simultaneously + * we must first create a mask for the old bits that are set and a mask for + * the new bits that are set. Then we can remove the old bits and set the new + * bits simultaneously in a "single" operation like so: + * OldMask = b1 | b2 | b3 | b4 + * NewMask = b3 | b4 | b1 | b2 + * + * So this: + * V & ~oldMask | newMask + * + * Expands to this: + * V & ~b1 & ~b2 & ~b3 & ~b4 | b3 | b4 | b1 | b2 + * + * Which becomes this: + * b1 | b2 | b3 | b4 + * + * Which is the correct result! + * + * @param {bigint} num + * @param {[bigint, bigint][]} mapping + */ +export function remapBitfield(num, mapping) { + // Create masks for the old and new bits that are set + let oldMask = 0n + let newMask = 0n + for (let [oldBit, newBit] of mapping) { + if (num & oldBit) { + oldMask = oldMask | oldBit + newMask = newMask | newBit + } + } + + // Remove all old bits + // Set all new bits + return (num & ~oldMask) | newMask +} |