Completed
Push — master ( 84b750...43e2b4 )
by Alex
21s queued 11s
created

BitMask::isFlag()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 1
c 0
b 0
f 0
nc 2
nop 1
dl 0
loc 3
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Cruxinator\BitMask;
6
7
use BadMethodCallException;
8
use MyCLabs\Enum\Enum;
9
use UnexpectedValueException;
10
11
abstract class BitMask extends Enum
12
{
13
    // Because 0 is the identity element when ORing a bitmask, we have to special-case it when ANDing bitmasks
14
    // (akin to ordinary division by 0, the addition identity element on integers/rationals/reals)
15
16
    protected function isFlag(int $flag): bool
17
    {
18
        return 0 === $flag ? 0 === $this->value : (($this->value & $flag) == $flag);
19
    }
20
21
    protected function isComponentOfFlag(int $flag): bool
22
    {
23
        return 0 === $flag ? 0 === $this->value : (($this->value & $flag) == $this->value);
24
    }
25
26
    protected function setFlag(int $flag, bool $value)
27
    {
28
        if ($value) {
29
            $this->value = 0 === $flag ? 0 : $this->value | $flag;
30
        } else {
31
            $this->value = 0 === $flag  ? $this->value : $this->value & ~$flag;
32
        }
33
        return $this;
34
    }
35
36
    /**
37
     * @param $name
38
     * @param $arguments
39
     * @throws \ReflectionException
40
     * @return bool|self
41
     */
42
    public function __call($name, $arguments)
43
    {
44
        $array     = static::toArray();
45
        $regexBase = '/(isComponentOf|is|set)(%s)/m';
46
        $regexFull = sprintf($regexBase, implode('$|', array_keys($array)));
47
        preg_match($regexFull, $name, $match);
48
        if (count($match)>0 && $match[0] === $name) {
49
            return $this->{$match[1] . 'Flag'}($array[$match[2]], $arguments[0] ?? true);
50
        }
51
        throw new BadMethodCallException(sprintf('Enum %s not found on %s', $name, get_class($this)));
52
    }
53
54
    /**
55
     * @param $value
56
     * @throws \ReflectionException
57
     * @return bool
58
     */
59
    public static function isValid($value): bool
60
    {
61
        $min = min(static::toArray());
62
        $max = max(static::toArray()) * 2 - 1;
63
        return $value >= $min && $value <= $max;
64
    }
65
66
    /**
67
     * @throws \ReflectionException
68
     * @return array
69
     */
70
    public static function toArray(): array
71
    {
72
        $firstTime = !isset(static::$cache[static::class]);
73
        $array     = array_filter(parent::toArray(), function ($value): bool {
74
            return is_scalar($value);
75
        });
76
        $firstTime && array_walk($array, function ($item): void {
77
            if (!is_integer($item)) {
78
                throw new UnexpectedValueException(
79
                    sprintf('All defined Const on Enum %s should be integers', static::class)
80
                );
81
            }
82
        });
83
        return $array;
84
    }
85
86
    /**
87
     * @throws \ReflectionException
88
     * @return array|mixed
89
     */
90
    public function getKey()
91
    {
92
        $value = $this->value;
93
        $f     = array_filter(static::toArray(), function () use (&$value) {
94
            $isSet = $value & 1;
95
            $value = $value >> 1;
96
            return $isSet;
97
        });
98
99
        return array_keys($f);
100
    }
101
102
    /**
103
     * @throws \ReflectionException
104
     * @return string
105
     */
106
    public function __toString(): string
107
    {
108
        $name  = $this->getName();
109
        $array = static::toArray();
110
        $ret   = '';
111
        foreach ($array as $key => $value) {
112
            $ret .= "'" . $key . "' => " . ($this->{'is' . $key}() ? 'TRUE' : 'FALSE') . PHP_EOL;
113
        }
114
        return $name . '[' . PHP_EOL .
115
            $ret .
116
            ']' . PHP_EOL;
117
    }
118
119
    public function getName(): string
120
    {
121
        $path = explode('\\', __CLASS__);
122
        return array_pop($path);
123
    }
124
}
125