I am trying to convert uint24 value of a kind 0x00ff08
to a human readable string
with the same characters in Solidity smart contract which I am going to deploy on RSK. In my question about bytes3 to hex string casting I was advised for these purposes to use a function
function uint24tohexstr(uint24 i) public pure returns (string memory) {
bytes memory o = new bytes(6);
uint24 mask = 0x00000f;
o[5] = bytes1(uint8tohexchar(uint8(i & mask)));
i = i >> 4;
o[4] = bytes1(uint8tohexchar(uint8(i & mask)));
i = i >> 4;
o[3] = bytes1(uint8tohexchar(uint8(i & mask)));
i = i >> 4;
o[2] = bytes1(uint8tohexchar(uint8(i & mask)));
i = i >> 4;
o[1] = bytes1(uint8tohexchar(uint8(i & mask)));
i = i >> 4;
o[0] = bytes1(uint8tohexchar(uint8(i & mask)));
return string(o);
}
I wanted to make use of a loop in that function and rewrote it like this
function uint24ToHexStr(uint24 i) public pure returns (string memory) {
bytes memory o = new bytes(6);
uint24 mask = 0x00000f; // hex 15
for(uint k = 5; k >= 0; k -= 1) {
o[k] = bytes1(uint8ToHexCharCode(uint8(i & mask)));
i >>= 4;
}
return string(o);
}
But unfortunately this function causes runtime error because on the last iteration unsigned integer k
becomes -1
. The first thing that crossed my mind was to increase k by one so that
for(uint k = 6; k >= 1; k -= 1) {
o[k - 1] = bytes1(uint8ToHexCharCode(uint8(i & mask)));
}
Can anyone think of a more elegant way to achieve the same result?
I like the 2nd option in @selbie's answer; and thought what if we used a different type of loop control structure. A regular while
loop would inherit the same "final iteration uint
underflow" problem that the for
loop has. Switching to a do .. while
loop, on the other hand, allows you to shift the evaluation of the condition from being checked before the iteration, to being checked after the iteration. This can be applied to your implementation like so:
function uint24ToHexStr(uint24 i) public pure returns (string memory) {
bytes memory o = new bytes(6);
uint24 mask = 0x00000f; // hex 15
uint k = 6;
do {
k--;
o[k] = bytes1(uint8ToHexCharCode(uint8(i & mask)));
i >>= 4;
} while (k > 0);
return string(o);
}
This avoids both the uint
underflow, and also does not require k - 1
for array indices within the loop. In terms of gas cost, I would "guesstimate" that it would be close to the original implementation of the same function from the previous question. (but actually try both out and compare to confirm)