Passed
Push — immutable-set ( ad8f31...209f02 )
by Marc
02:00
created

EnumSet::setIntersect()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 5
nc 2
nop 1
dl 0
loc 10
ccs 6
cts 6
cp 1
crap 2
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace MabeEnum;
6
7
use Countable;
8
use InvalidArgumentException;
9
use Iterator;
10
use IteratorAggregate;
11
12
/**
13
 * A set of enumerators of the given enumeration (EnumSet<T>)
14
 * based on an integer or binary bitset depending of given enumeration size.
15
 *
16
 * @copyright 2019 Marc Bennewitz
17
 * @license http://github.com/marc-mabe/php-enum/blob/master/LICENSE.txt New BSD License
18
 * @link http://github.com/marc-mabe/php-enum for the canonical source repository
19
 */
3 ignored issues
show
Coding Style introduced by
Missing @category tag in class comment
Loading history...
Coding Style introduced by
Missing @package tag in class comment
Loading history...
Coding Style introduced by
Missing @author tag in class comment
Loading history...
20
class EnumSet implements IteratorAggregate, Countable
21
{
22
    /**
23
     * The classname of the Enumeration
24
     * @var string
25
     */
26
    private $enumeration;
1 ignored issue
show
Coding Style introduced by
Expected 1 blank line before member var; 0 found
Loading history...
Coding Style introduced by
Private member variable "enumeration" must contain a leading underscore
Loading history...
27
28
    /**
29
     * Number of enumerators defined in the enumeration
30
     * @var int
31
     */
32
    private $enumerationCount;
1 ignored issue
show
Coding Style introduced by
Private member variable "enumerationCount" must contain a leading underscore
Loading history...
33
34
    /**
35
     * Integer or binary (little endian) bitset
36
     * @var int|string
37
     */
38
    private $bitset = 0;
1 ignored issue
show
Coding Style introduced by
Private member variable "bitset" must contain a leading underscore
Loading history...
39
40
    /**#@+
41
     * Defines private method names to be called depended of how the bitset type was set too.
42
     * ... Integer or binary bitset.
43
     * ... *Int or *Bin method
44
     * 
45
     * @var string
46
     */
47
    private $fnDoGetIterator       = 'doGetIteratorInt';
1 ignored issue
show
Coding Style introduced by
Private member variable "fnDoGetIterator" must contain a leading underscore
Loading history...
48
    private $fnDoCount             = 'doCountInt';
1 ignored issue
show
Coding Style introduced by
Private member variable "fnDoCount" must contain a leading underscore
Loading history...
Coding Style introduced by
Expected 1 blank line before member var; 0 found
Loading history...
49
    private $fnDoGetOrdinals       = 'doGetOrdinalsInt';
1 ignored issue
show
Coding Style introduced by
Expected 1 blank line before member var; 0 found
Loading history...
Coding Style introduced by
Private member variable "fnDoGetOrdinals" must contain a leading underscore
Loading history...
50
    private $fnDoGetBit            = 'doGetBitInt';
1 ignored issue
show
Coding Style introduced by
Expected 1 blank line before member var; 0 found
Loading history...
Coding Style introduced by
Private member variable "fnDoGetBit" must contain a leading underscore
Loading history...
51
    private $fnDoSetBit            = 'doSetBitInt';
1 ignored issue
show
Coding Style introduced by
Expected 1 blank line before member var; 0 found
Loading history...
Coding Style introduced by
Private member variable "fnDoSetBit" must contain a leading underscore
Loading history...
52
    private $fnDoUnsetBit          = 'doUnsetBitInt';
1 ignored issue
show
Coding Style introduced by
Expected 1 blank line before member var; 0 found
Loading history...
Coding Style introduced by
Private member variable "fnDoUnsetBit" must contain a leading underscore
Loading history...
53
    private $fnDoGetBinaryBitsetLe = 'doGetBinaryBitsetLeInt';
1 ignored issue
show
Coding Style introduced by
Expected 1 blank line before member var; 0 found
Loading history...
Coding Style introduced by
Private member variable "fnDoGetBinaryBitsetLe" must contain a leading underscore
Loading history...
54
    private $fnDoSetBinaryBitsetLe = 'doSetBinaryBitsetLeInt';
1 ignored issue
show
Coding Style introduced by
Expected 1 blank line before member var; 0 found
Loading history...
Coding Style introduced by
Private member variable "fnDoSetBinaryBitsetLe" must contain a leading underscore
Loading history...
55
    /**#@-*/
56
57
    /**
58
     * Constructor
59
     *
60
     * @param string $enumeration The classname of the enumeration
1 ignored issue
show
introduced by
Parameter comment must end with a full stop
Loading history...
Coding Style introduced by
Expected 8 spaces after parameter type; 1 found
Loading history...
61
     * @param iterable|null $enumerators iterable list of enumerators initializing the set
1 ignored issue
show
introduced by
Parameter comment must start with a capital letter
Loading history...
introduced by
Parameter comment must end with a full stop
Loading history...
62
     * @throws InvalidArgumentException
0 ignored issues
show
introduced by
Comment missing for @throws tag in function comment
Loading history...
63
     */
64 91
    public function __construct(string $enumeration, iterable $enumerators = null)
2 ignored issues
show
Coding Style introduced by
Incorrect spacing between argument "$enumerators" and equals sign; expected 0 but found 1
Loading history...
Coding Style introduced by
Incorrect spacing between default value and equals sign for argument "$enumerators"; expected 0 but found 1
Loading history...
65
    {
66 91
        if (!\is_subclass_of($enumeration, Enum::class)) {
67 1
            throw new InvalidArgumentException(\sprintf(
68 1
                '%s can handle subclasses of %s only',
69 1
                __METHOD__,
70 1
                Enum::class
71
            ));
72
        }
73
74 90
        $this->enumeration      = $enumeration;
75 90
        $this->enumerationCount = \count($enumeration::getConstants());
76
77
        // By default the bitset is initialized as integer bitset
78
        // in case the enumeraton has more enumerators then integer bits
79
        // we will switch this into a binary bitset
80 90
        if ($this->enumerationCount > \PHP_INT_SIZE * 8) {
81
            // init binary bitset with zeros
82 23
            $this->bitset = \str_repeat("\0", (int)\ceil($this->enumerationCount / 8));
83
84
            // switch internal binary bitset functions
85 23
            $this->fnDoGetIterator       = 'doGetIteratorBin';
86 23
            $this->fnDoCount             = 'doCountBin';
87 23
            $this->fnDoGetOrdinals       = 'doGetOrdinalsBin';
88 23
            $this->fnDoGetBit            = 'doGetBitBin';
89 23
            $this->fnDoSetBit            = 'doSetBitBin';
90 23
            $this->fnDoUnsetBit          = 'doUnsetBitBin';
91 23
            $this->fnDoGetBinaryBitsetLe = 'doGetBinaryBitsetLeBin';
92 23
            $this->fnDoSetBinaryBitsetLe = 'doSetBinaryBitsetLeBin';
93
        }
94
95 90
        if ($enumerators !== null) {
96 2
            foreach ($enumerators as $enumerator) {
97 2
                $this->{$this->fnDoSetBit}($enumeration::get($enumerator)->getOrdinal());
98
            }
99
        }
100 90
    }
101
102
    /**
103
     * Get the classname of the enumeration
104
     * @return string
105
     */
106 2
    public function getEnumeration(): string
107
    {
108 2
        return $this->enumeration;
109
    }
110
111
    /**
112
     * Attach an enumerator object or value
113
     * @param Enum|null|bool|int|float|string|array $enumerator Enumerator object or value
2 ignored issues
show
Coding Style introduced by
Expected "Enum|null|boolean|integer|float|string|array" but found "Enum|null|bool|int|float|string|array" for parameter type
Loading history...
introduced by
Parameter comment must end with a full stop
Loading history...
114
     * @return void
115
     * @throws InvalidArgumentException On an invalid given enumerator
0 ignored issues
show
introduced by
@throws tag comment must end with a full stop
Loading history...
116
     */
117 11
    public function attachEnumerator($enumerator): void
118
    {
119 11
        $this->{$this->fnDoSetBit}(($this->enumeration)::get($enumerator)->getOrdinal());
120 11
    }
121
122
    /**
123
     * Creates a new set with the given enumerator object or value attached
124
     * @param Enum|null|bool|int|float|string|array $enumerator Enumerator object or value
2 ignored issues
show
Coding Style introduced by
Expected "Enum|null|boolean|integer|float|string|array" but found "Enum|null|bool|int|float|string|array" for parameter type
Loading history...
introduced by
Parameter comment must end with a full stop
Loading history...
125
     * @return static
126
     * @throws InvalidArgumentException On an invalid given enumerator
0 ignored issues
show
introduced by
@throws tag comment must end with a full stop
Loading history...
127
     */
128 41
    public function withEnumerator($enumerator): self
129
    {
130 41
        $clone = clone $this;
131 41
        $clone->{$this->fnDoSetBit}(($this->enumeration)::get($enumerator)->getOrdinal());
132 41
        return $clone;
133
    }
134
135
    /**
136
     * Attach all enumerator objects or values of the given iterable
137
     * @param iterable $enumerators Iterable list of enumerator objects or values
1 ignored issue
show
introduced by
Parameter comment must end with a full stop
Loading history...
138
     * @return void
139
     * @throws InvalidArgumentException On an invalid given enumerator
0 ignored issues
show
introduced by
@throws tag comment must end with a full stop
Loading history...
140
     */
141 5
    public function attachEnumerators($enumerators): void
0 ignored issues
show
introduced by
Type hint "iterable" missing for $enumerators
Loading history...
142
    {
143 5
        foreach ($enumerators as $enumerator) {
144 5
            $this->{$this->fnDoSetBit}(($this->enumeration)::get($enumerator)->getOrdinal());
145
        }
146 5
    }
147
148
    /**
149
     * Creates a new set with the given enumeration objects or values attached
150
     * @param iterable $enumerators Iterable list of enumerator objects or values
1 ignored issue
show
introduced by
Parameter comment must end with a full stop
Loading history...
151
     * @return static
152
     * @throws InvalidArgumentException On an invalid given enumerator
0 ignored issues
show
introduced by
@throws tag comment must end with a full stop
Loading history...
153
     */
154 5
    public function withEnumerators(iterable $enumerators): self
155
    {
156 5
        $clone = clone $this;
157 5
        foreach ($enumerators as $enumerator) {
158 5
            $clone->{$this->fnDoSetBit}(($this->enumeration)::get($enumerator)->getOrdinal());
159
        }
160 5
        return $clone;
161
    }
162
163
    /**
164
     * Detach the given enumerator object or value
165
     * @param Enum|null|bool|int|float|string|array $enumerator Enumerator object or value
2 ignored issues
show
Coding Style introduced by
Expected "Enum|null|boolean|integer|float|string|array" but found "Enum|null|bool|int|float|string|array" for parameter type
Loading history...
introduced by
Parameter comment must end with a full stop
Loading history...
166
     * @return void
167
     * @throws InvalidArgumentException On an invalid given enumerator
0 ignored issues
show
introduced by
@throws tag comment must end with a full stop
Loading history...
168
     */
169 7
    public function detachEnumerator($enumerator): void
170
    {
171 7
        $this->{$this->fnDoUnsetBit}(($this->enumeration)::get($enumerator)->getOrdinal());
172 7
    }
173
174
    /**
175
     * Create a new set with the given enumerator object or value detached
176
     * @param Enum|null|bool|int|float|string|array $enumerator Enumerator object or value
2 ignored issues
show
Coding Style introduced by
Expected "Enum|null|boolean|integer|float|string|array" but found "Enum|null|bool|int|float|string|array" for parameter type
Loading history...
introduced by
Parameter comment must end with a full stop
Loading history...
177
     * @return static
178
     * @throws InvalidArgumentException On an invalid given enumerator
0 ignored issues
show
introduced by
@throws tag comment must end with a full stop
Loading history...
179
     */
180 9
    public function withoutEnumerator($enumerator): self
181
    {
182 9
        $clone = clone $this;
183 9
        $clone->{$this->fnDoUnsetBit}(($this->enumeration)::get($enumerator)->getOrdinal());
184 9
        return $clone;
185
    }
186
187
    /**
188
     * Detach all enumerator objects or values of the given iterable
189
     * @param iterable $enumerators Iterable list of enumerator objects or values
1 ignored issue
show
introduced by
Parameter comment must end with a full stop
Loading history...
190
     * @return void
191
     * @throws InvalidArgumentException On an invalid given enumerator
0 ignored issues
show
introduced by
@throws tag comment must end with a full stop
Loading history...
192
     */
193 5
    public function detachEnumerators(iterable $enumerators): void
194
    {
195 5
        foreach ($enumerators as $enumerator) {
196 5
            $this->{$this->fnDoUnsetBit}(($this->enumeration)::get($enumerator)->getOrdinal());
197
        }
198 5
    }
199
200
    /**
201
     * Creates a new set with the given enumeration objects or values detached
202
     * @param iterable $enumerators Iterable list of enumerator objects or values
1 ignored issue
show
introduced by
Parameter comment must end with a full stop
Loading history...
203
     * @return static
204
     * @throws InvalidArgumentException On an invalid given enumerator
0 ignored issues
show
introduced by
@throws tag comment must end with a full stop
Loading history...
205
     */
206 5
    public function withoutEnumerators(iterable $enumerators): self
207
    {
208 5
        $clone = clone $this;
209 5
        foreach ($enumerators as $enumerator) {
210 5
            $clone->{$this->fnDoUnsetBit}(($this->enumeration)::get($enumerator)->getOrdinal());
211
        }
212 5
        return $clone;
213
    }
214
215
    /**
216
     * Test if the given enumerator exists
217
     * @param Enum|null|bool|int|float|string|array $enumerator
1 ignored issue
show
Documentation introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Expected "Enum|null|boolean|integer|float|string|array" but found "Enum|null|bool|int|float|string|array" for parameter type
Loading history...
218
     * @return bool
1 ignored issue
show
Coding Style introduced by
Expected "boolean" but found "bool" for function return type
Loading history...
219
     */
220 21
    public function contains($enumerator): bool
221
    {
222 21
        return $this->{$this->fnDoGetBit}(($this->enumeration)::get($enumerator)->getOrdinal());
223
    }
224
225
    /* IteratorAggregate */
226
227
    /**
228
     * Get a new iterator
229
     * @return Iterator
230
     * @uses doGetIteratorInt()
231
     * @uses doGetIteratorBin()
232
     */
233 13
    public function getIterator(): Iterator
234
    {
235 13
        return $this->{$this->fnDoGetIterator}();
236
    }
237
238
    /**
239
     * Get a new Iterator.
240
     *
241
     * This is the binary bitset implementation.
242
     *
243
     * @return Iterator
244
     * @see getIterator()
245
     * @see goGetIteratorInt()
246
     */
247 4
    private function doGetIteratorBin()
248
    {
249 4
        $bitset   = $this->bitset;
250 4
        $byteLen  = \strlen($bitset);
251 4
        for ($bytePos = 0; $bytePos < $byteLen; ++$bytePos) {
252 4
            if ($bitset[$bytePos] === "\0") {
253
                // fast skip null byte
254 4
                continue;
255
            }
256
257 4
            $ord = \ord($bitset[$bytePos]);
258 4
            for ($bitPos = 0; $bitPos < 8; ++$bitPos) {
259 4
                if ($ord & (1 << $bitPos)) {
260 4
                    $ordinal = $bytePos * 8 + $bitPos;
261 4
                    yield $ordinal => ($this->enumeration)::byOrdinal($ordinal);
262
                }
263
            }
264
        }
265 4
    }
266
267
    /**
268
     * Get a new Iterator.
269
     *
270
     * This is the integer bitset implementation.
271
     *
272
     * @return Iterator
273
     * @see getIterator()
274
     * @see doGetIteratorBin()
275
     */
276 9
    private function doGetIteratorInt()
277
    {
278 9
        $count  = $this->enumerationCount;
279 9
        $bitset = $this->bitset;
280 9
        for ($ordinal = 0; $ordinal < $count; ++$ordinal) {
281 9
            if ($bitset & (1 << $ordinal)) {
282 7
                yield $ordinal => ($this->enumeration)::byOrdinal($ordinal);
283
            }
284
        }
285 7
    }
286
287
    /* Countable */
288
289
    /**
290
     * Count the number of elements
291
     *
292
     * @return int
1 ignored issue
show
Coding Style introduced by
Expected "integer" but found "int" for function return type
Loading history...
293
     * @uses doCountBin()
294
     * @uses doCountInt()
295
     */
296 32
    public function count(): int
297
    {
298 32
        return $this->{$this->fnDoCount}();
299
    }
300
301
    /**
302
     * Count the number of elements.
303
     *
304
     * This is the binary bitset implementation.
305
     *
306
     * @return int
1 ignored issue
show
Coding Style introduced by
Expected "integer" but found "int" for function return type
Loading history...
307
     * @see count()
308
     * @see doCountInt()
309
     */
310 15
    private function doCountBin()
311
    {
312 15
        $count   = 0;
313 15
        $bitset  = $this->bitset;
314 15
        $byteLen = \strlen($bitset);
315 15
        for ($bytePos = 0; $bytePos < $byteLen; ++$bytePos) {
316 15
            if ($bitset[$bytePos] === "\0") {
317
                // fast skip null byte
318 15
                continue;
319
            }
320
321 15
            $ord = \ord($bitset[$bytePos]);
322 15
            if ($ord & 0b00000001) ++$count;
1 ignored issue
show
Coding Style Best Practice introduced by
It is generally a best practice to always use braces with control structures.

Adding braces to control structures avoids accidental mistakes as your code changes:

// Without braces (not recommended)
if (true)
    doSomething();

// Recommended
if (true) {
    doSomething();
}
Loading history...
323 15
            if ($ord & 0b00000010) ++$count;
1 ignored issue
show
Coding Style Best Practice introduced by
It is generally a best practice to always use braces with control structures.

Adding braces to control structures avoids accidental mistakes as your code changes:

// Without braces (not recommended)
if (true)
    doSomething();

// Recommended
if (true) {
    doSomething();
}
Loading history...
324 15
            if ($ord & 0b00000100) ++$count;
1 ignored issue
show
Coding Style Best Practice introduced by
It is generally a best practice to always use braces with control structures.

Adding braces to control structures avoids accidental mistakes as your code changes:

// Without braces (not recommended)
if (true)
    doSomething();

// Recommended
if (true) {
    doSomething();
}
Loading history...
325 15
            if ($ord & 0b00001000) ++$count;
1 ignored issue
show
Coding Style Best Practice introduced by
It is generally a best practice to always use braces with control structures.

Adding braces to control structures avoids accidental mistakes as your code changes:

// Without braces (not recommended)
if (true)
    doSomething();

// Recommended
if (true) {
    doSomething();
}
Loading history...
326 15
            if ($ord & 0b00010000) ++$count;
1 ignored issue
show
Coding Style Best Practice introduced by
It is generally a best practice to always use braces with control structures.

Adding braces to control structures avoids accidental mistakes as your code changes:

// Without braces (not recommended)
if (true)
    doSomething();

// Recommended
if (true) {
    doSomething();
}
Loading history...
327 15
            if ($ord & 0b00100000) ++$count;
1 ignored issue
show
Coding Style Best Practice introduced by
It is generally a best practice to always use braces with control structures.

Adding braces to control structures avoids accidental mistakes as your code changes:

// Without braces (not recommended)
if (true)
    doSomething();

// Recommended
if (true) {
    doSomething();
}
Loading history...
328 15
            if ($ord & 0b01000000) ++$count;
1 ignored issue
show
Coding Style Best Practice introduced by
It is generally a best practice to always use braces with control structures.

Adding braces to control structures avoids accidental mistakes as your code changes:

// Without braces (not recommended)
if (true)
    doSomething();

// Recommended
if (true) {
    doSomething();
}
Loading history...
329 15
            if ($ord & 0b10000000) ++$count;
1 ignored issue
show
Coding Style Best Practice introduced by
It is generally a best practice to always use braces with control structures.

Adding braces to control structures avoids accidental mistakes as your code changes:

// Without braces (not recommended)
if (true)
    doSomething();

// Recommended
if (true) {
    doSomething();
}
Loading history...
330
        }
331 15
        return $count;
332
    }
333
334
    /**
335
     * Count the number of elements.
336
     *
337
     * This is the integer bitset implementation.
338
     *
339
     * @return int
1 ignored issue
show
Coding Style introduced by
Expected "integer" but found "int" for function return type
Loading history...
340
     * @see count()
341
     * @see doCountBin()
342
     */
343 17
    private function doCountInt()
344
    {
345 17
        $count  = 0;
346 17
        $bitset = $this->bitset;
347
348
        // PHP does not support right shift unsigned
349 17
        if ($bitset < 0) {
350 5
            $count  = 1;
351 5
            $bitset = $bitset & \PHP_INT_MAX;
352
        }
353
354
        // iterate byte by byte and count set bits
355 17
        $phpIntBitSize = \PHP_INT_SIZE * 8;
356 17
        for ($bitPos = 0; $bitPos < $phpIntBitSize; $bitPos += 8) {
357 17
            $bitChk = 0xff << $bitPos;
358 17
            $byte = $bitset & $bitChk;
359 17
            if ($byte) {
360 16
                $byte = $byte >> $bitPos;
361 16
                if ($byte & 0b00000001) ++$count;
1 ignored issue
show
Coding Style Best Practice introduced by
It is generally a best practice to always use braces with control structures.

Adding braces to control structures avoids accidental mistakes as your code changes:

// Without braces (not recommended)
if (true)
    doSomething();

// Recommended
if (true) {
    doSomething();
}
Loading history...
362 16
                if ($byte & 0b00000010) ++$count;
1 ignored issue
show
Coding Style Best Practice introduced by
It is generally a best practice to always use braces with control structures.

Adding braces to control structures avoids accidental mistakes as your code changes:

// Without braces (not recommended)
if (true)
    doSomething();

// Recommended
if (true) {
    doSomething();
}
Loading history...
363 16
                if ($byte & 0b00000100) ++$count;
1 ignored issue
show
Coding Style Best Practice introduced by
It is generally a best practice to always use braces with control structures.

Adding braces to control structures avoids accidental mistakes as your code changes:

// Without braces (not recommended)
if (true)
    doSomething();

// Recommended
if (true) {
    doSomething();
}
Loading history...
364 16
                if ($byte & 0b00001000) ++$count;
1 ignored issue
show
Coding Style Best Practice introduced by
It is generally a best practice to always use braces with control structures.

Adding braces to control structures avoids accidental mistakes as your code changes:

// Without braces (not recommended)
if (true)
    doSomething();

// Recommended
if (true) {
    doSomething();
}
Loading history...
365 16
                if ($byte & 0b00010000) ++$count;
1 ignored issue
show
Coding Style Best Practice introduced by
It is generally a best practice to always use braces with control structures.

Adding braces to control structures avoids accidental mistakes as your code changes:

// Without braces (not recommended)
if (true)
    doSomething();

// Recommended
if (true) {
    doSomething();
}
Loading history...
366 16
                if ($byte & 0b00100000) ++$count;
1 ignored issue
show
Coding Style Best Practice introduced by
It is generally a best practice to always use braces with control structures.

Adding braces to control structures avoids accidental mistakes as your code changes:

// Without braces (not recommended)
if (true)
    doSomething();

// Recommended
if (true) {
    doSomething();
}
Loading history...
367 16
                if ($byte & 0b01000000) ++$count;
1 ignored issue
show
Coding Style Best Practice introduced by
It is generally a best practice to always use braces with control structures.

Adding braces to control structures avoids accidental mistakes as your code changes:

// Without braces (not recommended)
if (true)
    doSomething();

// Recommended
if (true) {
    doSomething();
}
Loading history...
368 16
                if ($byte & 0b10000000) ++$count;
1 ignored issue
show
Coding Style Best Practice introduced by
It is generally a best practice to always use braces with control structures.

Adding braces to control structures avoids accidental mistakes as your code changes:

// Without braces (not recommended)
if (true)
    doSomething();

// Recommended
if (true) {
    doSomething();
}
Loading history...
369
            }
370
371 17
            if ($bitset <= $bitChk) {
372 17
                break;
373
            }
374
        }
375
376 17
        return $count;
377
    }
378
379
    /**
380
     * Check if this EnumSet is the same as other
381
     * @param EnumSet $other
0 ignored issues
show
Documentation introduced by
Missing parameter comment
Loading history...
382
     * @return bool
1 ignored issue
show
Coding Style introduced by
Expected "boolean" but found "bool" for function return type
Loading history...
383
     */
384 3
    public function isEqual(EnumSet $other): bool
385
    {
386 3
        return $this->enumeration === $other->enumeration
387 3
            && $this->bitset === $other->bitset;
388
    }
389
390
    /**
391
     * Check if this EnumSet is a subset of other
392
     * @param EnumSet $other
0 ignored issues
show
Documentation introduced by
Missing parameter comment
Loading history...
393
     * @return bool
1 ignored issue
show
Coding Style introduced by
Expected "boolean" but found "bool" for function return type
Loading history...
394
     */
395 4
    public function isSubset(EnumSet $other): bool
396
    {
397 4
        return $this->enumeration === $other->enumeration
398 4
            && ($this->bitset & $other->bitset) === $this->bitset;
399
    }
400
401
    /**
402
     * Check if this EnumSet is a superset of other
403
     * @param EnumSet $other
0 ignored issues
show
Documentation introduced by
Missing parameter comment
Loading history...
404
     * @return bool
1 ignored issue
show
Coding Style introduced by
Expected "boolean" but found "bool" for function return type
Loading history...
405
     */
406 4
    public function isSuperset(EnumSet $other): bool
407
    {
408 4
        return $this->enumeration === $other->enumeration
409 4
            && ($this->bitset | $other->bitset) === $this->bitset;
410
    }
411
412
    /**
413
     * Modify this set from both this and other (this | other)
414
     *
415
     * @param EnumSet $other EnumSet of the same enumeration to produce the union
1 ignored issue
show
introduced by
Parameter comment must end with a full stop
Loading history...
416
     * @return void
417
     * @throws InvalidArgumentException If $other doesn't match the enumeration
0 ignored issues
show
introduced by
@throws tag comment must end with a full stop
Loading history...
418
     */
419 3
    public function setUnion(EnumSet $other): void
420
    {
421 3
        if ($this->enumeration !== $other->enumeration) {
422 1
            throw new InvalidArgumentException(\sprintf(
423 1
                'Other should be of the same enumeration as this %s',
424 1
                $this->enumeration
425
            ));
426
        }
427
428 2
        $this->bitset = $this->bitset | $other->bitset;
429 2
    }
430
431
    /**
432
     * Create a new set with enumerators from both this and other (this | other)
433
     *
434
     * @param EnumSet $other EnumSet of the same enumeration to produce the union
1 ignored issue
show
introduced by
Parameter comment must end with a full stop
Loading history...
435
     * @return static
436
     * @throws InvalidArgumentException If $other doesn't match the enumeration
0 ignored issues
show
introduced by
@throws tag comment must end with a full stop
Loading history...
437
     */
438 1
    public function withUnion(EnumSet $other): self
439
    {
440 1
        $clone = clone $this;
441 1
        $clone->setUnion($other);
442 1
        return $clone;
443
    }
444
445
    /**
446
     * Modify this set with enumerators common to both this and other (this & other)
447
     *
448
     * @param EnumSet $other EnumSet of the same enumeration to produce the intersect
1 ignored issue
show
introduced by
Parameter comment must end with a full stop
Loading history...
449
     * @return void
450
     * @throws InvalidArgumentException If $other doesn't match the enumeration
0 ignored issues
show
introduced by
@throws tag comment must end with a full stop
Loading history...
451
     */
452 3
    public function setIntersect(EnumSet $other): void
453
    {
454 3
        if ($this->enumeration !== $other->enumeration) {
455 1
            throw new InvalidArgumentException(\sprintf(
456 1
                'Other should be of the same enumeration as this %s',
457 1
                $this->enumeration
458
            ));
459
        }
460
461 2
        $this->bitset = $this->bitset & $other->bitset;
462 2
    }
463
464
    /**
465
     * Create a new set with enumerators common to both this and other (this & other)
466
     *
467
     * @param EnumSet $other EnumSet of the same enumeration to produce the intersect
1 ignored issue
show
introduced by
Parameter comment must end with a full stop
Loading history...
468
     * @return static
469
     * @throws InvalidArgumentException If $other doesn't match the enumeration
0 ignored issues
show
introduced by
@throws tag comment must end with a full stop
Loading history...
470
     */
471 1
    public function withIntersect(EnumSet $other): self
472
    {
473 1
        $clone = clone $this;
474 1
        $clone->setIntersect($other);
475 1
        return $clone;
476
    }
477
478
    /**
479
     * Modify this set with enumerators in this but not in other (this - other)
480
     *
481
     * @param EnumSet $other EnumSet of the same enumeration to produce the diff
1 ignored issue
show
introduced by
Parameter comment must end with a full stop
Loading history...
482
     * @return void
483
     * @throws InvalidArgumentException If $other doesn't match the enumeration
0 ignored issues
show
introduced by
@throws tag comment must end with a full stop
Loading history...
484
     */
485 3
    public function setDiff(EnumSet $other): void
486
    {
487 3
        if ($this->enumeration !== $other->enumeration) {
488 1
            throw new InvalidArgumentException(\sprintf(
489 1
                'Other should be of the same enumeration as this %s',
490 1
                $this->enumeration
491
            ));
492
        }
493
494 2
        $this->bitset = $this->bitset & ~$other->bitset;
495 2
    }
496
497
    /**
498
     * Modify this set with enumerators in this but not in other (this - other)
499
     *
500
     * @param EnumSet $other EnumSet of the same enumeration to produce the diff
1 ignored issue
show
introduced by
Parameter comment must end with a full stop
Loading history...
501
     * @return static
502
     * @throws InvalidArgumentException If $other doesn't match the enumeration
0 ignored issues
show
introduced by
@throws tag comment must end with a full stop
Loading history...
503
     */
504 1
    public function withDiff(EnumSet $other): self
505
    {
506 1
        $clone = clone $this;
507 1
        $clone->setDiff($other);
508 1
        return $clone;
509
    }
510
511
    /**
512
     * Modify this set with enumerators in either this and other but not in both (this ^ other)
513
     *
514
     * @param EnumSet $other EnumSet of the same enumeration to produce the symmetric difference
1 ignored issue
show
introduced by
Parameter comment must end with a full stop
Loading history...
515
     * @return void
516
     * @throws InvalidArgumentException If $other doesn't match the enumeration
0 ignored issues
show
introduced by
@throws tag comment must end with a full stop
Loading history...
517
     */
518 3
    public function setSymDiff(EnumSet $other): void
519
    {
520 3
        if ($this->enumeration !== $other->enumeration) {
521 1
            throw new InvalidArgumentException(\sprintf(
522 1
                'Other should be of the same enumeration as this %s',
523 1
                $this->enumeration
524
            ));
525
        }
526
527 2
        $this->bitset = $this->bitset ^ $other->bitset;
528 2
    }
529
530
    /**
531
     * Create a new set with enumerators in either this and other but not in both (this ^ other)
532
     *
533
     * @param EnumSet $other EnumSet of the same enumeration to produce the symmetric difference
1 ignored issue
show
introduced by
Parameter comment must end with a full stop
Loading history...
534
     * @return static
535
     * @throws InvalidArgumentException If $other doesn't match the enumeration
0 ignored issues
show
introduced by
@throws tag comment must end with a full stop
Loading history...
536
     */
537 1
    public function withSymDiff(EnumSet $other): self
538
    {
539 1
        $clone = clone $this;
540 1
        $clone->setSymDiff($other);
541 1
        return $clone;
542
    }
543
544
    /**
545
     * Get ordinal numbers of the defined enumerators as array
546
     * @return int[]
547
     * @uses  doGetOrdinalsBin()
548
     * @uses  doGetOrdinalsInt()
549
     */
550 13
    public function getOrdinals(): array
551
    {
552 13
        return $this->{$this->fnDoGetOrdinals}();
553
    }
554
555
    /**
556
     * Get ordinal numbers of the defined enumerators as array.
557
     *
558
     * This is the binary bitset implementation.
559
     *
560
     * @return int[]
561
     * @see getOrdinals()
562
     * @see goGetOrdinalsInt()
563
     */
564 1
    private function doGetOrdinalsBin()
565
    {
566 1
        $ordinals = [];
567 1
        $bitset   = $this->bitset;
568 1
        $byteLen  = \strlen($bitset);
569 1
        for ($bytePos = 0; $bytePos < $byteLen; ++$bytePos) {
570 1
            if ($bitset[$bytePos] === "\0") {
571
                // fast skip null byte
572 1
                continue;
573
            }
574
575 1
            $ord = \ord($bitset[$bytePos]);
576 1
            for ($bitPos = 0; $bitPos < 8; ++$bitPos) {
577 1
                if ($ord & (1 << $bitPos)) {
578 1
                    $ordinals[] = $bytePos * 8 + $bitPos;
579
                }
580
            }
581
        }
582 1
        return $ordinals;
583
    }
584
585
    /**
586
     * Get ordinal numbers of the defined enumerators as array.
587
     *
588
     * This is the integer bitset implementation.
589
     *
590
     * @return int[]
591
     * @see getOrdinals()
592
     * @see doGetOrdinalsBin()
593
     */
594 12
    private function doGetOrdinalsInt()
595
    {
596 12
        $ordinals = [];
597 12
        $count    = $this->enumerationCount;
598 12
        $bitset   = $this->bitset;
599 12
        for ($ordinal = 0; $ordinal < $count; ++$ordinal) {
600 12
            if ($bitset & (1 << $ordinal)) {
601 12
                $ordinals[] = $ordinal;
602
            }
603
        }
604 12
        return $ordinals;
605
    }
606
607
    /**
608
     * Get values of the defined enumerators as array
609
     * @return mixed[]
610
     */
611 9
    public function getValues(): array
612
    {
613 9
        $enumeration = $this->enumeration;
614 9
        $values      = [];
615 9
        foreach ($this->getOrdinals() as $ord) {
616 9
            $values[] = $enumeration::byOrdinal($ord)->getValue();
617
        }
618 9
        return $values;
619
    }
620
621
    /**
622
     * Get names of the defined enumerators as array
623
     * @return string[]
624
     */
625 1
    public function getNames(): array
626
    {
627 1
        $enumeration = $this->enumeration;
628 1
        $names       = [];
629 1
        foreach ($this->getOrdinals() as $ord) {
630 1
            $names[] = $enumeration::byOrdinal($ord)->getName();
631
        }
632 1
        return $names;
633
    }
634
635
    /**
636
     * Get the defined enumerators as array
637
     * @return Enum[]
638
     */
639 1
    public function getEnumerators(): array
640
    {
641 1
        $enumeration = $this->enumeration;
642 1
        $enumerators = [];
643 1
        foreach ($this->getOrdinals() as $ord) {
644 1
            $enumerators[] = $enumeration::byOrdinal($ord);
645
        }
646 1
        return $enumerators;
647
    }
648
649
    /**
650
     * Get binary bitset in little-endian order
651
     * 
652
     * @return string
653
     * @uses doGetBinaryBitsetLeBin()
654
     * @uses doGetBinaryBitsetLeInt()
655
     */
656 6
    public function getBinaryBitsetLe(): string
657
    {
658 6
        return $this->{$this->fnDoGetBinaryBitsetLe}();
659
    }
660
661
    /**
662
     * Get binary bitset in little-endian order.
663
     *
664
     * This is the binary bitset implementation.
665
     *
666
     * @return string
667
     * @see getBinaryBitsetLe()
668
     * @see doGetBinaryBitsetLeInt()
669
     */
670 4
    private function doGetBinaryBitsetLeBin()
671
    {
672 4
        return $this->bitset;
673
    }
674
675
    /**
676
     * Get binary bitset in little-endian order.
677
     *
678
     * This is the integer bitset implementation.
679
     *
680
     * @return string
681
     * @see getBinaryBitsetLe()
682
     * @see doGetBinaryBitsetLeBin()
683
     */
684 2
    private function doGetBinaryBitsetLeInt()
685
    {
686 2
        $bin = \pack(\PHP_INT_SIZE === 8 ? 'P' : 'V', $this->bitset);
687 2
        return \substr($bin, 0, (int)\ceil($this->enumerationCount / 8));
688
    }
689
690
    /**
691
     * Set the given binary bitset in little-endian order
692
     *
693
     * @param string $bitset
0 ignored issues
show
Documentation introduced by
Missing parameter comment
Loading history...
694
     * @return void
695
     * @throws InvalidArgumentException On out-of-range bits given as input bitset
0 ignored issues
show
introduced by
@throws tag comment must end with a full stop
Loading history...
696
     * @uses doSetBinaryBitsetLeBin()
697
     * @uses doSetBinaryBitsetLeInt()
698
     */
699 1
    public function setBinaryBitsetLe(string $bitset): void
700
    {
701 1
        $this->{$this->fnDoSetBinaryBitsetLe}($bitset);
702 1
    }
703
704
    /**
705
     * Create a new set with the given binary bitset in little-endian order
706
     *
707
     * @param string $bitset
0 ignored issues
show
Documentation introduced by
Missing parameter comment
Loading history...
708
     * @return static
709
     * @throws InvalidArgumentException On out-of-range bits given as input bitset
0 ignored issues
show
introduced by
@throws tag comment must end with a full stop
Loading history...
710
     * @uses doSetBinaryBitsetLeBin()
711
     * @uses doSetBinaryBitsetLeInt()
712
     */
713 11
    public function withBinaryBitsetLe(string $bitset): self
714
    {
715 11
        $clone = clone $this;
716 11
        $clone->{$this->fnDoSetBinaryBitsetLe}($bitset);
717 5
        return $clone;
718
    }
719
720
    /**
721
     * Set binary bitset in little-endian order
722
     *
723
     * @param string $bitset
0 ignored issues
show
Documentation introduced by
Missing parameter comment
Loading history...
724
     * @return void
725
     * @throws InvalidArgumentException On out-of-range bits given as input bitset
0 ignored issues
show
introduced by
@throws tag comment must end with a full stop
Loading history...
726
     * @see setBinaryBitsetLeBin()
727
     * @see doSetBinaryBitsetLeInt()
728
     */
729 9
    private function doSetBinaryBitsetLeBin($bitset): void
0 ignored issues
show
Coding Style introduced by
Type hint "string" missing for $bitset
Loading history...
730
    {
731 9
        $size   = \strlen($this->bitset);
732 9
        $sizeIn = \strlen($bitset);
733
734 9
        if ($sizeIn < $size) {
735
            // add "\0" if the given bitset is not long enough
736 1
            $bitset .= \str_repeat("\0", $size - $sizeIn);
737 8
        } elseif ($sizeIn > $size) {
738 2
            if (\ltrim(\substr($bitset, $size), "\0") !== '') {
739 1
                throw new InvalidArgumentException('out-of-range bits detected');
740
            }
741 1
            $bitset = \substr($bitset, 0, $size);
742
        }
743
744
        // truncate out-of-range bits of last byte
745 8
        $lastByteMaxOrd = $this->enumerationCount % 8;
746 8
        if ($lastByteMaxOrd !== 0) {
747 8
            $lastByte         = $bitset[-1];
748 8
            $lastByteExpected = \chr((1 << $lastByteMaxOrd) - 1) & $lastByte;
749 8
            if ($lastByte !== $lastByteExpected) {
750 2
                throw new InvalidArgumentException('out-of-range bits detected');
751
            }
752
753 6
            $this->bitset = \substr($bitset, 0, -1) . $lastByteExpected;
754
        }
755
756 6
        $this->bitset = $bitset;
757 6
    }
758
759
    /**
760
     * Set binary bitset in little-endian order
761
     *
762
     * @param string $bitset
0 ignored issues
show
Documentation introduced by
Missing parameter comment
Loading history...
763
     * @return void
764
     * @throws InvalidArgumentException On out-of-range bits given as input bitset
0 ignored issues
show
introduced by
@throws tag comment must end with a full stop
Loading history...
765
     * @see setBinaryBitsetLeBin()
766
     * @see doSetBinaryBitsetLeBin()
767
     */
768 5
    private function doSetBinaryBitsetLeInt($bitset): void
0 ignored issues
show
Coding Style introduced by
Type hint "string" missing for $bitset
Loading history...
769
    {
770 5
        $len = \strlen($bitset);
771 5
        $int = 0;
772 5
        for ($i = 0; $i < $len; ++$i) {
773 5
            $ord = \ord($bitset[$i]);
774
775 5
            if ($ord && $i > \PHP_INT_SIZE - 1) {
776 1
                throw new InvalidArgumentException('out-of-range bits detected');
777
            }
778
779 5
            $int |= $ord << (8 * $i);
780
        }
781
782 4
        if ($int & (~0 << $this->enumerationCount)) {
783 2
            throw new InvalidArgumentException('out-of-range bits detected');
784
        }
785
786 2
        $this->bitset = $int;
787 2
    }
788
789
    /**
790
     * Get binary bitset in big-endian order
791
     * 
792
     * @return string
793
     */
794 1
    public function getBinaryBitsetBe(): string
795
    {
796 1
        return \strrev($this->bitset);
797
    }
798
799
    /**
800
     * Set the given binary bitset in big-endian order
801
     *
802
     * @param string $bitset
0 ignored issues
show
Documentation introduced by
Missing parameter comment
Loading history...
803
     * @return void
804
     * @throws InvalidArgumentException On out-of-range bits given as input bitset
0 ignored issues
show
introduced by
@throws tag comment must end with a full stop
Loading history...
805
     */
806 1
    public function setBinaryBitsetBe(string $bitset): void
807
    {
808 1
        $this->{$this->fnDoSetBinaryBitsetLe}(\strrev($bitset));
809 1
    }
810
811
    /**
812
     * Create a new set with the given binary bitset in big-endian order
813
     *
814
     * @param string $bitset
0 ignored issues
show
Documentation introduced by
Missing parameter comment
Loading history...
815
     * @return static
816
     * @throws InvalidArgumentException On out-of-range bits given as input bitset
0 ignored issues
show
introduced by
@throws tag comment must end with a full stop
Loading history...
817
     */
818 1
    public function withBinaryBitsetBe(string $bitset): self
819
    {
820 1
        $clone = $this;
821 1
        $clone->{$this->fnDoSetBinaryBitsetLe}(\strrev($bitset));
822 1
        return $clone;
823
    }
824
825
    /**
826
     * Get a bit at the given ordinal number
827
     *
828
     * @param int $ordinal Ordinal number of bit to get
2 ignored issues
show
Coding Style introduced by
Expected "integer" but found "int" for parameter type
Loading history...
introduced by
Parameter comment must end with a full stop
Loading history...
829
     * @return bool
1 ignored issue
show
Coding Style introduced by
Expected "boolean" but found "bool" for function return type
Loading history...
830
     * @throws InvalidArgumentException If the given ordinal number is out-of-range
0 ignored issues
show
introduced by
@throws tag comment must end with a full stop
Loading history...
831
     * @uses doGetBitBin()
832
     * @uses doGetBitInt()
833
     */
834 4
    public function getBit(int $ordinal): bool
835
    {
836 4
        if ($ordinal < 0 || $ordinal > $this->enumerationCount) {
837 1
            throw new InvalidArgumentException("Ordinal number must be between 0 and {$this->enumerationCount}");
1 ignored issue
show
Coding Style Best Practice introduced by
As per coding-style, please use concatenation or sprintf for the variable $this instead of interpolation.

It is generally a best practice as it is often more readable to use concatenation instead of interpolation for variables inside strings.

// Instead of
$x = "foo $bar $baz";

// Better use either
$x = "foo " . $bar . " " . $baz;
$x = sprintf("foo %s %s", $bar, $baz);
Loading history...
Coding Style introduced by
This line exceeds maximum limit of 100 characters; contains 113 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
838
        }
839
840 3
        return $this->{$this->fnDoGetBit}($ordinal);
841
    }
842
843
    /**
844
     * Get a bit at the given ordinal number.
845
     *
846
     * This is the binary bitset implementation.
847
     *
848
     * @param int $ordinal Ordinal number of bit to get
2 ignored issues
show
Coding Style introduced by
Expected "integer" but found "int" for parameter type
Loading history...
introduced by
Parameter comment must end with a full stop
Loading history...
849
     * @return bool
1 ignored issue
show
Coding Style introduced by
Expected "boolean" but found "bool" for function return type
Loading history...
850
     * @see getBit()
851
     * @see doGetBitInt()
852
     */
853 8
    private function doGetBitBin($ordinal)
0 ignored issues
show
Coding Style introduced by
Type hint "int" missing for $ordinal
Loading history...
854
    {
855 8
        return (\ord($this->bitset[(int) ($ordinal / 8)]) & 1 << ($ordinal % 8)) !== 0;
856
    }
857
858
    /**
859
     * Get a bit at the given ordinal number.
860
     *
861
     * This is the integer bitset implementation.
862
     * 
863
     * @param int $ordinal Ordinal number of bit to get
2 ignored issues
show
Coding Style introduced by
Expected "integer" but found "int" for parameter type
Loading history...
introduced by
Parameter comment must end with a full stop
Loading history...
864
     * @return bool
1 ignored issue
show
Coding Style introduced by
Expected "boolean" but found "bool" for function return type
Loading history...
865
     * @see getBit()
866
     * @see doGetBitBin()
867
     */
868 15
    private function doGetBitInt($ordinal)
0 ignored issues
show
Coding Style introduced by
Type hint "int" missing for $ordinal
Loading history...
869
    {
870 15
        return (bool)($this->bitset & (1 << $ordinal));
871
    }
872
873
    /**
874
     * Set a bit at the given ordinal number
875
     *
876
     * @param int $ordinal Ordinal number of bit to set
2 ignored issues
show
Coding Style introduced by
Expected "integer" but found "int" for parameter type
Loading history...
Coding Style introduced by
Expected 2 spaces after parameter type; 1 found
Loading history...
introduced by
Parameter comment must end with a full stop
Loading history...
877
     * @param bool $bit    The bit to set
2 ignored issues
show
Coding Style introduced by
Expected "boolean" but found "bool" for parameter type
Loading history...
Coding Style introduced by
Expected 5 spaces after parameter name; 4 found
Loading history...
introduced by
Parameter comment must end with a full stop
Loading history...
878
     * @return void
879
     * @throws InvalidArgumentException If the given ordinal number is out-of-range
0 ignored issues
show
introduced by
@throws tag comment must end with a full stop
Loading history...
880
     * @uses doSetBitBin()
881
     * @uses doSetBitInt()
882
     * @uses doUnsetBitBin()
883
     * @uses doUnsetBitInt()
884
     */
885 3
    public function setBit(int $ordinal, bool $bit): void
886
    {
887 3
        if ($ordinal < 0 || $ordinal > $this->enumerationCount) {
888 1
            throw new InvalidArgumentException("Ordinal number must be between 0 and {$this->enumerationCount}");
1 ignored issue
show
Coding Style Best Practice introduced by
As per coding-style, please use concatenation or sprintf for the variable $this instead of interpolation.

It is generally a best practice as it is often more readable to use concatenation instead of interpolation for variables inside strings.

// Instead of
$x = "foo $bar $baz";

// Better use either
$x = "foo " . $bar . " " . $baz;
$x = sprintf("foo %s %s", $bar, $baz);
Loading history...
Coding Style introduced by
This line exceeds maximum limit of 100 characters; contains 113 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
889
        }
890
891 2
        if ($bit) {
892 2
            $this->{$this->fnDoSetBit}($ordinal);
893
        } else {
894 2
            $this->{$this->fnDoUnsetBit}($ordinal);
895
        }
896 2
    }
897
898
    /**
899
     * Create a new set with the bit at the given ordinal number set
900
     *
901
     * @param int $ordinal Ordinal number of bit to set
2 ignored issues
show
Coding Style introduced by
Expected "integer" but found "int" for parameter type
Loading history...
Coding Style introduced by
Expected 2 spaces after parameter type; 1 found
Loading history...
introduced by
Parameter comment must end with a full stop
Loading history...
902
     * @param bool $bit    The bit to set
2 ignored issues
show
Coding Style introduced by
Expected "boolean" but found "bool" for parameter type
Loading history...
Coding Style introduced by
Expected 5 spaces after parameter name; 4 found
Loading history...
introduced by
Parameter comment must end with a full stop
Loading history...
903
     * @return static
904
     * @throws InvalidArgumentException If the given ordinal number is out-of-range
0 ignored issues
show
introduced by
@throws tag comment must end with a full stop
Loading history...
905
     * @uses doSetBitBin()
906
     * @uses doSetBitInt()
907
     * @uses doUnsetBitBin()
908
     * @uses doUnsetBitInt()
909
     */
910 1
    public function withBit(int $ordinal, bool $bit): self
911
    {
912 1
        $clone = clone $this;
913 1
        $clone->setBit($ordinal, $bit);
914 1
        return $clone;
915
    }
916
917
    /**
918
     * Set a bit at the given ordinal number.
919
     *
920
     * This is the binary bitset implementation.
921
     * 
922
     * @param int $ordinal Ordinal number of bit to set
2 ignored issues
show
Coding Style introduced by
Expected "integer" but found "int" for parameter type
Loading history...
introduced by
Parameter comment must end with a full stop
Loading history...
923
     * @return void
924
     * @see setBit()
925
     * @see doSetBitInt()
926
     */
927 14
    private function doSetBitBin($ordinal): void
0 ignored issues
show
Coding Style introduced by
Type hint "int" missing for $ordinal
Loading history...
928
    {
929 14
        $byte = (int) ($ordinal / 8);
930 14
        $this->bitset[$byte] = $this->bitset[$byte] | \chr(1 << ($ordinal % 8));
931 14
    }
932
933
    /**
934
     * Set a bit at the given ordinal number.
935
     *
936
     * This is the binary bitset implementation.
937
     *
938
     * @param int $ordinal Ordinal number of bit to set
2 ignored issues
show
Coding Style introduced by
Expected "integer" but found "int" for parameter type
Loading history...
introduced by
Parameter comment must end with a full stop
Loading history...
939
     * @return void
940
     * @see setBit()
941
     * @see doSetBitBin()
942
     */
943 52
    private function doSetBitInt($ordinal): void
0 ignored issues
show
Coding Style introduced by
Type hint "int" missing for $ordinal
Loading history...
944
    {
945 52
        $this->bitset = $this->bitset | (1 << $ordinal);
946 52
    }
947
948
    /**
949
     * Unset a bit at the given ordinal number.
950
     *
951
     * This is the binary bitset implementation.
952
     *
953
     * @param int $ordinal Ordinal number of bit to unset
2 ignored issues
show
Coding Style introduced by
Expected "integer" but found "int" for parameter type
Loading history...
introduced by
Parameter comment must end with a full stop
Loading history...
954
     * @return void
955
     * @see setBit()
956
     * @see doUnsetBitInt()
957
     */
958 10
    private function doUnsetBitBin($ordinal): void
0 ignored issues
show
Coding Style introduced by
Type hint "int" missing for $ordinal
Loading history...
959
    {
960 10
        $byte = (int) ($ordinal / 8);
961 10
        $this->bitset[$byte] = $this->bitset[$byte] & \chr(~(1 << ($ordinal % 8)));
962 10
    }
963
964
    /**
965
     * Unset a bit at the given ordinal number.
966
     *
967
     * This is the integer bitset implementation.
968
     *
969
     * @param int $ordinal Ordinal number of bit to unset
2 ignored issues
show
Coding Style introduced by
Expected "integer" but found "int" for parameter type
Loading history...
introduced by
Parameter comment must end with a full stop
Loading history...
970
     * @return void
971
     * @see setBit()
972
     * @see doUnsetBitBin()
973
     */
974 18
    private function doUnsetBitInt($ordinal): void
0 ignored issues
show
Coding Style introduced by
Type hint "int" missing for $ordinal
Loading history...
975
    {
976 18
        $this->bitset = $this->bitset & ~(1 << $ordinal);
977 18
    }
978
}
979