BitArray::offsetExists()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 3
dl 0
loc 7
rs 10
c 1
b 0
f 0
cc 3
nc 3
nop 1
1
<?php
2
3
namespace Mfonte\Base62x\Compression\Huffman\Binary;
4
5
/**
6
 * 	a simple, fixed-size bit array, backed internally by a string.
7
 */
8
class BitArray implements \ArrayAccess
9
{
10
    private $data = '';
11
    private $size = 0;
12
13
    /**
14
     * 	create a new bit array of the given size.
15
     */
16
    public function __construct($size)
17
    {
18
        $this->size = $size;
19
        $this->init();
20
    }
21
22
    /**
23
     *	create a new BitArray from the bytes in the supplied string.
24
     */
25
    public static function load($data)
26
    {
27
        $array = new self(mb_strlen($data) * 8);
28
        $array->data = $data;
29
30
        return $array;
31
    }
32
33
    /**
34
     *	retrieve the internal string representation of the binary data.
35
     */
36
    public function getData()
37
    {
38
        return $this->data;
39
    }
40
41
    /**
42
     * 	whether the given offset exists: ArrayAccess.
43
     */
44
    public function offsetExists($offset): bool
45
    {
46
        if (!\is_int($offset)) {
47
            return false;
48
        }
49
50
        return $offset >= 0 && $offset < $this->size;
51
    }
52
53
    /**
54
     * 	get the value at the given offset: ArrayAccess.
55
     */
56
    #[\ReturnTypeWillChange]
57
    public function offsetGet($offset)
58
    {
59
        list($index, $bit) = $this->getPosition($offset);
60
61
        return ($this->getNumericValueAt($index) & (1 << $bit)) ? 1 : 0;
62
    }
63
64
    /**
65
     * 	set the value at the given offset: ArrayAccess.
66
     */
67
    public function offsetSet($offset, $value): void
68
    {
69
        $Xor = false;
70
        if (!$value) {
71
            if ($this->offsetGet($offset)) {
72
                //	later, we'll flip that bit using XOR
73
                $Xor = true;
74
            } else {
75
                //	it's already 0. we're done
76
                return;
77
            }
78
        }
79
        list($index, $bit) = $this->getPosition($offset);
80
        $byte = $this->getNumericValueAt($index);
81
        $byte = ($Xor)
82
            ? $byte ^ (1 << $bit)
83
            : $byte | (1 << $bit);
84
        $this->data[$index] = pack('C*', $byte);
85
    }
86
87
    /**
88
     * 	unset given offset: ArrayAccess
89
     * 	NOTE: This deviates a little from the true ArrayAccess meaning,
90
     *	b/c we have a value (0 or 1) at every bit no matter what. unsetting sets to 0.
91
     */
92
    public function offsetUnset($offset): void
93
    {
94
        $this->offsetSet($offset, 0);
95
    }
96
97
    /**
98
     * 	get the one-byte character that contains the given offset.
99
     */
100
    private function getPosition($offset)
101
    {
102
        $quotient = (int) ($offset / 8);
103
        $bit = $offset % 8;
104
105
        return [$quotient, $bit];
106
    }
107
108
    /**
109
     * 	get the current numeric value of a byte in our string.
110
     */
111
    private function getNumericValueAt($index)
112
    {
113
        $bytes = unpack('C*', $this->data[$index]);
114
115
        return $bytes[1];
116
    }
117
118
    /**
119
     * 	initialize the array with 0 for all bits.
120
     */
121
    private function init()
122
    {
123
        $this->data = str_repeat("\0", (int) (ceil($this->size / 8)));
124
    }
125
}
126