Skip to content
This repository has been archived by the owner on Jun 26, 2023. It is now read-only.

Commit

Permalink
GMP関数に対応、リファクタリング
Browse files Browse the repository at this point in the history
  • Loading branch information
k-holy committed Mar 19, 2014
1 parent 50f52bd commit 3f36265
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 116 deletions.
190 changes: 80 additions & 110 deletions src/Volcanus/RadixConverter/RadixConverter.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,26 +28,24 @@ class RadixConverter
/** 62進数 **/
const MAP_ALPHANUMERIC_62 = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';

private $configurations;
/**
* @var array 設定値
*/
private $config;

/**
* @var mixed 値
*/
private $value;

/**
* オブジェクトを初期化します。
* コンストラクタ
*
* @param array 設定配列
* @return $this
*/
public function initialize(array $configurations = array())
public function __construct(array $configurations = array())
{
$this->configurations = array(
'map' => self::MAP_ALPHANUMERIC_62,
'acceptLong' => false,
);
$this->value = null;
if (!empty($configurations)) {
$this->configurations($configurations);
}
return $this;
$this->initialize($configurations);
}

/**
Expand All @@ -62,39 +60,24 @@ public static function instance(array $configurations = array())
}

/**
* コンストラクタ
* オブジェクトを初期化します。
*
* @param array 設定配列
* @return $this
*/
public function __construct(array $configurations = array())
{
$this->initialize($configurations);
}

/**
* 引数なしの場合は全ての設定を配列で返します。
* 引数ありの場合は全ての設定を引数の配列からセットして$thisを返します。
*
* @param array 設定の配列
* @return mixed 設定の配列 または $this
*/
public function configurations()
public function initialize(array $configurations = array())
{
switch (func_num_args()) {
case 0:
return $this->configurations;
case 1:
$configurations = func_get_arg(0);
if (!is_array($configurations)) {
throw new \InvalidArgumentException(
'The configurations is not Array.');
}
$this->config = array(
'map' => self::MAP_ALPHANUMERIC_62,
'acceptLong' => false,
);
$this->value = null;
if (!empty($configurations)) {
foreach ($configurations as $name => $value) {
$this->setConfiguration($name, $value);
$this->config($name, $value);
}
return $this;
}
throw new \InvalidArgumentException('Invalid argument count.');
return $this;
}

/**
Expand All @@ -104,6 +87,7 @@ public function configurations()
* acceptLong
* 整数の最大値を越える値を扱うかどうかのフラグ。
* PHP_INT_MAX以上の数値を扱う場合、このフラグを有効にする必要があります。
* ※GMP関数またはBcMath関数が必要です
*
* map
* N進数への変換用文字列
Expand All @@ -113,11 +97,39 @@ public function configurations()
*/
public function config($name)
{
if (!array_key_exists($name, $this->config)) {
throw new \InvalidArgumentException(
sprintf('The configuration "%s" does not exists.', $name));
}
switch (func_num_args()) {
case 1:
return $this->getConfiguration($name);
return $this->config[$name];
case 2:
$this->setConfiguration($name, func_get_arg(1));
$value = func_get_arg(1);
if (isset($value)) {
switch ($name) {
case 'map':
if (!is_string($value)) {
throw new \InvalidArgumentException(
sprintf('The map is invalid type %s.', (is_object($value))
? get_class($value) : gettype($value)));
}
if (strlen($value) !== strlen(count_chars($value, 3))) {
throw new \InvalidArgumentException(
sprintf('The map "%s" contains same character.', $value));
}
break;
case 'acceptLong':
if ($value) {
if (!extension_loaded('gmp') && !extension_loaded('bcmath')) {
throw new \RuntimeException('BcMath extension and GMP extension is not loaded.');
}
}
$value = (bool)$value;
break;
}
$this->config[$name] = $value;
}
return $this;
}
throw new \InvalidArgumentException('Invalid argument count.');
Expand Down Expand Up @@ -167,8 +179,8 @@ public function __call($method, $args)
case 'encode':
case 'decode':
$value = (isset($args[0])) ? $args[0] : $this->value;
$map = (isset($args[1])) ? $args[1] : $this->getConfiguration('map');
$acceptLong = (isset($args[2])) ? $args[2] : $this->getConfiguration('acceptLong');
$map = (isset($args[1])) ? $args[1] : $this->config('map');
$acceptLong = (isset($args[2])) ? $args[2] : $this->config('acceptLong');
$this->value = static::$method($value, $map, $acceptLong);
return $this;
}
Expand Down Expand Up @@ -202,7 +214,7 @@ public static function __callStatic($method, $args)
*
* @param mixed 変換する数値
* @param string N進数への変換用文字列 (指定のない場合は 62進数)
* @param boolean 整数の最大値を越える値を扱うかどうか (指定のない場合は FALSE)
* @param boolean 整数の最大値を越える値を扱うかどうか (指定のない場合は FALSE) ※GMP関数またはBcMath関数が必要です
* @return string
*/
private static function encode($number, $map = null, $acceptLong = null)
Expand All @@ -213,8 +225,10 @@ private static function encode($number, $map = null, $acceptLong = null)
if (!isset($acceptLong)) {
$acceptLong = false;
}
if ($acceptLong && !extension_loaded('bcmath')) {
throw new \RuntimeException('BcMath extension is not loaded.');
$gmpLoaded = extension_loaded('gmp');
$bcmathLoaded = extension_loaded('bcmath');
if ($acceptLong && !$gmpLoaded && !$bcmathLoaded) {
throw new \RuntimeException('GMP extension and BcMath extension is not loaded.');
}
if (is_string($number) && !ctype_digit($number)) {
throw new \InvalidArgumentException(
Expand All @@ -227,8 +241,16 @@ private static function encode($number, $map = null, $acceptLong = null)
$string = '';
$length = strlen($map);
do {
$offset = ($acceptLong) ? bcmod($number, $length) : $number % $length;
$number = ($acceptLong) ? bcdiv($number, $length) : $number / $length;
if (!$acceptLong) {
$offset = $number % $length;
$number = $number / $length;
} elseif ($gmpLoaded) {
$offset = gmp_strval(gmp_mod(gmp_init($number, 10), gmp_init($length, 10)), 10);
$number = gmp_strval(gmp_div_q(gmp_init($number, 10), gmp_init($length, 10)), 10);
} elseif ($bcmathLoaded) {
$offset = bcmod($number, $length);
$number = bcdiv($number, $length);
}
$string .= $map[$offset];
} while ($number >= 1);
return strrev($string);
Expand All @@ -240,7 +262,7 @@ private static function encode($number, $map = null, $acceptLong = null)
*
* @param string 変換する文字列
* @param string N進数への変換用文字列 (指定のない場合は 62進数)
* @param boolean 整数の最大値を越える値を扱うかどうか (指定のない場合は FALSE)
* @param boolean 整数の最大値を越える値を扱うかどうか (指定のない場合は FALSE) ※GMP関数またはBcMath関数が必要です
* @return mixed string|int
*/
private static function decode($string, $map = null, $acceptLong = null)
Expand All @@ -251,8 +273,10 @@ private static function decode($string, $map = null, $acceptLong = null)
if (!isset($acceptLong)) {
$acceptLong = false;
}
if ($acceptLong && !extension_loaded('bcmath')) {
throw new \RuntimeException('BcMath extension is not loaded.');
$gmpLoaded = extension_loaded('gmp');
$bcmathLoaded = extension_loaded('bcmath');
if ($acceptLong && !$gmpLoaded && !$bcmathLoaded) {
throw new \RuntimeException('GMP extension and BcMath extension is not loaded.');
}
$number = 0;
$length = strlen($map);
Expand All @@ -262,69 +286,15 @@ private static function decode($string, $map = null, $acceptLong = null)
throw new \InvalidArgumentException(
sprintf('The value "%s" includes invalid character "%s".', $string, $char));
}
if ($acceptLong) {
$number = bcadd($number, bcmul($n, bcpow($length, $i)));
} else {
if (!$acceptLong) {
$number += $n * pow($length, $i);
} elseif ($gmpLoaded) {
$number = gmp_strval(gmp_add(gmp_init($number, 10), gmp_mul(gmp_init($n, 10), gmp_pow(gmp_init($length, 10), $i))), 10);
} elseif ($bcmathLoaded) {
$number = bcadd($number, bcmul($n, bcpow($length, $i)));
}
}
return $number;
}

/**
* 指定された設置の値をセットします。
*
* acceptLong
* 整数の最大値を越える値を扱うかどうかのフラグ。
* PHP_INT_MAX以上の数値を扱う場合、このフラグを有効にする必要があります。
*
* map
* N進数への変換用文字列
*
* @param string 設定名
* @param mixed 設定値
*/
private function setConfiguration($name, $value)
{
if (!array_key_exists($name, $this->configurations)) {
throw new \InvalidArgumentException(
sprintf('The configuration "%s" does not exists.', $name));
}
switch ($name) {
case 'map':
if (!is_string($value)) {
throw new \InvalidArgumentException(
sprintf('The map is invalid type %s.', (is_object($value))
? get_class($value) : gettype($value)));
}
if (strlen($value) !== strlen(count_chars($value, 3))) {
throw new \InvalidArgumentException(
sprintf('The map "%s" contains same character.', $value));
}
break;
case 'acceptLong':
if ($value && !extension_loaded('bcmath')) {
throw new \RuntimeException('BcMath extension is not loaded.');
}
$value = (bool)$value;
break;
}
$this->configurations[$name] = $value;
}

/**
* 指定された設置の値を返します。
*
* @param string 設定名
* @return mixed 設定値
*/
private function getConfiguration($name)
{
if (!array_key_exists($name, $this->configurations)) {
throw new \InvalidArgumentException(
sprintf('The configuration "%s" does not exists.', $name));
}
return $this->configurations[$name];
}

}
12 changes: 6 additions & 6 deletions tests/Volcanus/RadixConveter/Test/RadixConverterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -318,20 +318,20 @@ public function testDecodeByCallStaticWithMap()
$this->assertEquals(228, RadixConverter::decode('UNKO', 'OKNU'));
}

/**
* @requires extension bcmath
*/
public function testEncodeByCallStaticWithMapAndAcceptLong()
{
if (!extension_loaded('bcmath') && !extension_loaded('gmp')) {
$this->markTestSkipped('BcMath extension or GMP extension is required.');
}
$this->assertEquals('2lkCB2', RadixConverter::encode('2147483648', RadixConverter::MAP_ALPHANUMERIC_62, true));
$this->assertEquals('aZl8N0y58M8', RadixConverter::encode('9223372036854775808', RadixConverter::MAP_ALPHANUMERIC_62, true));
}

/**
* @requires extension bcmath
*/
public function testDecodeByCallStaticWithMapAndAcceptLong()
{
if (!extension_loaded('bcmath') && !extension_loaded('gmp')) {
$this->markTestSkipped('BcMath extension or GMP extension is required.');
}
$this->assertEquals('2147483648', RadixConverter::decode('2lkCB2', RadixConverter::MAP_ALPHANUMERIC_62, true));
$this->assertEquals('9223372036854775808', RadixConverter::decode('aZl8N0y58M8', RadixConverter::MAP_ALPHANUMERIC_62, true));
}
Expand Down

0 comments on commit 3f36265

Please sign in to comment.