Skip to content

Commit

Permalink
Merge branch into fast_toString
Browse files Browse the repository at this point in the history
  • Loading branch information
Amxx committed Jul 25, 2022
2 parents 029c82e + 365e07b commit 8597e3d
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 80 deletions.
28 changes: 15 additions & 13 deletions contracts/utils/Strings.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,45 +15,47 @@ library Strings {
*/
function toString(uint256 value) internal pure returns (string memory result) {
unchecked {
if (value < 10) {
return string(abi.encodePacked(uint8(value + 48)));
}
uint256 length = 0;
uint256 length = 1;

// compute log10(value), and add it to length
uint256 valueCopy = value;
if (valueCopy >= 10**63) {
if (valueCopy >= 10**64) {
valueCopy /= 10**64;
length += 64;
}
if (valueCopy >= 10**31) {
if (valueCopy >= 10**32) {
valueCopy /= 10**32;
length += 32;
}
if (valueCopy >= 10**15) {
if (valueCopy >= 10**16) {
valueCopy /= 10**16;
length += 16;
}
if (valueCopy >= 10**7) {
if (valueCopy >= 10**8) {
valueCopy /= 10**8;
length += 8;
}
if (valueCopy >= 10**3) {
if (valueCopy >= 10**4) {
valueCopy /= 10**4;
length += 4;
}
if (valueCopy >= 10**1) {
if (valueCopy >= 10**2) {
valueCopy /= 10**2;
length += 2;
}
if (valueCopy >= 1) {
if (valueCopy >= 10**1) {
length += 1;
}
// now, length is log10(value) + 1
result = new string(length);

This comment has been minimized.

Copy link
@CodeSandwich

CodeSandwich Jul 25, 2022

Owner

It creates a string 1 character too long in all cases except 0

This comment has been minimized.

Copy link
@Amxx

Amxx Jul 25, 2022

Author

Test don't show that.

/// @solidity memory-safe-assembly
assembly {
let ptr := add(result, add(length, 32))
let pos := add(result, 32)
let ptr := add(pos, length)

for {

} gt(value, 0) {
} gt(ptr, pos) {

} {
ptr := sub(ptr, 1)
Expand Down
93 changes: 26 additions & 67 deletions test/utils/Strings.test.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const { constants, expectRevert } = require('@openzeppelin/test-helpers');
const { BN, constants, expectRevert } = require('@openzeppelin/test-helpers');

const { expect } = require('chai');

Expand All @@ -12,73 +12,32 @@ contract('Strings', function (accounts) {
});

describe('toString', function () {
async function testToString (input) {
expect(await strings.toStringDecimal(input)).to.equal(input);
for (const [ key, value ] of Object.entries([
'0',
'7',
'10',
'99',
'100',
'101',
'123',
'4132',
'12345',
'1234567',
'1234567890',
'123456789012345',
'12345678901234567890',
'123456789012345678901234567890',
'1234567890123456789012345678901234567890',
'12345678901234567890123456789012345678901234567890',
'123456789012345678901234567890123456789012345678901234567890',
'1234567890123456789012345678901234567890123456789012345678901234567890',
].reduce((acc, value) => Object.assign(acc, { [value]: new BN(value) }), {
MAX_UINT256: constants.MAX_UINT256.toString(),
}))) {
it(`converts ${key}`, async function () {
expect(await strings.toStringDecimal(value)).to.equal(value.toString(10));
});
}

it('converts 0', async function () {
await testToString('0');
});

it('converts 7', async function () {
await testToString('7');
});

it('converts 42', async function () {
await testToString('42');
});

it('converts 123', async function () {
await testToString('123');
});

it('converts 4132', async function () {
await testToString('4132');
});

it('converts 12345', async function () {
await testToString('12345');
});

it('converts 1234567', async function () {
await testToString('1234567');
});

it('converts 1234567890', async function () {
await testToString('1234567890');
});

it('converts 123456789012345', async function () {
await testToString('123456789012345');
});

it('converts 12345678901234567890', async function () {
await testToString('12345678901234567890');
});

it('converts 123456789012345678901234567890', async function () {
await testToString('123456789012345678901234567890');
});

it('converts 1234567890123456789012345678901234567890', async function () {
await testToString('1234567890123456789012345678901234567890');
});

it('converts 12345678901234567890123456789012345678901234567890', async function () {
await testToString('12345678901234567890123456789012345678901234567890');
});

it('converts 123456789012345678901234567890123456789012345678901234567890', async function () {
await testToString('123456789012345678901234567890123456789012345678901234567890');
});

it('converts 1234567890123456789012345678901234567890123456789012345678901234567890', async function () {
await testToString('1234567890123456789012345678901234567890123456789012345678901234567890');
});

it('converts MAX_UINT256', async function () {
await testToString(constants.MAX_UINT256.toString());
});
});

describe('toHexString', function () {
Expand Down

0 comments on commit 8597e3d

Please sign in to comment.