BigInteger::compareTo()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 2
c 0
b 0
f 0
dl 0
loc 4
rs 10
cc 1
nc 1
nop 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Sysbot\Bin\Polyfill;
6
7
use ArithmeticError;
8
use Exception;
9
use Sysbot\Bin\Deserializer;
10
use Sysbot\Bin\Serializer;
11
12
/**
13
 * Polyfill class for 64-bit systems.
14
 *
15
 * Class BigInteger
16
 * @package Sysbot\Bin\Common
17
 */
18
class BigInteger
19
{
20
21
    /**
22
     * @throws Exception
23
     */
24
    protected function __construct(protected string $value)
25
    {
26
        if (IS_32_BIT) {
27
            throw new Exception('This class cannot be used on 32-bit systems');
28
        }
29
    }
30
31
    /**
32
     * @param BigInteger|int|string $value
33
     * @return static
34
     * @throws Exception
35
     */
36
    public static function of(BigInteger|int|string $value): self
37
    {
38
        if ($value instanceof BigInteger) {
39
            return $value;
40
        }
41
        return new self((string)$value);
42
    }
43
44
    /**
45
     * @param string $value
46
     * @return static
47
     * @throws ArithmeticError
48
     * @throws Exception
49
     */
50
    public static function fromBytes(string $value): self
51
    {
52
        $data = Deserializer::unpack('q', IS_BIG_ENDIAN ? $value : strrev($value));
53
        if (null === $data) {
54
            throw new ArithmeticError('Cannot de-serialize from bytes');
55
        }
56
        return self::of($data);
57
    }
58
59
    /**
60
     * @return string
61
     */
62
    public function toBytes(): string
63
    {
64
        $value = (int)$this->value;
65
        $bytes = Serializer::pack('q', $value) ?? '';
66
        if (!IS_BIG_ENDIAN) {
67
            $bytes = strrev($bytes);
68
        }
69
        return $bytes;
70
    }
71
72
    /**
73
     * @return int
74
     */
75
    public function toInt(): int
76
    {
77
        return (int)$this->value;
78
    }
79
80
    /**
81
     * @param int|string|BigInteger $number
82
     * @return int
83
     * @throws Exception
84
     */
85
    public function compareTo(int|string|BigInteger $number): int
86
    {
87
        $number = BigInteger::of($number);
88
        return (int)$this->value <=> $number->toInt();
89
    }
90
91
    /**
92
     * @param int|string|BigInteger $number
93
     * @return $this
94
     * @throws Exception
95
     */
96
    public function plus(int|string|BigInteger $number): BigInteger
97
    {
98
        $number = BigInteger::of($number);
99
        $this->value = (string)($this->toInt() + $number->toInt());
100
        return $this;
101
    }
102
103
    /**
104
     * @param int|string|BigInteger $number
105
     * @return $this
106
     * @throws Exception
107
     */
108
    public function minus(int|string|BigInteger $number): BigInteger
109
    {
110
        if ($number instanceof BigInteger) {
111
            $number = $number->toInt();
112
        }
113
        $number = (int)$number;
114
        return $this->plus(-$number);
115
    }
116
117
    /**
118
     * @param int|string|BigInteger $number
119
     * @return $this
120
     * @throws Exception
121
     */
122
    public function multipliedBy(int|string|BigInteger $number): BigInteger
123
    {
124
        $number = BigInteger::of($number);
125
        $this->value = (string)($this->toInt() * $number->toInt());
126
        return $this;
127
    }
128
129
    /**
130
     * @param int $distance
131
     * @return $this
132
     * @throws Exception
133
     */
134
    public function shiftedLeft(int $distance): BigInteger
135
    {
136
        if ($distance === 0) {
137
            return $this;
138
        }
139
        if ($distance < 0) {
140
            return $this->shiftedRight(-$distance);
141
        }
142
        return BigInteger::of($this->toInt() << $distance);
143
    }
144
145
    /**
146
     * @param int $distance
147
     * @return BigInteger
148
     * @throws Exception
149
     */
150
    public function shiftedRight(int $distance): BigInteger
151
    {
152
        if ($distance === 0) {
153
            return $this;
154
        }
155
        if ($distance < 0) {
156
            return $this->shiftedLeft(-$distance);
157
        }
158
        return BigInteger::of($this->toInt() >> $distance);
159
    }
160
161
    /**
162
     * @return string
163
     */
164
    public function __toString()
165
    {
166
        return $this->value;
167
    }
168
169
}