PluginProbe ʕ •ᴥ•ʔ
Independent Analytics – WordPress Analytics Plugin / 2.15.0
Independent Analytics – WordPress Analytics Plugin v2.15.0
2.15.0 2.14.10 trunk 1.1 1.10 1.10.1 1.11 1.12 1.13 1.14 1.15 1.16 1.17 1.17.1 1.17.2 1.17.3 1.17.4 1.18 1.18.1 1.19.0 1.19.1 1.2 1.20.0 1.21.0 1.22.0 1.22.1 1.23.0 1.23.1 1.24.0 1.24.1 1.25.0 1.25.1 1.26.0 1.27.0 1.28.0 1.28.1 1.28.2 1.28.3 1.29.0 1.3 1.30.0 1.30.1 1.4 1.5 1.6 1.7 1.8 1.9 2.0.0 2.0.1 2.1.4 2.1.5 2.1.6 2.10.0 2.10.1 2.10.2 2.10.3 2.10.4 2.11.0 2.11.1 2.11.10 2.11.2 2.11.3 2.11.4 2.11.5 2.11.6 2.11.7 2.11.8 2.11.9 2.12.0 2.12.1 2.12.2 2.13.1 2.13.2 2.13.5 2.13.6 2.14.0 2.14.1 2.14.2 2.14.4 2.14.6 2.14.7 2.14.8 2.14.9 2.2.0 2.2.1 2.3.1 2.3.2 2.4.2 2.4.3 2.5.0 2.5.1 2.6.0 2.6.1 2.6.2 2.6.3 2.6.4 2.7.0 2.7.1 2.7.2 2.7.3 2.8.2 2.8.3 2.8.4 2.8.5 2.8.6 2.8.7 2.8.8 2.8.9 2.9.2 2.9.3 2.9.4 2.9.5 2.9.6 2.9.7
independent-analytics / vendor / mlocati / ip-lib / src / Service / NumberInChunks.php
independent-analytics / vendor / mlocati / ip-lib / src / Service Last commit date
BinaryMath.php 4 days ago NumberInChunks.php 4 days ago RangesFromBoundaryCalculator.php 4 days ago UnsignedIntegerMath.php 4 days ago
NumberInChunks.php
234 lines
1 <?php
2
3 namespace IAWPSCOPED\IPLib\Service;
4
5 use InvalidArgumentException;
6 /**
7 * @internal
8 *
9 * @readonly
10 */
11 class NumberInChunks
12 {
13 const CHUNKSIZE_BYTES = 8;
14 const CHUNKSIZE_WORDS = 16;
15 /**
16 * @var bool
17 */
18 public $negative;
19 /**
20 * @var int[]
21 */
22 public $chunks;
23 /**
24 * @var int
25 */
26 public $chunkSize;
27 /**
28 * @param bool $negative
29 * @param int[] $chunks
30 * @param int $chunkSize
31 */
32 public function __construct($negative, array $chunks, $chunkSize)
33 {
34 $this->negative = $negative;
35 $this->chunks = $chunks;
36 $this->chunkSize = $chunkSize;
37 }
38 /**
39 * @throws \InvalidArgumentException if $other has a $chunkSize that's not the same as the $chunkSize of this
40 *
41 * @return \IPLib\Service\NumberInChunks
42 */
43 public function negate()
44 {
45 return new self($this->chunks === array(0) ? \false : !$this->negative, $this->chunks, $this->chunkSize);
46 }
47 /**
48 * @throws \InvalidArgumentException if $other has a $chunkSize that's not the same as the $chunkSize of this
49 *
50 * @return \IPLib\Service\NumberInChunks
51 */
52 public function add(NumberInChunks $that)
53 {
54 if ($this->chunkSize !== $that->chunkSize) {
55 throw new InvalidArgumentException('Incompatible chunk size');
56 }
57 if ($this->negative === $that->negative) {
58 return new self($this->negative, self::addChunks($this->chunks, $that->chunks, $this->chunkSize), $this->chunkSize);
59 }
60 if ($that->negative) {
61 list($negative, $chunks) = self::substractChunks($this->chunks, $that->chunks, $this->chunkSize);
62 } else {
63 list($negative, $chunks) = self::substractChunks($that->chunks, $this->chunks, $this->chunkSize);
64 }
65 return new self($negative, $chunks, $this->chunkSize);
66 }
67 /**
68 * @param int $int
69 * @param int $chunkSize
70 *
71 * @return \IPLib\Service\NumberInChunks
72 */
73 public static function fromInteger($int, $chunkSize)
74 {
75 if ($int === 0) {
76 return new self(\false, array(0), $chunkSize);
77 }
78 $negative = $int < 0;
79 if ($negative) {
80 $positiveInt = -$int;
81 /** @var int|float $positiveInt may be float because -PHP_INT_MIN is bigger than PHP_INT_MAX */
82 if (\is_float($positiveInt)) {
83 return self::fromNumericString((string) $int, $chunkSize);
84 }
85 $int = $positiveInt;
86 }
87 $bitMask = (1 << $chunkSize) - 1;
88 $chunks = array();
89 while ($int !== 0) {
90 $chunks[] = $int & $bitMask;
91 $int >>= $chunkSize;
92 }
93 return new self($negative, \array_reverse($chunks), $chunkSize);
94 }
95 /**
96 * @param string $numericString a string normalized with BinaryMath::normalizeIntegerString()
97 * @param int $chunkSize
98 *
99 * @return \IPLib\Service\NumberInChunks
100 */
101 public static function fromNumericString($numericString, $chunkSize)
102 {
103 if ($numericString === '0') {
104 return new self(\false, array(0), $chunkSize);
105 }
106 $negative = $numericString[0] === '-';
107 if ($negative) {
108 $numericString = \substr($numericString, 1);
109 }
110 $chunks = array();
111 while ($numericString !== '0') {
112 $chunks[] = self::modulo($numericString, $chunkSize);
113 $numericString = self::divide($numericString, $chunkSize);
114 }
115 return new self($negative, \array_reverse($chunks), $chunkSize);
116 }
117 /**
118 * @param string $numericString
119 * @param int $chunkSize
120 *
121 * @return int
122 */
123 private static function modulo($numericString, $chunkSize)
124 {
125 $divisor = 1 << $chunkSize;
126 $carry = 0;
127 $len = \strlen($numericString);
128 for ($i = 0; $i < $len; $i++) {
129 $digit = (int) $numericString[$i];
130 $carry = ($carry * 10 + $digit) % $divisor;
131 }
132 return $carry;
133 }
134 /**
135 * @param string $numericString
136 * @param int $chunkSize
137 *
138 * @return string
139 */
140 private static function divide($numericString, $chunkSize)
141 {
142 $divisor = 1 << $chunkSize;
143 $quotient = '';
144 $carry = 0;
145 $len = \strlen($numericString);
146 for ($i = 0; $i < $len; $i++) {
147 $digit = (int) $numericString[$i];
148 $value = $carry * 10 + $digit;
149 $quotient .= (string) ($value >> $chunkSize);
150 $carry = $value % $divisor;
151 }
152 return \ltrim($quotient, '0') ?: '0';
153 }
154 /**
155 * @param int[] $addend1
156 * @param int[] $addend2
157 * @param int $chunkSize
158 *
159 * @return int[]
160 */
161 private static function addChunks(array $addend1, array $addend2, $chunkSize)
162 {
163 $divisor = 1 << $chunkSize;
164 $result = array();
165 $carry = 0;
166 while ($addend1 !== array() || $addend2 !== array()) {
167 $sum = $carry + (\array_pop($addend1) ?: 0) + (\array_pop($addend2) ?: 0);
168 $result[] = $sum % $divisor;
169 $carry = $sum >> $chunkSize;
170 }
171 if ($carry !== 0) {
172 $result[] = $carry;
173 }
174 return \array_reverse($result);
175 }
176 /**
177 * @param int[] $minuend
178 * @param int[] $subtrahend
179 * @param int $chunkSize
180 *
181 * @return array{bool, int[]}
182 */
183 private static function substractChunks(array $minuend, array $subtrahend, $chunkSize)
184 {
185 $minuendCount = \count($minuend);
186 $subtrahendCount = \count($subtrahend);
187 if ($minuendCount > $subtrahendCount) {
188 $count = $minuendCount;
189 $negative = \false;
190 } elseif ($minuendCount < $subtrahendCount) {
191 $count = $subtrahendCount;
192 $negative = \true;
193 } else {
194 $count = $minuendCount;
195 $negative = \false;
196 for ($i = 0; $i < $count; $i++) {
197 $delta = $minuend[$i] - $subtrahend[$i];
198 if ($delta === 0) {
199 continue;
200 }
201 if ($delta < 0) {
202 $negative = \true;
203 }
204 break;
205 }
206 }
207 if ($negative) {
208 list($minuend, $subtrahend) = array($subtrahend, $minuend);
209 }
210 $subtrahend = \array_pad($subtrahend, -$count, 0);
211 $borrowValue = 1 << $chunkSize;
212 $result = array();
213 $borrow = 0;
214 for ($i = $count - 1; $i >= 0; $i--) {
215 $value = $minuend[$i] - $subtrahend[$i] - $borrow;
216 if ($value < 0) {
217 $value += $borrowValue;
218 $borrow = 1;
219 } else {
220 $borrow = 0;
221 }
222 $result[] = $value;
223 }
224 while (isset($result[1])) {
225 $value = \array_pop($result);
226 if ($value !== 0) {
227 $result[] = $value;
228 break;
229 }
230 }
231 return array($negative, \array_reverse($result));
232 }
233 }
234