1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/** |
4
|
|
|
* chdemko\BitArray\BitArray class |
5
|
|
|
* |
6
|
|
|
* @author Christophe Demko <[email protected]> |
7
|
|
|
* @copyright Copyright (C) 2012-2016 Christophe Demko. All rights reserved. |
8
|
|
|
* |
9
|
|
|
* @license http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html The CeCILL B license |
10
|
|
|
* |
11
|
|
|
* This file is part of the php-bitarray package https://github.com/chdemko/php-bitarray |
12
|
|
|
*/ |
13
|
|
|
|
14
|
|
|
// Declare chdemko\BitArray namespace |
15
|
|
|
namespace chdemko\BitArray; |
16
|
|
|
|
17
|
|
|
/** |
18
|
|
|
* Array of bits |
19
|
|
|
* |
20
|
|
|
* @package BitArray |
21
|
|
|
* |
22
|
|
|
* @property-read integer $count The number of bits set to true |
23
|
|
|
* @property-read integer $size The number of bits |
24
|
|
|
* |
25
|
|
|
* @since 1.0.0 |
26
|
|
|
*/ |
27
|
|
|
class BitArray implements \ArrayAccess, \Countable, \IteratorAggregate, \JsonSerializable |
28
|
|
|
{ |
29
|
|
|
/** |
30
|
|
|
* @var integer[] Number of bits for each value between 0 and 255 |
31
|
|
|
*/ |
32
|
|
|
private static $count = [ |
33
|
|
|
0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, |
34
|
|
|
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, |
35
|
|
|
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, |
36
|
|
|
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, |
37
|
|
|
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, |
38
|
|
|
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, |
39
|
|
|
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, |
40
|
|
|
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, |
41
|
|
|
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, |
42
|
|
|
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, |
43
|
|
|
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, |
44
|
|
|
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, |
45
|
|
|
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, |
46
|
|
|
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, |
47
|
|
|
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, |
48
|
|
|
4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8 |
49
|
|
|
]; |
50
|
|
|
|
51
|
|
|
/** |
52
|
|
|
* @var integer[] Mask for restricting complements |
53
|
|
|
*/ |
54
|
|
|
private static $restrict = [255, 1, 3, 7, 15, 31, 63, 127]; |
55
|
|
|
|
56
|
|
|
/** |
57
|
|
|
* @var string Underlying data |
58
|
|
|
* |
59
|
|
|
* @since 1.0.0 |
60
|
|
|
*/ |
61
|
|
|
private $data; |
62
|
|
|
|
63
|
|
|
/** |
64
|
|
|
* @var integer Size of the bit array |
65
|
|
|
* |
66
|
|
|
* @since 1.0.0 |
67
|
|
|
*/ |
68
|
|
|
private $size; |
69
|
|
|
|
70
|
|
|
/** |
71
|
|
|
* Create a new bit array of the given size |
72
|
|
|
* |
73
|
|
|
* @param integer $size The BitArray size |
74
|
|
|
* |
75
|
|
|
* @since 1.0.0 |
76
|
|
|
*/ |
77
|
|
|
protected function __construct($size) |
78
|
|
|
{ |
79
|
|
|
$this->size = (int) $size; |
80
|
|
|
$this->data = str_repeat("\0", ceil($this->size / 8)); |
81
|
|
|
} |
82
|
|
|
|
83
|
|
|
/** |
84
|
|
|
* Clone a bitarray |
85
|
|
|
* |
86
|
|
|
* @return void |
87
|
|
|
* |
88
|
|
|
* @since 1.0.0 |
89
|
|
|
*/ |
90
|
|
|
public function __clone() |
91
|
|
|
{ |
92
|
|
|
$this->data = str_repeat($this->data, 1); |
93
|
|
|
} |
94
|
|
|
|
95
|
|
|
/** |
96
|
|
|
* Convert the object to a string |
97
|
|
|
* |
98
|
|
|
* @return string String representation of this object |
99
|
|
|
* |
100
|
|
|
* @since 1.0.0 |
101
|
|
|
*/ |
102
|
|
|
public function __toString() |
103
|
|
|
{ |
104
|
|
|
$string = str_repeat('0', $this->size); |
105
|
|
|
|
106
|
|
|
for ($offset = 0; $offset < $this->size; $offset++) |
107
|
|
|
{ |
108
|
|
|
if (ord($this->data[(int) ($offset / 8)]) & (1 << $offset % 8)) |
109
|
|
|
{ |
110
|
|
|
$string[$offset] = '1'; |
111
|
|
|
} |
112
|
|
|
} |
113
|
|
|
|
114
|
|
|
return $string; |
115
|
|
|
} |
116
|
|
|
|
117
|
|
|
/** |
118
|
|
|
* Magic get method |
119
|
|
|
* |
120
|
|
|
* @param string $property The property |
121
|
|
|
* |
122
|
|
|
* @throws \RuntimeException If the property does not exist |
123
|
|
|
* |
124
|
|
|
* @return mixed The value associated to the property |
125
|
|
|
* |
126
|
|
|
* @since 1.0.0 |
127
|
|
|
*/ |
128
|
|
|
public function __get($property) |
129
|
|
|
{ |
130
|
|
|
switch ($property) |
131
|
|
|
{ |
132
|
|
|
case 'size': |
133
|
|
|
return $this->size; |
134
|
|
|
case 'count': |
135
|
|
|
return $this->count(); |
136
|
|
|
default: |
137
|
|
|
throw new \RuntimeException('Undefined property'); |
138
|
|
|
} |
139
|
|
|
} |
140
|
|
|
|
141
|
|
|
/** |
142
|
|
|
* Test the existence of an index |
143
|
|
|
* |
144
|
|
|
* @param integer $offset The offset |
145
|
|
|
* |
146
|
|
|
* @return boolean The truth value |
147
|
|
|
* |
148
|
|
|
* @since 1.0.0 |
149
|
|
|
*/ |
150
|
|
|
public function offsetExists($offset) |
151
|
|
|
{ |
152
|
|
|
return is_int($offset) && $offset >= 0 && $offset < $this->size; |
153
|
|
|
} |
154
|
|
|
|
155
|
|
|
/** |
156
|
|
|
* Get the truth value for an index |
157
|
|
|
* |
158
|
|
|
* @param integer $offset The offset |
159
|
|
|
* |
160
|
|
|
* @return boolean The truth value |
161
|
|
|
* |
162
|
|
|
* @throw \OutOfRangeException Argument index must be an positive integer lesser than the size |
163
|
|
|
* |
164
|
|
|
* @since 1.0.0 |
165
|
|
|
*/ |
166
|
|
|
public function offsetGet($offset) |
167
|
|
|
{ |
168
|
|
|
if ($this->offsetExists($offset)) |
169
|
|
|
{ |
170
|
|
|
return (bool) (ord($this->data[(int) ($offset / 8)]) & (1 << $offset % 8)); |
171
|
|
|
} |
172
|
|
|
else |
173
|
|
|
{ |
174
|
|
|
throw new \OutOfRangeException('Argument offset must be a positive integer lesser than the size'); |
175
|
|
|
} |
176
|
|
|
} |
177
|
|
|
|
178
|
|
|
/** |
179
|
|
|
* Set the truth value for an index |
180
|
|
|
* |
181
|
|
|
* @param integer $offset The offset |
182
|
|
|
* @param boolean $value The truth value |
183
|
|
|
* |
184
|
|
|
* @return void |
185
|
|
|
* |
186
|
|
|
* @throw \OutOfRangeException Argument index must be an positive integer lesser than the size |
187
|
|
|
* |
188
|
|
|
* @since 1.0.0 |
189
|
|
|
*/ |
190
|
|
|
public function offsetSet($offset, $value) |
191
|
|
|
{ |
192
|
|
|
if ($this->offsetExists($offset)) |
193
|
|
|
{ |
194
|
|
|
$index = (int) ($offset / 8); |
195
|
|
|
|
196
|
|
|
if ($value) |
197
|
|
|
{ |
198
|
|
|
$this->data[$index] = chr(ord($this->data[$index]) | (1 << $offset % 8)); |
199
|
|
|
} |
200
|
|
|
else |
201
|
|
|
{ |
202
|
|
|
$this->data[$index] = chr(ord($this->data[$index]) & ~(1 << $offset % 8)); |
203
|
|
|
} |
204
|
|
|
} |
205
|
|
|
else |
206
|
|
|
{ |
207
|
|
|
throw new \OutOfRangeException('Argument index must be a positive integer lesser than the size'); |
208
|
|
|
} |
209
|
|
|
} |
210
|
|
|
|
211
|
|
|
/** |
212
|
|
|
* Unset the existence of an index |
213
|
|
|
* |
214
|
|
|
* @param integer $offset The index |
215
|
|
|
* |
216
|
|
|
* @return void |
217
|
|
|
* |
218
|
|
|
* @throw \RuntimeException Values cannot be unset |
219
|
|
|
* |
220
|
|
|
* @since 1.0.0 |
221
|
|
|
*/ |
222
|
|
|
public function offsetUnset($offset) |
223
|
|
|
{ |
224
|
|
|
throw new \RuntimeException('Values cannot be unset'); |
225
|
|
|
} |
226
|
|
|
|
227
|
|
|
/** |
228
|
|
|
* Return the number of true bits |
229
|
|
|
* |
230
|
|
|
* @return integer The number of true bits |
231
|
|
|
* |
232
|
|
|
* @since 1.0.0 |
233
|
|
|
*/ |
234
|
|
|
public function count() |
235
|
|
|
{ |
236
|
|
|
$count = 0; |
237
|
|
|
|
238
|
|
|
for ($i = 0, $length = strlen($this->data); $i < $length; $i++) |
239
|
|
|
{ |
240
|
|
|
$count += self::$count[ord($this->data[$i])]; |
241
|
|
|
} |
242
|
|
|
|
243
|
|
|
return $count; |
244
|
|
|
} |
245
|
|
|
|
246
|
|
|
/** |
247
|
|
|
* Transform the object to an array |
248
|
|
|
* |
249
|
|
|
* @return array Array of values |
250
|
|
|
* |
251
|
|
|
* @since 1.1.0 |
252
|
|
|
*/ |
253
|
|
|
public function toArray() |
254
|
|
|
{ |
255
|
|
|
$array = []; |
256
|
|
|
|
257
|
|
|
for ($offset = 0; $offset < $this->size; $offset++) |
258
|
|
|
{ |
259
|
|
|
$array[] = (bool) (ord($this->data[(int) ($offset / 8)]) & (1 << $offset % 8)); |
260
|
|
|
} |
261
|
|
|
|
262
|
|
|
return $array; |
263
|
|
|
} |
264
|
|
|
|
265
|
|
|
/** |
266
|
|
|
* Serialize the object |
267
|
|
|
* |
268
|
|
|
* @return array Array of values |
269
|
|
|
* |
270
|
|
|
* @since 1.0.0 |
271
|
|
|
*/ |
272
|
|
|
public function jsonSerialize() |
273
|
|
|
{ |
274
|
|
|
return $this->toArray(); |
275
|
|
|
} |
276
|
|
|
|
277
|
|
|
/** |
278
|
|
|
* Get an iterator |
279
|
|
|
* |
280
|
|
|
* @return Iterator Iterator |
281
|
|
|
* |
282
|
|
|
* @since 1.0.0 |
283
|
|
|
*/ |
284
|
|
|
public function getIterator() |
285
|
|
|
{ |
286
|
|
|
return new Iterator($this); |
287
|
|
|
} |
288
|
|
|
|
289
|
|
|
/** |
290
|
|
|
* Return the size |
291
|
|
|
* |
292
|
|
|
* @return integer The size |
293
|
|
|
* |
294
|
|
|
* @since 1.0.0 |
295
|
|
|
*/ |
296
|
|
|
public function size() |
297
|
|
|
{ |
298
|
|
|
return $this->size; |
299
|
|
|
} |
300
|
|
|
|
301
|
|
|
/** |
302
|
|
|
* Create a new BitArray from an integer |
303
|
|
|
* |
304
|
|
|
* @param integer $size Size of the bitarray |
305
|
|
|
* |
306
|
|
|
* @return BitArray A new BitArray |
307
|
|
|
* |
308
|
|
|
* @since 1.0.0 |
309
|
|
|
*/ |
310
|
|
|
public static function fromInteger($size) |
311
|
|
|
{ |
312
|
|
|
return new BitArray($size); |
313
|
|
|
} |
314
|
|
|
|
315
|
|
|
/** |
316
|
|
|
* Create a new BitArray from a traversable |
317
|
|
|
* |
318
|
|
|
* @param \Traversable $traversable A traversable and countable |
319
|
|
|
* |
320
|
|
|
* @return BitArray A new BitArray |
321
|
|
|
* |
322
|
|
|
* @since 1.0.0 |
323
|
|
|
*/ |
324
|
|
View Code Duplication |
public static function fromTraversable($traversable) |
325
|
|
|
{ |
326
|
|
|
$bits = new BitArray(count($traversable)); |
327
|
|
|
$offset = 0; |
328
|
|
|
$ord = 0; |
329
|
|
|
|
330
|
|
|
foreach ($traversable as $value) |
331
|
|
|
{ |
332
|
|
|
if ($value) |
333
|
|
|
{ |
334
|
|
|
$ord |= 1 << $offset % 8; |
335
|
|
|
} |
336
|
|
|
|
337
|
|
|
if ($offset % 8 === 7) |
338
|
|
|
{ |
339
|
|
|
$bits->data[(int) ($offset / 8)] = chr($ord); |
340
|
|
|
$ord = 0; |
341
|
|
|
} |
342
|
|
|
|
343
|
|
|
$offset++; |
344
|
|
|
} |
345
|
|
|
|
346
|
|
|
if ($offset % 8 !== 0) |
347
|
|
|
{ |
348
|
|
|
$bits->data[(int) ($offset / 8)] = chr($ord); |
349
|
|
|
} |
350
|
|
|
|
351
|
|
|
return $bits; |
352
|
|
|
} |
353
|
|
|
|
354
|
|
|
/** |
355
|
|
|
* Create a new BitArray from a bit string |
356
|
|
|
* |
357
|
|
|
* @param string $string A bit string |
358
|
|
|
* |
359
|
|
|
* @return BitArray A new BitArray |
360
|
|
|
* |
361
|
|
|
* @since 1.0.0 |
362
|
|
|
*/ |
363
|
|
View Code Duplication |
public static function fromString($string) |
364
|
|
|
{ |
365
|
|
|
$bits = new BitArray(strlen($string)); |
366
|
|
|
$ord = 0; |
367
|
|
|
|
368
|
|
|
for ($offset = 0; $offset < $bits->size; $offset++) |
369
|
|
|
{ |
370
|
|
|
if ($string[$offset] !== '0') |
371
|
|
|
{ |
372
|
|
|
$ord |= 1 << $offset % 8; |
373
|
|
|
} |
374
|
|
|
|
375
|
|
|
if ($offset % 8 === 7) |
376
|
|
|
{ |
377
|
|
|
$bits->data[(int) ($offset / 8)] = chr($ord); |
378
|
|
|
$ord = 0; |
379
|
|
|
} |
380
|
|
|
} |
381
|
|
|
|
382
|
|
|
if ($offset % 8 !== 0) |
383
|
|
|
{ |
384
|
|
|
$bits->data[(int) ($offset / 8)] = chr($ord); |
385
|
|
|
} |
386
|
|
|
|
387
|
|
|
return $bits; |
388
|
|
|
} |
389
|
|
|
|
390
|
|
|
/** |
391
|
|
|
* Create a new BitArray from json |
392
|
|
|
* |
393
|
|
|
* @param string $json A json encoded value |
394
|
|
|
* |
395
|
|
|
* @return BitArray A new BitArray |
396
|
|
|
* |
397
|
|
|
* @since 1.0.0 |
398
|
|
|
*/ |
399
|
|
|
public static function fromJson($json) |
400
|
|
|
{ |
401
|
|
|
return self::fromTraversable(json_decode($json)); |
402
|
|
|
} |
403
|
|
|
|
404
|
|
|
/** |
405
|
|
|
* Create a new BitArray using a slice |
406
|
|
|
* |
407
|
|
|
* @param BitArray $bits A bitarray to get the slice |
408
|
|
|
* @param int $offset If offset is non-negative, the slice will start at that offset in the bits argument. |
409
|
|
|
* If offset is negative, the slice will start that far from the end of the bits argument. |
410
|
|
|
* @param mixed $size If size is given and is positive, then the slice will have up to that many elements in it. |
411
|
|
|
* If the bits argument is shorter than the size, then only the available elements will be present. |
412
|
|
|
* If size is given and is negative then the slice will stop that many elements from the end of the bits argument. |
413
|
|
|
* If it is omitted, then the slice will have everything from offset up until the end of the bits argument. |
414
|
|
|
* |
415
|
|
|
* @return BitArray A new BitArray |
416
|
|
|
* |
417
|
|
|
* @since 1.1.0 |
418
|
|
|
*/ |
419
|
|
|
public static function fromSlice(BitArray $bits, $offset = 0, $size = null) |
420
|
|
|
{ |
421
|
|
|
$offset = (int) $offset; |
422
|
|
|
|
423
|
|
|
if ($offset < 0) |
424
|
|
|
{ |
425
|
|
|
// Start from the end |
426
|
|
|
$offset = $bits->size + $offset; |
427
|
|
|
|
428
|
|
|
if ($offset < 0) |
429
|
|
|
{ |
430
|
|
|
$offset = 0; |
431
|
|
|
} |
432
|
|
|
} |
433
|
|
|
elseif ($offset > $bits->size) |
434
|
|
|
{ |
435
|
|
|
$offset = $bits->size; |
436
|
|
|
} |
437
|
|
|
|
438
|
|
|
if ($size === null) |
439
|
|
|
{ |
440
|
|
|
$size = $bits->size - $offset; |
441
|
|
|
} |
442
|
|
|
else |
443
|
|
|
{ |
444
|
|
|
$size = (int) $size; |
445
|
|
|
|
446
|
|
|
if ($size < 0) |
447
|
|
|
{ |
448
|
|
|
$size = $bits->size + $size - $offset; |
449
|
|
|
|
450
|
|
|
if ($size < 0) |
451
|
|
|
{ |
452
|
|
|
$size = 0; |
453
|
|
|
} |
454
|
|
|
} |
455
|
|
|
elseif ($size > $bits->size - $offset) |
456
|
|
|
{ |
457
|
|
|
$size = $bits->size - $offset; |
458
|
|
|
} |
459
|
|
|
} |
460
|
|
|
|
461
|
|
|
$slice = new BitArray($size); |
462
|
|
|
|
463
|
|
|
for ($i = 0; $i < $size; $i++) |
464
|
|
|
{ |
465
|
|
|
$slice[$i] = $bits[$i + $offset]; |
466
|
|
|
} |
467
|
|
|
|
468
|
|
|
return $slice; |
469
|
|
|
} |
470
|
|
|
|
471
|
|
|
/** |
472
|
|
|
* Create a new BitArray using the concat operation |
473
|
|
|
* |
474
|
|
|
* @param BitArray $bits1 A bitarray |
475
|
|
|
* @param BitArray $bits2 A bitarray |
476
|
|
|
* |
477
|
|
|
* @return BitArray A new BitArray |
478
|
|
|
* |
479
|
|
|
* @since 1.1.0 |
480
|
|
|
*/ |
481
|
|
|
public static function fromConcat(BitArray $bits1, BitArray $bits2) |
482
|
|
|
{ |
483
|
|
|
$size = $bits1->size + $bits2->size; |
484
|
|
|
$concat = new BitArray($size); |
485
|
|
|
|
486
|
|
View Code Duplication |
for ($i = 0; $i < $bits1->size; $i++) |
|
|
|
|
487
|
|
|
{ |
488
|
|
|
$concat[$i] = $bits1[$i]; |
489
|
|
|
} |
490
|
|
|
|
491
|
|
View Code Duplication |
for ($i = 0; $i < $bits2->size; $i++) |
|
|
|
|
492
|
|
|
{ |
493
|
|
|
$concat[$i + $bits1->size] = $bits2[$i]; |
494
|
|
|
} |
495
|
|
|
|
496
|
|
|
return $concat; |
497
|
|
|
} |
498
|
|
|
|
499
|
|
|
/** |
500
|
|
|
* Complement the bit array |
501
|
|
|
* |
502
|
|
|
* @return BitArray This object for chaining |
503
|
|
|
* |
504
|
|
|
* @since 1.0.0 |
505
|
|
|
*/ |
506
|
|
|
public function applyComplement() |
507
|
|
|
{ |
508
|
|
|
$length = strlen($this->data); |
509
|
|
|
|
510
|
|
|
for ($i = 0; $i < $length; $i++) |
511
|
|
|
{ |
512
|
|
|
$this->data[$i] = chr(~ ord($this->data[$i])); |
513
|
|
|
} |
514
|
|
|
|
515
|
|
|
// Remove useless bits |
516
|
|
|
if ($length > 0) |
517
|
|
|
{ |
518
|
|
|
$this->data[$length - 1] = chr(ord($this->data[$length - 1]) & self::$restrict[$this->size % 8]); |
519
|
|
|
} |
520
|
|
|
|
521
|
|
|
return $this; |
522
|
|
|
} |
523
|
|
|
|
524
|
|
|
/** |
525
|
|
|
* Or with an another bit array |
526
|
|
|
* |
527
|
|
|
* @param BitArray $bits A bit array |
528
|
|
|
* |
529
|
|
|
* @return BitArray This object for chaining |
530
|
|
|
* |
531
|
|
|
* @throw \InvalidArgumentException Argument must be of equal size |
532
|
|
|
* |
533
|
|
|
* @since 1.0.0 |
534
|
|
|
*/ |
535
|
|
View Code Duplication |
public function applyOr(BitArray $bits) |
536
|
|
|
{ |
537
|
|
|
if ($this->size == $bits->size) |
538
|
|
|
{ |
539
|
|
|
$length = strlen($this->data); |
540
|
|
|
|
541
|
|
|
for ($i = 0; $i < $length; $i++) |
542
|
|
|
{ |
543
|
|
|
$this->data[$i] = chr(ord($this->data[$i]) | ord($bits->data[$i])); |
544
|
|
|
} |
545
|
|
|
|
546
|
|
|
return $this; |
547
|
|
|
} |
548
|
|
|
else |
549
|
|
|
{ |
550
|
|
|
throw new \InvalidArgumentException('Argument must be of equal size'); |
551
|
|
|
} |
552
|
|
|
} |
553
|
|
|
|
554
|
|
|
/** |
555
|
|
|
* And with an another bit array |
556
|
|
|
* |
557
|
|
|
* @param BitArray $bits A bit array |
558
|
|
|
* |
559
|
|
|
* @return BitArray This object for chaining |
560
|
|
|
* |
561
|
|
|
* @throw \InvalidArgumentException Argument must be of equal size |
562
|
|
|
* |
563
|
|
|
* @since 1.0.0 |
564
|
|
|
*/ |
565
|
|
View Code Duplication |
public function applyAnd(BitArray $bits) |
566
|
|
|
{ |
567
|
|
|
if ($this->size == $bits->size) |
568
|
|
|
{ |
569
|
|
|
$length = strlen($this->data); |
570
|
|
|
|
571
|
|
|
for ($i = 0; $i < $length; $i++) |
572
|
|
|
{ |
573
|
|
|
$this->data[$i] = chr(ord($this->data[$i]) & ord($bits->data[$i])); |
574
|
|
|
} |
575
|
|
|
|
576
|
|
|
return $this; |
577
|
|
|
} |
578
|
|
|
else |
579
|
|
|
{ |
580
|
|
|
throw new \InvalidArgumentException('Argument must be of equal size'); |
581
|
|
|
} |
582
|
|
|
} |
583
|
|
|
|
584
|
|
|
/** |
585
|
|
|
* Xor with an another bit array |
586
|
|
|
* |
587
|
|
|
* @param BitArray $bits A bit array |
588
|
|
|
* |
589
|
|
|
* @return BitArray This object for chaining |
590
|
|
|
* |
591
|
|
|
* @throw \InvalidArgumentException Argument must be of equal size |
592
|
|
|
* |
593
|
|
|
* @since 1.0.0 |
594
|
|
|
*/ |
595
|
|
View Code Duplication |
public function applyXor(BitArray $bits) |
596
|
|
|
{ |
597
|
|
|
if ($this->size == $bits->size) |
598
|
|
|
{ |
599
|
|
|
$length = strlen($this->data); |
600
|
|
|
|
601
|
|
|
for ($i = 0; $i < $length; $i++) |
602
|
|
|
{ |
603
|
|
|
$this->data[$i] = chr(ord($this->data[$i]) ^ ord($bits->data[$i])); |
604
|
|
|
} |
605
|
|
|
|
606
|
|
|
return $this; |
607
|
|
|
} |
608
|
|
|
else |
609
|
|
|
{ |
610
|
|
|
throw new \InvalidArgumentException('Argument must be of equal size'); |
611
|
|
|
} |
612
|
|
|
} |
613
|
|
|
} |
614
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.