8000 minor #36070 [Uid] improve base convertion logic (nicolas-grekas) · symfony/symfony@fa5d636 · GitHub
[go: up one dir, main page]

Skip to content

Commit fa5d636

Browse files
minor #36070 [Uid] improve base convertion logic (nicolas-grekas)
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
2 parents 42c76d7 + 0e05c6d commit fa5d636

File tree

4 files changed

+101
-89
lines changed

4 files changed

+101
-89
lines changed
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Uid;
13+
14+
/**
15+
* @internal
16+
*
17+
* @author Nicolas Grekas <p@tchwork.com>
18+
*/
19+
class BinaryUtil
20+
{
21+
public const BASE10 = [
22+
'' => '0123456789',
23+
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
24+
];
25+
26+
public static function toBase(string $bytes, array $map): string
27+
{
28+
$base = \strlen($alphabet = $map['']);
29+
$bytes = array_values(unpack(\PHP_INT_SIZE >= 8 ? 'n*' : 'C*', $bytes));
30+
$digits = '';
31+
32+
while ($count = \count($bytes)) {
33+
$quotient = [];
34+
$remainder = 0;
35+
36+
for ($i = 0; $i !== $count; ++$i) {
37+
$carry = $bytes[$i] + ($remainder << (\PHP_INT_SIZE >= 8 ? 16 : 8));
38+
$digit = intdiv($carry, $base);
39+
$remainder = $carry % $base;
40+
41+
if ($digit || $quotient) {
42+
$quotient[] = $digit;
43+
}
44+
}
45+
46+
$digits = $alphabet[$remainder].$digits;
47+
$bytes = $quotient;
48+
}
49+
50+
return $digits;
51+
}
52+
53+
public static function fromBase(string $digits, array $map): string
54+
{
55+
$base = \strlen($map['']);
56+
$count = \strlen($digits);
57+
$bytes = [];
58+
59+
while ($count) {
60+
$quotient = [];
61+
$remainder = 0;
62+
63+
for ($i = 0; $i !== $count; ++$i) {
64+
$carry = ($bytes ? $digits[$i] : $map[$digits[$i]]) + $remainder * $base;
65+
66+
if (\PHP_INT_SIZE >= 8) {
67+
$digit = $carry >> 16;
68+
$remainder = $carry & 0xFFFF;
69+
} else {
70+
$digit = $carry >> 8;
71+
$remainder = $carry & 0xFF;
72+
}
73+
74+
if ($digit || $quotient) {
75+
$quotient[] = $digit;
76+
}
77+
}
78+
79+
$bytes[] = $remainder;
80+
$count = \count($digits = $quotient);
81+
}
82+
83+
return pack(\PHP_INT_SIZE >= 8 ? 'n*' : 'C*', ...array_reverse($bytes));
84+
}
85+
86+
public static function add(string $a, string $b): string
87+
{
88+
$carry = 0;
89+
for ($i = 7; 0 <= $i; --$i) {
90+
$carry += \ord($a[$i]) + \ord($b[$i]);
91+
$a[$i] = \chr($carry & 0xFF);
92+
$carry >>= 8;
93+
}
94+
95+
return $a;
96+
}
97+
}

src/Symfony/Component/Uid/InternalUtil.php

Lines changed: 0 additions & 85 deletions
This file was deleted.

src/Symfony/Component/Uid/Ulid.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ public function getTime(): float
121121
base_convert(substr($time, 6, 4), 32, 16)
122122
);
123123

124-
return InternalUtil::toDecimal(hex2bin($time)) / 1000;
124+
return BinaryUtil::toBase(hex2bin($time), BinaryUtil::BASE10) / 1000;
125125
}
126126

127127
public function __toString(): string
@@ -163,7 +163,7 @@ private static function generate(): string
163163
if (\PHP_INT_SIZE >= 8) {
164164
$time = base_convert($time, 10, 32);
165165
} else {
166-
$time = bin2hex(InternalUtil::toBinary($time));
166+
$time = bin2hex(BinaryUtil::fromBase($time, BinaryUtil::BASE10));
167167
$time = sprintf('%s%04s%04s',
168168
base_convert(substr($time, 0, 2), 16, 32),
169169
base_convert(substr($time, 2, 5), 16, 32),

src/Symfony/Component/Uid/Uuid.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,10 +121,10 @@ public function getTime(): float
121121
}
122122

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

127-
return InternalUtil::toDecimal($time) / 10000000;
127+
return BinaryUtil::toBase($time, BinaryUtil::BASE10) / 10000000;
128128
}
129129

130130
public function getMac(): string

0 commit comments

Comments
 (0)
0