IntArray.php
6. 6. 2013, aktualizováno: 29. 9. 2021 #kód
Unboxed int array in PHP
// advanced bit-twiddling abstract class AbstractIntArray { protected int $length; protected string $data; protected int $typeSize; function __construct(int $length) { $this->length = $length; $this->data = str_repeat("\0", $length * $this->typeSize); } protected function checkIndex(int $idx) { if ($idx < 0 || $idx >= $this->length) throw new \OutOfRangeException("index out of range"); } function getData() { return $this->data; } } /** store unsigned bytes */ final class ByteArray extends AbstractIntArray { protected int $typeSize = 1; function get(int $idx) { $this->checkIndex($idx); return ord($this->data[$idx]); } function put(int $idx, int $val) { $this->checkIndex($idx); if ($val < 0 || $val > 255) throw new \OutOfRangeException(); $this->data[$idx] = chr($val); } } final class BitSet extends AbstractIntArray { protected int $length; private ByteArray $byteArray; function __construct(int $length) { $this->length = $length; $this->byteArray = new ByteArray(ceil($length / 8)); } function get(int $idx) { $this->checkIndex($idx); $byteIdx = intdiv($idx, 8); $bitIdx = $idx % 8; $byte = $this->byteArray->get($byteIdx); return (($byte >> $bitIdx) & 1) === 1; } function put(int $idx, bool $val) { $this->checkIndex($idx); $byteIdx = intdiv($idx, 8); $bitIdx = $idx % 8; $byte = $this->byteArray->get($byteIdx); if ($val) { $byte |= (1 << $bitIdx); } else { $byte &= ~(1 << $bitIdx); } $this->byteArray->put($byteIdx, $byte & 0xff); } function getData() { return $this->byteArray->getData(); } } final class Int32Array extends AbstractIntArray { protected int $typeSize = 4; function get(int $idx) { $this->checkIndex($idx); return unpack('V', $this->data, $idx * 4)[1]; } function put(int $idx, int $val) { $this->checkIndex($idx); $bytes = pack('V', $val); $base = $idx * 4; for ($i = 0; $i < 4; $i++) { $this->data[$base + $i] = $bytes[$i]; } } } final class Int64Array extends AbstractIntArray { protected int $typeSize = 8; function get(int $idx) { $this->checkIndex($idx); return unpack('P', $this->data, $idx * 4)[1]; } function put(int $idx, int $val) { $this->checkIndex($idx); $bytes = pack('P', $val); $base = $idx * 8; for ($i = 0; $i < 8; $i++) { $this->data[$base + $i] = $bytes[$i]; } } }
Array with 1000000 integers:
- PHP 5.3 array: 129.0 MB
- PHP 5.5 array: 96.0 MB
- PHP 7.4 array: 33.5 MB
- Int32Array: 4.2 MB