From f622e5996c9e687c99bebc30d8f4ece278f487e4 Mon Sep 17 00:00:00 2001 From: Armen Baghumian Date: Fri, 4 Dec 2015 06:10:11 +0000 Subject: [PATCH] Optimize get* operation It's slightly faster to convert the value to signed value in PHP as opposed to use pack and unpack. For 1M get operation the difference is: getShort in 3.3272678852081 seconds getInt in 3.8338589668274 seconds getLong in 5.6381590366364 seconds getLong (neg) in 5.6149101257324 seconds vs getShort in 2.7564418315887 seconds getInt in 3.1612701416016 seconds getLong in 3.1369340419769 seconds getLong (neg) in 3.1478710174561 seconds And since pack("P") and unpack("q") has been removed now ByteBuffer works for PHP >= 5.4 --- php/ByteBuffer.php | 32 +++++++++++--------------------- tests/phpTest.php | 13 +++++++++++++ 2 files changed, 24 insertions(+), 21 deletions(-) diff --git a/php/ByteBuffer.php b/php/ByteBuffer.php index cd6af76aa..9ab9717af 100644 --- a/php/ByteBuffer.php +++ b/php/ByteBuffer.php @@ -372,7 +372,11 @@ class ByteBuffer { $result = $this->readLittleEndian($index, 2); - return self::convertHelper(self::__SHORT, $result); + $sign = $index + (ByteBuffer::isLittleEndian() ? 1 : 0); + $issigned = isset($this->_buffer[$sign]) && ord($this->_buffer[$sign]) & 0x80; + + // 65536 = 1 << 16 = Maximum unsigned 16-bit int + return $issigned ? $result - 65536 : $result; } /** @@ -392,7 +396,11 @@ class ByteBuffer { $result = $this->readLittleEndian($index, 4); - return self::convertHelper(self::__INT, $result); + $sign = $index + (ByteBuffer::isLittleEndian() ? 3 : 0); + $issigned = isset($this->_buffer[$sign]) && ord($this->_buffer[$sign]) & 0x80; + + // 4294967296 = 1 << 32 = Maximum unsigned 32-bit int + return $issigned ? $result - 4294967296 : $result; } /** @@ -410,9 +418,7 @@ class ByteBuffer */ public function getLong($index) { - $result = $this->readLittleEndian($index, 8); - - return self::convertHelper(self::__LONG, $result); + return $this->readLittleEndian($index, 8); } /** @@ -459,22 +465,6 @@ class ByteBuffer // see also: http://php.net/manual/en/function.pack.php switch ($type) { - case self::__SHORT: - $helper = pack("v", $value); - $v = unpack("s", $helper); - - return $v[1]; - break; - case self::__INT: - $helper = pack("V", $value); - $v = unpack("l", $helper); - return $v[1]; - break; - case self::__LONG: - $helper = pack("P", $value); - $v = unpack("q", $helper); - return $v[1]; - break; case self::__FLOAT: $inthelper = pack("V", $value); $v = unpack("f", $inthelper); diff --git a/tests/phpTest.php b/tests/phpTest.php index c942ef121..e91e47a1d 100644 --- a/tests/phpTest.php +++ b/tests/phpTest.php @@ -539,6 +539,19 @@ function testByteBuffer(Assert $assert) { $buffer[7] = chr(0x01); $uut = Google\FlatBuffers\ByteBuffer::wrap($buffer); $assert->Equal(0x010203040A0B0C0D, $uut->getLong(0)); + + //Test: Signed Long + $buffer = str_repeat("\0", 8); + $buffer[0] = chr(0x00); + $buffer[1] = chr(0x00); + $buffer[2] = chr(0x00); + $buffer[3] = chr(0x00); + $buffer[4] = chr(0x00); + $buffer[5] = chr(0x00); + $buffer[6] = chr(0x00); + $buffer[7] = chr(0x80); + $uut = Google\FlatBuffers\ByteBuffer::wrap($buffer); + $assert->Equal(-1 << 63, $uut->getLong(0)); } //Test: ByteBuffer_GetLongChecksOffset