101 lines
3.4 KiB
PHP
101 lines
3.4 KiB
PHP
|
<?php
|
||
|
// IntegerBaseConverter.php
|
||
|
// Created: 2024-07-31
|
||
|
// Updated: 2024-07-31
|
||
|
|
||
|
namespace Index;
|
||
|
|
||
|
use InvalidArgumentException;
|
||
|
|
||
|
/**
|
||
|
* Provides methods for encoding integers in different bases.
|
||
|
*/
|
||
|
class IntegerBaseConverter {
|
||
|
private int $maxBase;
|
||
|
|
||
|
/**
|
||
|
* @param string $characterSet Specifies the provided character set, must be a string consisting out of at least two unique characters.
|
||
|
* @throws InvalidArgumentException If $characterSet contains less than two characters.
|
||
|
* @throws InvalidArgumentException If $characterSet contains duplicate characters.
|
||
|
*/
|
||
|
public function __construct(
|
||
|
private string $characterSet
|
||
|
) {
|
||
|
$length = strlen($characterSet);
|
||
|
if($length < 2)
|
||
|
throw new InvalidArgumentException('$characterSet must contain at least two characters');
|
||
|
if(XString::countUnique($characterSet) !== $length)
|
||
|
throw new InvalidArgumentException('$characterSet must contain a set of entirely unique characters');
|
||
|
|
||
|
$this->maxBase = $length;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Converts a positive base10 integer to another base.
|
||
|
*
|
||
|
* @param int $integer The integer to encode.
|
||
|
* @param int $toBase Target base, 0 for the base of the provided character set.
|
||
|
* @return string The encoded data, as a string.
|
||
|
*/
|
||
|
public function encode(int $integer, int $toBase = 0): string {
|
||
|
if($integer < 0)
|
||
|
throw new InvalidArgumentException('$integer contains a negative value, which cannot be represented');
|
||
|
if($toBase === 0)
|
||
|
$toBase = $this->maxBase;
|
||
|
else {
|
||
|
if($toBase < 2)
|
||
|
throw new InvalidArgumentException('lowest supported value for $toBase is 2');
|
||
|
if($toBase > $this->maxBase)
|
||
|
throw new InvalidArgumentException('specified $toBase value is greater than the amount of characters in the provided character set');
|
||
|
}
|
||
|
|
||
|
if($integer === 0)
|
||
|
return '';
|
||
|
|
||
|
$output = '';
|
||
|
|
||
|
for($i = floor(log10($integer) / log10($toBase)); $i >= 0; --$i) {
|
||
|
$exp = $toBase ** $i;
|
||
|
$index = (int)floor($integer / $exp);
|
||
|
$output .= $this->characterSet[$index];
|
||
|
$integer -= $index * $exp;
|
||
|
}
|
||
|
|
||
|
return $output;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Converts another base encoded integer to a base10 integer.
|
||
|
*
|
||
|
* @param string $string The encoded integer.
|
||
|
* @param int $fromBase Source base, 0 for the base of the provided character set.
|
||
|
* @return int|false Returns the decoded integer or false on failure.
|
||
|
*/
|
||
|
public function decode(string $string, int $fromBase = 0): int|false {
|
||
|
if($fromBase === 0)
|
||
|
$fromBase = $this->maxBase;
|
||
|
else {
|
||
|
if($fromBase < 2)
|
||
|
throw new InvalidArgumentException('lowest supported value for $fromBase is 2');
|
||
|
if($fromBase > $this->maxBase)
|
||
|
throw new InvalidArgumentException('specified $fromBase value is greater than the amount of characters in the provided character set');
|
||
|
}
|
||
|
|
||
|
if($string === '')
|
||
|
return 0;
|
||
|
|
||
|
$output = 0;
|
||
|
$length = strlen($string) - 1;
|
||
|
|
||
|
for($i = 0; $i <= $length; ++$i) {
|
||
|
$pos = strpos($this->characterSet, $string[$i]);
|
||
|
if($pos === false)
|
||
|
return false;
|
||
|
|
||
|
$output += $pos * ($fromBase ** ($length - $i));
|
||
|
}
|
||
|
|
||
|
return $output;
|
||
|
}
|
||
|
}
|