Overview

Namespaces

  • esperecyan
    • webidl
      • lib

Classes

  • BooleanType
  • DictionaryType
  • FloatType
  • IntegerType
  • NullableType
  • ObjectType
  • SequenceType
  • StringType
  • Type
  • UnionType

Traits

  • Error
  • Overview
  • Namespace
  • Class
  • Tree
  1:   2:   3:   4:   5:   6:   7:   8:   9:  10:  11:  12:  13:  14:  15:  16:  17:  18:  19:  20:  21:  22:  23:  24:  25:  26:  27:  28:  29:  30:  31:  32:  33:  34:  35:  36:  37:  38:  39:  40:  41:  42:  43:  44:  45:  46:  47:  48:  49:  50:  51:  52:  53:  54:  55:  56:  57:  58:  59:  60:  61:  62:  63:  64:  65:  66:  67:  68:  69:  70:  71:  72:  73:  74:  75:  76:  77:  78:  79:  80:  81:  82:  83:  84:  85:  86:  87:  88:  89:  90:  91:  92:  93:  94:  95:  96:  97:  98:  99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127: 128: 129: 130: 131: 132: 133: 134: 135: 136: 137: 138: 139: 140: 141: 142: 143: 144: 145: 146: 147: 148: 149: 150: 151: 152: 153: 154: 155: 156: 157: 158: 159: 160: 161: 162: 163: 164: 165: 166: 167: 168: 169: 170: 171: 172: 173: 174: 175: 176: 177: 178: 179: 180: 181: 182: 183: 184: 185: 186: 187: 188: 189: 190: 191: 192: 193: 194: 195: 196: 197: 198: 199: 200: 201: 202: 203: 204: 205: 206: 207: 208: 209: 210: 211: 212: 213: 214: 215: 216: 
<?php
namespace esperecyan\webidl\lib;

/** @internal */
class IntegerType
{
    use Utility;
    
    /** @var int PHP がサポートする整数型の最小値。 */
    private static $phpIntMin = ~PHP_INT_MAX;
    
    /**
     * 与えられた値が整数型に変換可能であれば真を返します。
     *
     * 次の型の値が整数型に変換可能であるとみなされます。
     * 論理型。整数型。浮動小数点型。文字列型。リソース型。オブジェクト型のうち、GMP のインスタンス。
     * @param mixed $value
     * @return bool
     */
    public static function isIntegerCastable($value)
    {
        return is_scalar($value) || is_resource($value) || $value instanceof \GMP;
    }
    
    /**
     * 与えられた値を整数型に変換して返します。
     * @link https://triple-underscore.github.io/WebIDL-ja.html#es-integer-types Web IDL (第2版 — 日本語訳)
     * @param bool|int|float|string|resource|\GMP $value
     * @param string $type byte、octet、short、unsigned short、long、unsigned long、long long、unsigned long long
     * @param int|float $min 浮動小数点型で正確に扱える整数の範囲よりも、整数型で扱える整数の範囲が狭ければ (整数型が32bitである環境なら) 浮動小数点数。
     * @param int|float $max 浮動小数点型で正確に扱える整数の範囲よりも、整数型で扱える整数の範囲が狭ければ (整数型が32bitである環境なら) 浮動小数点数。
     * @param int $bits
     * @param booelan $signed
     * @param string $extendedAttribute 拡張属性。[EnforceRange] か [Clamp] のいずれか。
     * @return int|float 整数型の範囲を超える場合は浮動小数点数。
     * @throws \InvalidArgumentException 配列、NULL が与えられた場合。または、GMP 以外のオブジェクトが与えられた場合。
     * @throws \DomainException $extendedAttribute が [EnforceRange]、かつ与えられたの値が $min 〜 $max に収まらなかった場合。
     */
    private static function toInteger($value, $type, $min, $max, $bits, $signed, $extendedAttribute = null)
    {
        /** @var string 要求される型。 */
        $expectedType = sprintf(
            '%s (an integer in the range of %s to %s)',
            $type,
            is_float($min) ? number_format($min, 0, '', '') : $min,
            is_float($max) ? number_format($max, 0, '', '') : $max
        );
        
        if (!self::isIntegerCastable($value)) {
            throw new \InvalidArgumentException(ErrorMessageCreator::create($value, $expectedType));
        }
        
        if ($value instanceof \GMP || is_resource($value) && get_resource_type($value) === 'GMP integer') {
            // GMP数であれば、あらかじめ文字列に変換しておく
            $value = gmp_strval($value);
        }
        
        /** @var int|float 与えられた値の数値表現。整数型の範囲を超える場合は浮動小数点数。整数値となる場合、小数部があれば0方向へ丸められる。 */
        $number = is_float($value) || (float)$value < self::$phpIntMin || (float)$value > PHP_INT_MAX
            ? (float)$value
            : (int)$value;
    
        if ($extendedAttribute === '[EnforceRange]') {
            /** @var int|float 与えられた値の整数表現。整数型の範囲を超える場合は浮動小数点数。 */
            $integer = self::roundTowardZero($number);
            if (!is_finite($number) || $integer < $min || $integer > $max) {
                throw new \DomainException(ErrorMessageCreator::create($value, $expectedType));
            }
        } elseif (!is_nan($number) && $extendedAttribute === '[Clamp]') {
            $number = min($max, max($number, $min));
            $integer = is_float($number) ? round($number, 0, PHP_ROUND_HALF_EVEN) : $number;
        } elseif (!is_finite($number)) {
            $integer = 0;
        } else {
            $integer = self::modulo(self::roundTowardZero($number), pow(2, $bits));
            if ($signed && $integer >= pow(2, $bits - 1)
                && !(PHP_INT_SIZE === 8 && $bits === 64 && $integer <= PHP_INT_MAX)) {
                $integer -= pow(2, $bits);
            }
        }
        
        return is_float($integer) && $integer >= self::$phpIntMin && $integer <= PHP_INT_MAX
            ? (int)$integer
            : $integer;
    }
    
    /**
     * 与えられた数値を0の方向に丸めた整数を返します。
     * @param float|int $value
     * @return float|int
     */
    private static function roundTowardZero($value)
    {
        return is_float($value) ? ($value >= 0 ? 1 : -1) * floor(abs($value)) : $value;
    }
    
    /**
     * 正の剰余を返します。
     * @link https://www.ecma-international.org/ecma-262/7.0/index.html#sec-algorithm-conventions ECMAScript 2015 Language Specification – ECMA-262 6th Edition
     * @param int|float $x
     * @param int|float $y
     * @return int|float
     */
    private static function modulo($x, $y)
    {
        return ($x < $y ? $x : (is_int($y) ? $x % $y : fmod($x, $y))) + ($x < 0 ? $y : 0);
    }
    
    /**
     * 与えられた値を −128〜127 の範囲の整数に変換して返します。
     * @link https://www.w3.org/TR/WebIDL-1/#idl-byte WebIDL Level 1
     * @param bool|int|float|string|resource|\GMP $value
     * @param string|null $extendedAttribute 拡張属性。[EnforceRange] か [Clamp] のいずれか。
     * @return int
     */
    public static function toByte($value, $extendedAttribute = null)
    {
        return self::toInteger($value, 'byte', -128, 127, 8, true, $extendedAttribute);
    }
    
    /**
     * 与えられた値を 0〜255 の範囲の整数に変換して返します。
     * @link https://www.w3.org/TR/WebIDL-1/#idl-octet WebIDL Level 1
     * @param bool|int|float|string|resource|\GMP $value
     * @param string|null $extendedAttribute 拡張属性。[EnforceRange] か [Clamp] のいずれか。
     * @return int
     */
    public static function toOctet($value, $extendedAttribute = null)
    {
        return self::toInteger($value, 'octet', 0, 255, 8, false, $extendedAttribute);
    }
    
    /**
     * 与えられた値を −32768〜32767 の範囲の整数に変換して返します。
     * @link https://www.w3.org/TR/WebIDL-1/#idl-short WebIDL Level 1
     * @param bool|int|float|string|resource|\GMP $value
     * @param string|null $extendedAttribute 拡張属性。[EnforceRange] か [Clamp] のいずれか。
     * @return int
     */
    public static function toShort($value, $extendedAttribute = null)
    {
        return self::toInteger($value, 'short', -32768, 32767, 16, true, $extendedAttribute);
    }
    
    /**
     * 与えられた値を 0〜65535 の範囲の整数に変換して返します。
     * @link https://www.w3.org/TR/WebIDL-1/#idl-unsigned-short WebIDL Level 1
     * @param bool|int|float|string|resource|\GMP $value
     * @param string|null $extendedAttribute 拡張属性。[EnforceRange] か [Clamp] のいずれか。
     * @return int
     */
    public static function toUnsignedShort($value, $extendedAttribute = null)
    {
        return self::toInteger($value, 'unsigned short', 0, 65535, 16, false, $extendedAttribute);
    }
    
    /**
     * 与えられた値を −2147483648〜2147483647 の範囲の整数に変換して返します。
     * @link https://www.w3.org/TR/WebIDL-1/#idl-long WebIDL Level 1
     * @param bool|int|float|string|resource|\GMP $value
     * @param string|null $extendedAttribute 拡張属性。[EnforceRange] か [Clamp] のいずれか。
     * @return int
     */
    public static function toLong($value, $extendedAttribute = null)
    {
        return self::toInteger($value, 'long', -2147483648, 2147483647, 32, true, $extendedAttribute);
    }
    
    /**
     * 与えられた値を 0〜4294967295 の範囲の整数に変換して返します。
     * @link https://www.w3.org/TR/WebIDL-1/#idl-unsigned-long WebIDL Level 1
     * @param bool|int|float|string|resource|\GMP $value
     * @param string|null $extendedAttribute 拡張属性。[EnforceRange] か [Clamp] のいずれか。
     * @return int|float 32bit版のPHP、またはWindows版のPHP 5.6以前において、整数型の範囲を超える場合は浮動小数点数。
     */
    public static function toUnsignedLong($value, $extendedAttribute = null)
    {
        return self::toInteger($value, 'unsigned long', 0, 4294967295, 32, false, $extendedAttribute);
    }
    
    /**
     * 与えられた値を −9223372036854775808〜9223372036854775807 の範囲の整数に変換して返します。
     * 32bit版のPHP、またはWindows版のPHP 5.6以前では、−9007199254740991〜9007199254740991 の範囲の整数に変換して返します。
     * @link https://www.w3.org/TR/WebIDL-1/#idl-long WebIDL Level 1
     * @param bool|int|float|string|resource|\GMP $value
     * @param string|null $extendedAttribute 拡張属性。[EnforceRange] か [Clamp] のいずれか。
     * @return int|float 32bit版のPHP、またはWindows版のPHP 5.6以前において、整数型の範囲を超える場合は浮動小数点数。
     */
    public static function toLongLong($value, $extendedAttribute = null)
    {
        $longLongMin = self::$phpIntMin > -9007199254740991 ? -9007199254740991 : ~9223372036854775807;
        $longLongMax = PHP_INT_MAX < 9007199254740991 ? 9007199254740991 : 9223372036854775807;
        return self::toInteger($value, 'long long', $longLongMin, $longLongMax, 64, true, $extendedAttribute);
    }
    
    /**
     * 与えられた値を 0〜9223372036854775807 の範囲の整数に変換して返します。
     * 32bit版のPHP、またはWindows版のPHP 5.6以前では、0〜9007199254740991 の範囲の整数に変換して返します。
     * @link https://www.w3.org/TR/WebIDL-1/#idl-unsigned-long-long WebIDL Level 1
     * @param bool|int|float|string|resource|\GMP $value
     * @param string|null $extendedAttribute 拡張属性。[EnforceRange] か [Clamp] のいずれか。
     * @return int|float 32bit版のPHP、またはWindows版のPHP 5.6以前において、整数型の範囲を超える場合は浮動小数点数。
     */
    public static function toUnsignedLongLong($value, $extendedAttribute = null)
    {
        if (PHP_INT_MAX < 9007199254740991) {
            $unsignedLongLongMax = 9007199254740991;
        } elseif (PHP_INT_MAX < 18446744073709551615) {
            $unsignedLongLongMax = PHP_INT_MAX;
        } else {
            $unsignedLongLongMax = 18446744073709551615;
        }
        return self::toInteger($value, 'unsigned long long', 0, $unsignedLongLongMax, 64, false, $extendedAttribute);
    }
}
esperecyan/webidl documentation API documentation generated by ApiGen