I recently had a small need for a bitwise XOR, and was disappointed that Corona’s bit plugin is only available at Pro (or Enterprise) subscription levels.
Drat. My need wasn’t great enough to justify that expense. Though note that if you do have need for thousands of XOR’s, particularly if 16- or 32-bit, then you may indeed need the native code of the plugin — interpreted Lua simply can’t match that performance. But if your needs are more modest, then perhaps there’s an alternative…
For myself, I headed off to the Lua Wiki where I knew there to be several pure Lua implementations.
Alas, while there are many capable implementations listed there, they’re all just a bit too capable for my purposes. Because the downside of being fully capable (dealing with 32-bit quantities, etc) and general-purpose means that their performance isn’t very snappy on a mobile device.
I just needed a special-purpose 8-bit xor, for dealing with values you might obtain from string.byte(), for example. So I scoured the list archive and found what looked like a good starting point. (and I couldn’t have aksed for a better authority than Roberto! 🙂 )
Basically all I’ve done here is just cripple it a bit, for 8-bit use only, then unrolled the loop and removed some intermediate values where not reused, just to gain back a bit of performance.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
local xor4tab = { { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }, { 1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12, 15, 14 }, { 2, 3, 0, 1, 6, 7, 4, 5, 10, 11, 8, 9, 14, 15, 12, 13 }, { 3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12 }, { 4, 5, 6, 7, 0, 1, 2, 3, 12, 13, 14, 15, 8, 9, 10, 11 }, { 5, 4, 7, 6, 1, 0, 3, 2, 13, 12, 15, 14, 9, 8, 11, 10 }, { 6, 7, 4, 5, 2, 3, 0, 1, 14, 15, 12, 13, 10, 11, 8, 9 }, { 7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8 }, { 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7 }, { 9, 8, 11, 10, 13, 12, 15, 14, 1, 0, 3, 2, 5, 4, 7, 6 }, {10, 11, 8, 9, 14, 15, 12, 13, 2, 3, 0, 1, 6, 7, 4, 5 }, {11, 10, 9, 8, 15, 14, 13, 12, 3, 2, 1, 0, 7, 6, 5, 4 }, {12, 13, 14, 15, 8, 9, 10, 11, 4, 5, 6, 7, 0, 1, 2, 3 }, {13, 12, 15, 14, 9, 8, 11, 10, 5, 4, 7, 6, 1, 0, 3, 2 }, {14, 15, 12, 13, 10, 11, 8, 9, 6, 7, 4, 5, 2, 3, 0, 1 }, {15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 } } local function xor8(a,b) --[[ -- ASSERTIONS / ASSUMPTIONS -- this routine ONLY supports 8-bit integer values, for example as returned by string.byte() -- call it wisely and you won't actually need these asserts to babysit: assert( (type(a)=="number") and (a>=0) and (a<=255) and (math.floor(a)==a), "byte value required" ) assert( (type(b)=="number") and (b>=0) and (b<=255) and (math.floor(b)==b), "byte value required" ) --]] --[[ -- 8-BIT-ONLY "READABLE" TRANSLATION OF ORIGINAL -- local alo, blo = a%16, b%16 local ahi, bhi = (a-alo)/16, (b-blo)/16 local xorlo = xor4tab[alo+1][blo+1] local xorhi = xor4tab[ahi+1][bhi+1] return xorhi * 16 + xorlo --]] -- -- UNREADABLE OPTIMIZATIONS -- local alo, blo = a%16, b%16 return xor4tab[(a-alo)/16+1][(b-blo)/16+1] * 16 + xor4tab[alo+1][blo+1] end |
That’s about as far as it made sense for me to optimize. (I suppose you could duplicate and premultiply the table to save that final multiply, but it won’t make much difference. Or memoize it out to the full 64K,.. yikes. etc. My feeling was once you start contemplating those sorts of drastic measures, then you should just be using the bit plugin instead.)
And here’s a simple validation suite against the bit plugin:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
-- build.settings plugins section must have: --["plugin.bit"] = { publisherId = "com.coronalabs" } local bit = require("plugin.bit") local bit_bxor = bit.bxor local nerrors = 0 for a = 0, 255 do for b = 0, 255 do local actual = bit_bxor(a,b) if (actual ~= xor8(a,b)) then nerrors = nerrors + 1 end end end assert(nerrors==0, "VALIDATION FAILED") |