Skip to content

Commit

Permalink
minor #36070 [Uid] improve base convertion logic (nicolas-grekas)
Browse files Browse the repository at this point in the history
This PR was merged into the 5.1-dev branch.

Discussion
----------

[Uid] improve base convertion logic

| Q             | A
| ------------- | ---
| Branch?       | master
| Bug fix?      | no
| New feature?  | no
| Deprecations? | no
| Tickets       | -
| License       | MIT
| Doc PR        | -

The new logic is at least twice as fast as the current algo.
It's also way more common and generic.

Commits
-------

0e05c6d [Uid] improve base convertion logic
  • Loading branch information
nicolas-grekas committed Mar 14, 2020
2 parents 42c76d7 + 0e05c6d commit fa5d636
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 89 deletions.
97 changes: 97 additions & 0 deletions src/Symfony/Component/Uid/BinaryUtil.php
@@ -0,0 +1,97 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Component\Uid;

/**
* @internal
*
* @author Nicolas Grekas <p@tchwork.com>
*/
class BinaryUtil
{
public const BASE10 = [
'' => '0123456789',
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
];

public static function toBase(string $bytes, array $map): string
{
$base = \strlen($alphabet = $map['']);
$bytes = array_values(unpack(\PHP_INT_SIZE >= 8 ? 'n*' : 'C*', $bytes));
$digits = '';

while ($count = \count($bytes)) {
$quotient = [];
$remainder = 0;

for ($i = 0; $i !== $count; ++$i) {
$carry = $bytes[$i] + ($remainder << (\PHP_INT_SIZE >= 8 ? 16 : 8));
$digit = intdiv($carry, $base);
$remainder = $carry % $base;

if ($digit || $quotient) {
$quotient[] = $digit;
}
}

$digits = $alphabet[$remainder].$digits;
$bytes = $quotient;
}

return $digits;
}

public static function fromBase(string $digits, array $map): string
{
$base = \strlen($map['']);
$count = \strlen($digits);
$bytes = [];

while ($count) {
$quotient = [];
$remainder = 0;

for ($i = 0; $i !== $count; ++$i) {
$carry = ($bytes ? $digits[$i] : $map[$digits[$i]]) + $remainder * $base;

if (\PHP_INT_SIZE >= 8) {
$digit = $carry >> 16;
$remainder = $carry & 0xFFFF;
} else {
$digit = $carry >> 8;
$remainder = $carry & 0xFF;
}

if ($digit || $quotient) {
$quotient[] = $digit;
}
}

$bytes[] = $remainder;
$count = \count($digits = $quotient);
}

return pack(\PHP_INT_SIZE >= 8 ? 'n*' : 'C*', ...array_reverse($bytes));
}

public static function add(string $a, string $b): string
{
$carry = 0;
for ($i = 7; 0 <= $i; --$i) {
$carry += \ord($a[$i]) + \ord($b[$i]);
$a[$i] = \chr($carry & 0xFF);
$carry >>= 8;
}

return $a;
}
}
85 changes: 0 additions & 85 deletions src/Symfony/Component/Uid/InternalUtil.php

This file was deleted.

4 changes: 2 additions & 2 deletions src/Symfony/Component/Uid/Ulid.php
Expand Up @@ -121,7 +121,7 @@ public function getTime(): float
base_convert(substr($time, 6, 4), 32, 16)
);

return InternalUtil::toDecimal(hex2bin($time)) / 1000;
return BinaryUtil::toBase(hex2bin($time), BinaryUtil::BASE10) / 1000;
}

public function __toString(): string
Expand Down Expand Up @@ -163,7 +163,7 @@ private static function generate(): string
if (\PHP_INT_SIZE >= 8) {
$time = base_convert($time, 10, 32);
} else {
$time = bin2hex(InternalUtil::toBinary($time));
$time = bin2hex(BinaryUtil::fromBase($time, BinaryUtil::BASE10));
$time = sprintf('%s%04s%04s',
base_convert(substr($time, 0, 2), 16, 32),
base_convert(substr($time, 2, 5), 16, 32),
Expand Down
4 changes: 2 additions & 2 deletions src/Symfony/Component/Uid/Uuid.php
Expand Up @@ -121,10 +121,10 @@ public function getTime(): float
}

$time = str_pad(hex2bin($time), 8, "\0", STR_PAD_LEFT);
$time = InternalUtil::binaryAdd($time, self::TIME_OFFSET_COM);
$time = BinaryUtil::add($time, self::TIME_OFFSET_COM);
$time[0] = $time[0] & "\x7F";

return InternalUtil::toDecimal($time) / 10000000;
return BinaryUtil::toBase($time, BinaryUtil::BASE10) / 10000000;
}

public function getMac(): string
Expand Down

0 comments on commit fa5d636

Please sign in to comment.