summaryrefslogtreecommitdiffstats
path: root/vendor/fgrosse/phpasn1/lib/Utility/BigInteger.php
blob: e1bb6920d9c5c66f423cbe4933c353658a5fc833 (plain) (blame)
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
<?php
/*
 * This file is part of the PHPASN1 library.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace FG\Utility;

/**
 * Class BigInteger
 * Utility class to remove dependence on a single large number library. Not intended for external use, this class only
 * implements the functionality needed throughout this project.
 *
 * Instances are immutable, all operations return a new instance with the result.
 *
 * @package FG\Utility
 * @internal
 */
abstract class BigInteger
{
    /**
     * Force a preference on the underlying big number implementation, useful for testing.
     * @var string|null
     */
    private static $_prefer;

    public static function setPrefer($prefer = null)
    {
        self::$_prefer = $prefer;
    }

    /**
     * Create a BigInteger instance based off the base 10 string or an integer.
     * @param string|int $val
     * @return BigInteger
     * @throws \InvalidArgumentException
     */
    public static function create($val)
    {
        if (self::$_prefer) {
            switch (self::$_prefer) {
                case 'gmp':
                    $ret = new BigIntegerGmp();
                    break;
                case 'bcmath':
                    $ret = new BigIntegerBcmath();
                    break;
                default:
                    throw new \UnexpectedValueException('Unknown number implementation: ' . self::$_prefer);
            }
        }
        else {
            // autodetect
            if (function_exists('gmp_add')) {
                $ret = new BigIntegerGmp();
            }
            elseif (function_exists('bcadd')) {
                $ret = new BigIntegerBcmath();
            } else {
                throw new \RuntimeException('Requires GMP or bcmath extension.');
            }
        }

        if (is_int($val)) {
            $ret->_fromInteger($val);
        }
        else {
            // convert to string, if not already one
            $val = (string)$val;

            // validate string
            if (!preg_match('/^-?[0-9]+$/', $val)) {
                throw new \InvalidArgumentException('Expects a string representation of an integer.');
            }
            $ret->_fromString($val);
        }

        return $ret;
    }

    /**
     * BigInteger constructor.
     * Prevent directly instantiating object, use BigInteger::create instead.
     */
    protected function __construct()
    {

    }

    /**
     * Subclasses must provide clone functionality.
     * @return BigInteger
     */
    abstract public function __clone();

    /**
     * Assign the instance value from base 10 string.
     * @param string $str
     */
    abstract protected function _fromString($str);

    /**
     * Assign the instance value from an integer type.
     * @param int $integer
     */
    abstract protected function _fromInteger($integer);

    /**
     * Must provide string implementation that returns base 10 number.
     * @return string
     */
    abstract public function __toString();

    /* INFORMATIONAL FUNCTIONS */

    /**
     * Return integer, if possible. Throws an exception if the number can not be represented as a native integer.
     * @return int
     * @throws \OverflowException
     */
    abstract public function toInteger();

    /**
     * Is represented integer negative?
     * @return bool
     */
    abstract public function isNegative();

    /**
     * Compare the integer with $number, returns a negative integer if $this is less than number, returns 0 if $this is
     * equal to number and returns a positive integer if $this is greater than number.
     * @param BigInteger|string|int $number
     * @return int
     */
    abstract public function compare($number);

    /* MODIFY */

    /**
     * Add another integer $b and returns the result.
     * @param BigInteger|string|int $b
     * @return BigInteger
     */
    abstract public function add($b);

    /**
     * Subtract $b from $this and returns the result.
     * @param BigInteger|string|int $b
     * @return BigInteger
     */
    abstract public function subtract($b);

    /**
     * Multiply value.
     * @param BigInteger|string|int $b
     * @return BigInteger
     */
    abstract public function multiply($b);

    /**
     * The value $this modulus $b.
     * @param BigInteger|string|int $b
     * @return BigInteger
     */
    abstract public function modulus($b);

    /**
     * Raise $this to the power of $b and returns the result.
     * @param BigInteger|string|int $b
     * @return BigInteger
     */
    abstract public function toPower($b);

    /**
     * Shift the value to the right by a set number of bits and returns the result.
     * @param int $bits
     * @return BigInteger
     */
    abstract public function shiftRight($bits = 8);

    /**
     * Shift the value to the left by a set number of bits and returns the result.
     * @param int $bits
     * @return BigInteger
     */
    abstract public function shiftLeft($bits = 8);

    /**
     * Returns the absolute value.
     * @return BigInteger
     */
    abstract public function absoluteValue();
}