Challenge | Hex decoder |
---|---|

Submitter | hyszeth.eth |

Submitted at | 2018-46-24 |

Gas used | 888018 |

```
/**
* This file is part of the 1st Solidity Gas Golfing Contest.
*
* This work is licensed under Creative Commons Attribution ShareAlike 3.0.
* https://creativecommons.org/licenses/by-sa/3.0/
* Author: Greg Hysen (@hysz)
* Date: June 2018
*/
pragma solidity 0.4.24;
contract HexDecoder {
/**
* @dev Decodes a hex-encoded input string, returning it in binary.
*
* Input strings may be of any length, but will always be a multiple of two
* bytes long, and will not contain any non-hexadecimal characters.
*
* @param input The hex-encoded input.
* @return The decoded output.
*/
function decode(string input) public pure returns(bytes output) {
uint j = 0;
uint inputLen = bytes(input).length;
if(inputLen == 0) return output;
// Assumption: all competition inputs are multiples of 2 (this assumption saves gas)
output = new bytes(inputLen / 2); // +1 because we need to round up
inputLen -= 1;
for(uint i = 0; i < inputLen; i += 2) {
// Combine left & right into one whole byte
output[j++] = byte(
getHalfOfByte(uint(bytes(input)[i+1])) +
getHalfOfByte(uint(bytes(input)[i])) * 16
);
}
}
function getHalfOfByte(uint hexLetter) internal pure returns (uint) {
/*
[0-9] is 0x30 to 0x39
[a-f] is 0x41 to 0x46
[A-F] is 0x61 to 0x66
We take advantage of these ranges to construct the conversion below.
#1
ASCII `0` maps to 48, so `0 % 16` == 0x0, `1 % 16` == 0x1, ...
ASCII `a` and ASCII `A` map to 65 and 97, respectively; so
`a % 16` == 0x1 and `A % 16` == 0x1.
The correct mapping is `a%16 + 9` and `A%16 + 9`.
* For a-f/A-F we add 9, and for 0-9 we do not.
#2
Looking at the binary representations of these character ranges,
a-f and A-F have a leading `1` (for 64). The range 0-9 does not
have this. By dividing by 64 we'll shift this MSB bit to equal 1
for a-f/A-F and 0 for 0-9.
* We can then multiply this value by 9 to get the correct offset.
#3 It's cheaper to & than %, so rather than %16 we &15.
*/
return (hexLetter/uint(64)) * 9 + hexLetter & 15;
}
}
```