@@ -23,26 +23,12 @@ private function __construct()
2323 {
2424 }
2525
26- /**
27- * Converts a single hexadecimal character to its numeric value.
28- *
29- * @param string $char Single hex character (0-9, a-f, A-F).
30- *
31- * @return int Numeric value (0-15).
32- */
33- private static function parseHexCharacter (string $ char ): int
34- {
35- return match (true ) {
36- $ char >= '0 ' && $ char <= '9 ' => ord ($ char ) - 48 ,
37- $ char >= 'a ' && $ char <= 'f ' => ord ($ char ) - 87 ,
38- $ char >= 'A ' && $ char <= 'F ' => ord ($ char ) - 55 ,
39- default => 0 ,
40- };
41- }
42-
4326 /**
4427 * Converts a hexadecimal string to large base representation.
4528 *
29+ * Processes 8 hexadecimal characters at a time for improved performance,
30+ * reducing loop iterations by 8x compared to single-character processing.
31+ *
4632 * @param string $hexValue Hexadecimal string to convert.
4733 * @param int $base Large base for digit storage (100 million).
4834 *
@@ -51,13 +37,38 @@ private static function parseHexCharacter(string $char): int
5137 private static function convertHexToLargeBase (string $ hexValue , int $ base ): array
5238 {
5339 $ digits = [0 ];
40+ $ len = strlen ($ hexValue );
41+
42+ $ remainder = $ len % 8 ;
43+ $ i = 0 ;
44+
45+ if ($ remainder > 0 ) {
46+ $ chunk = substr ($ hexValue , 0 , $ remainder );
47+ $ chunkValue = (int ) hexdec ($ chunk );
48+ $ carry = $ chunkValue ;
49+ $ multiplier = 1 << $ remainder * 4 ; // 16^remainder = 2^(remainder*4)
50+
51+ for ($ j = 0 , $ jlen = count ($ digits ); $ j < $ jlen ; $ j ++) {
52+ $ current = $ digits [$ j ] * $ multiplier + $ carry ;
53+ $ digits [$ j ] = $ current % $ base ;
54+ $ carry = intdiv ($ current , $ base );
55+ }
56+
57+ while ($ carry > 0 ) {
58+ $ digits [] = $ carry % $ base ;
59+ $ carry = intdiv ($ carry , $ base );
60+ }
61+
62+ $ i = $ remainder ;
63+ }
5464
55- for ($ i = 0 , $ len = strlen ($ hexValue ); $ i < $ len ; $ i ++) {
56- $ hexDigit = self ::parseHexCharacter ($ hexValue [$ i ]);
57- $ carry = $ hexDigit ;
65+ for (; $ i < $ len ; $ i += 8 ) {
66+ $ chunk = substr ($ hexValue , $ i , 8 );
67+ $ chunkValue = (int ) hexdec ($ chunk );
68+ $ carry = $ chunkValue ;
5869
5970 for ($ j = 0 , $ jlen = count ($ digits ); $ j < $ jlen ; $ j ++) {
60- $ current = $ digits [$ j ] * 16 + $ carry ;
71+ $ current = $ digits [$ j ] * 4294967296 + $ carry ; // 16^8 = 2^32 = 4294967296
6172 $ digits [$ j ] = $ current % $ base ;
6273 $ carry = intdiv ($ current , $ base );
6374 }
@@ -108,15 +119,17 @@ private static function convertLargeBaseToBase36(array $digits, int $base): stri
108119 * Converts a hexadecimal string to base36 encoding.
109120 *
110121 * This function performs arbitrary precision base conversion without requiring
111- * the GMP extension. It uses a large intermediate base (100 million) for efficient
112- * arithmetic operations on large numbers.
122+ * the GMP extension. For small values (≤14 hex chars), it uses the native
123+ * base_convert() function for optimal performance. For larger values, it uses
124+ * a large intermediate base (100 million) for efficient arithmetic operations.
113125 *
114126 * Base36 encoding uses digits 0-9 and lowercase letters a-z (36 characters total),
115127 * producing shorter strings than hexadecimal while remaining URL-safe.
116128 *
117129 * Algorithm:
118- * 1. Convert hex string to internal representation using base 100M
119- * 2. Convert internal representation to base36 by repeated division
130+ * 1. Fast path: Use base_convert() for small values (≤14 hex chars / 56 bits)
131+ * 2. Large values: Convert hex string to internal representation using base 100M
132+ * 3. Convert internal representation to base36 by repeated division
120133 *
121134 * @param string $hexValue Hexadecimal string to convert (case-insensitive).
122135 *
@@ -128,6 +141,10 @@ public static function hexToBase36(string $hexValue): string
128141 return '0 ' ;
129142 }
130143
144+ if (strlen ($ hexValue ) <= 14 ) {
145+ return base_convert ($ hexValue , 16 , 36 );
146+ }
147+
131148 $ base = 100_000_000 ;
132149 $ digits = self ::convertHexToLargeBase ($ hexValue , $ base );
133150
0 commit comments