StringArray::__construct()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 12
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 1

Importance

Changes 2
Bugs 0 Features 1
Metric Value
c 2
b 0
f 1
dl 0
loc 12
ccs 6
cts 6
cp 1
rs 9.4285
cc 1
eloc 6
nc 1
nop 3
crap 1
1
<?php
2
3
namespace ale\StringArray;
4
5
/**
6
 * Class StringArray
7
 * A simple implementation of a C-style array as a string.
8
 */
9
class StringArray
10
{
11
12
    /**
13
     * The width of the simulated array.
14
     *
15
     * This is not currently used actively, but might be handy (eg. in case we
16
     * want to initialize the whole string in advance.)
17
     *
18
     * @var int
19
     */
20
    private $width;
21
22
    /**
23
     * The height of the simulated array.
24
     *
25
     * @var int
26
     */
27
    private $height;
28
29
    /**
30
     * The size in bytes of each value in the array.
31
     *
32
     * @var int
33
     */
34
    private $cellSize;
35
36
    /**
37
     * Storage for the actual data.
38
     *
39
     * @var string
40
     */
41
    private $data = '';
42
43 1
    /**
44
     * A cache of the unprintable ASCII characters.
45
     *
46
     * @var array
47
     */
48 1
    private $unprintableChars = array();
49 1
50 1
    /**
51 1
     * The type of data this StringArray can handle.
52 1
     *
53
     * @var string
54
     */
55
    private $type = 'UINT32';
56
57
    /**
58
     * List of types supported by this class.
59
     *
60
     * @var array
61
     */
62
    private $types = array(
63
        'UINT32' => array('size' => 4, 'format' => 'L'),
64 1
        'DOUBLE' => array('size' => 8, 'format' => 'd'),
65
    );
66 1
67
    public function __construct($width, $height, $type = 'UINT32') {
68 1
        // @todo - handle type and cell size internally.
69
70
        // Initialize the string so that PHP won't think it's an array when we
71 1
        // start using offsets.
72 1
        $this->data = str_pad('', 1, chr(0));
73 1
        $this->width = $width;
74 1
        $this->height = $height;
75 1
        $this->type = $type;
76
        // @TODO - validate types.
77
        $this->cellSize = $this->types[$type]['size'];
78
    }
79
80
    /**
81
     * Inserts a value at the requested position.
82
     *
83
     * @param int $i
84
     *   The first dimension position to store the value.
85
     * @param int $j
86
     *   The second dimension position to store the value.
87 1
     * @param mixed $value
88 1
     *   The value to store.
89 1
     */
90 1
    public function insert($i, $j, $value) {
91
        // @todo - validate that the passed value fits in the dimensions.
92
        $index = $this->getIndex($i, $j);
93
        // @todo - generalise hardcoded type.
94
        $encoded = pack($this->types[$this->type]['format'], $value);
95
        // I think this is the fastest way to splice this value into storage,
96
        // but maybe worth checking.
97
        for ($i = 0; $i < $this->types[$this->type]['size']; ++$i) {
98
            $this->data[$index + $i] = $encoded[$i];
99
        }
100
    }
101
102
    /**
103 1
     * Retrieves a value from the given position.
104 1
     *
105
     * @param int $i
106
     *   The first dimension position to retrieve.
107
     * @param int $j
108
     *   the second dimension position to retrieve.
109
     * @return mixed
110
     *   The retrieved value.
111
     */
112
    public function retrieve($i, $j) {
113
        $index = $this->getIndex($i, $j);
114
        $encoded = substr($this->data, $index, $this->types[$this->type]['size']);
115
        // Appending "value" to the unpack format forces the result to be in the
116
        // returned array under that key.
117
        return unpack($this->types[$this->type]['format'] . 'value', $encoded)['value'];
118
    }
119
120
    /**
121
     * Gets an index into the storage string
122
     *
123
     * @param int $i
124
     *   The first dimension position.
125 1
     * @param int $j
126
     *   The second dimension position.
127
     * @return int
128
     *   The caluculated increment into the storage string.
129
     */
130
    private function getIndex($i, $j) {
131
        return ($i * $this->height + $j) * $this->cellSize;
132
    }
133
134
    /**
135
     * Dump the internal storage, replacing some unprintable characters.
136
     */
137
    public function dump() {
138
        // Set up the excluded characters list just once if it hasn't been set.
139
        if (empty($this->unprintableChars)) {
140
            for ($i = 0; $i <= 31; ++$i) {
141
                $this->unprintableChars[] = chr($i);
142
            }
143
        }
144
        return str_replace($this->unprintableChars, '*', $this->data);
145
    }
146
147
    /**
148
     * Gets the size of the internal storage of the array.
149
     *
150
     * @return int
151
     *   The size, in bytes, taken by the internal array storage.
152
     */
153
    public function size() {
154
        return strlen($this->data);
155
    }
156
157
}
158