Skip to content

Commit 3fd993c

Browse files
committed
Several micro optimizations to the Binary decoder
1 parent 8273a91 commit 3fd993c

File tree

2 files changed

+74
-53
lines changed

2 files changed

+74
-53
lines changed

library/DrSlump/Protobuf/Codec/Binary.php

Lines changed: 56 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,17 @@ public function encode(Protobuf\Message $message)
3030
*/
3131
public function decode(Protobuf\Message $message, $data)
3232
{
33-
return $this->decodeMessage($message, $data);
33+
static $reader;
34+
35+
// Create a single reader for all messages to be parsed
36+
if (!$reader) {
37+
$reader = new Protobuf\Codec\Binary\Reader();
38+
}
39+
40+
// Initialize the reader with the current message data
41+
$reader->init($data);
42+
43+
return $this->decodeMessage($reader, $message);
3444
}
3545

3646

@@ -167,19 +177,26 @@ protected function encodeSimpleType($writer, $type, $value)
167177
}
168178
}
169179

170-
171-
protected function decodeMessage(\DrSlump\Protobuf\Message $message, $data)
180+
/**
181+
* @param \DrSlump\Protobuf\Codec\Binary\Reader $reader
182+
* @param \DrSlump\Protobuf\Message $message
183+
* @param int $length
184+
* @return \DrSlump\Protobuf\Message
185+
*/
186+
protected function decodeMessage($reader, \DrSlump\Protobuf\Message $message, $length = NULL)
172187
{
173188
/** @var $message \DrSlump\Protobuf\Message */
174189
/** @var $descriptor \DrSlump\Protobuf\Descriptor */
175190

176-
// Create a binary reader for the data
177-
$reader = new Protobuf\Codec\Binary\Reader($data);
178-
179191
// Get message descriptor
180192
$descriptor = Protobuf::getRegistry()->getDescriptor($message);
181193

182-
while (!$reader->eof()) {
194+
// Calculate the maximum offset if we have defined a length
195+
$limit = $length ? $reader->pos() + $length : NULL;
196+
$pos = $reader->pos();
197+
198+
// Keep reading until we reach the end or the limit
199+
while ($limit === NULL && !$reader->eof() || $limit !== NULL && $reader->pos() < $limit) {
183200

184201
// Get initial varint with tag number and wire type
185202
$key = $reader->varint();
@@ -203,10 +220,11 @@ protected function decodeMessage(\DrSlump\Protobuf\Message $message, $data)
203220
// flag of the message since we cannot be certain if the creator of the message
204221
// was using it.
205222
if ($wire === self::WIRE_LENGTH && $field->isRepeated() && $this->isPackable($type)) {
206-
$length = $reader->varint();
207-
$until = $reader->pos() + $length;
223+
$len = $reader->varint();
224+
$until = $reader->pos() + $len;
225+
$wire = $this->getWireType($type);
208226
while ($reader->pos() < $until) {
209-
$item = $this->decodeSimpleType($reader, $type, self::WIRE_VARINT);
227+
$item = $this->decodeSimpleType($reader, $type, $wire);
210228
$message->_add($tag, $item);
211229
}
212230

@@ -220,10 +238,10 @@ protected function decodeMessage(\DrSlump\Protobuf\Message $message, $data)
220238
$submessage = $field->getReference();
221239
$submessage = new $submessage;
222240

223-
$length = $this->decodeSimpleType($reader, Protobuf::TYPE_INT64, self::WIRE_VARINT);
224-
$data = $reader->read($length);
241+
$len = $reader->varint();
225242

226-
$value = $this->decodeMessage($submessage, $data);
243+
//$reader2 = new Binary\Reader( $reader->read($len) );
244+
$value = $this->decodeMessage($reader, $submessage, $len);
227245
} else {
228246
$value = $this->decodeSimpleType($reader, $type, $wire);
229247
}
@@ -292,32 +310,28 @@ protected function assertWireType($wire, $type)
292310

293311
protected function getWireType($type, $default)
294312
{
295-
switch ($type) {
296-
case Protobuf::TYPE_INT32:
297-
case Protobuf::TYPE_INT64:
298-
case Protobuf::TYPE_UINT32:
299-
case Protobuf::TYPE_UINT64:
300-
case Protobuf::TYPE_SINT32:
301-
case Protobuf::TYPE_SINT64:
302-
case Protobuf::TYPE_BOOL:
303-
case Protobuf::TYPE_ENUM:
304-
return self::WIRE_VARINT;
305-
case Protobuf::TYPE_FIXED64:
306-
case Protobuf::TYPE_SFIXED64:
307-
case Protobuf::TYPE_DOUBLE:
308-
return self::WIRE_FIXED64;
309-
case Protobuf::TYPE_STRING:
310-
case Protobuf::TYPE_BYTES:
311-
case Protobuf::TYPE_MESSAGE:
312-
return self::WIRE_LENGTH;
313-
case Protobuf::TYPE_FIXED32:
314-
case Protobuf::TYPE_SFIXED32:
315-
case Protobuf::TYPE_FLOAT:
316-
return self::WIRE_FIXED32;
317-
default:
318-
// Unknown fields just return the reported wire type
319-
return $default;
320-
}
313+
static $map = array(
314+
Protobuf::TYPE_INT32 => self::WIRE_VARINT,
315+
Protobuf::TYPE_INT64 => self::WIRE_VARINT,
316+
Protobuf::TYPE_UINT32 => self::WIRE_VARINT,
317+
Protobuf::TYPE_UINT64 => self::WIRE_VARINT,
318+
Protobuf::TYPE_SINT32 => self::WIRE_VARINT,
319+
Protobuf::TYPE_SINT64 => self::WIRE_VARINT,
320+
Protobuf::TYPE_BOOL => self::WIRE_VARINT,
321+
Protobuf::TYPE_ENUM => self::WIRE_VARINT,
322+
Protobuf::TYPE_FIXED64 => self::WIRE_FIXED64,
323+
Protobuf::TYPE_SFIXED64 => self::WIRE_FIXED64,
324+
Protobuf::TYPE_DOUBLE => self::WIRE_FIXED64,
325+
Protobuf::TYPE_STRING => self::WIRE_LENGTH,
326+
Protobuf::TYPE_BYTES => self::WIRE_LENGTH,
327+
Protobuf::TYPE_MESSAGE => self::WIRE_LENGTH,
328+
Protobuf::TYPE_FIXED32 => self::WIRE_FIXED32,
329+
Protobuf::TYPE_SFIXED32 => self::WIRE_FIXED32,
330+
Protobuf::TYPE_FLOAT => self::WIRE_FIXED32
331+
);
332+
333+
// Unknown types just return the reported wire type
334+
return isset($map[$type]) ? $map[$type] : $default;
321335
}
322336

323337
protected function decodeSimpleType($reader, $type, $wireType)
@@ -327,6 +341,7 @@ protected function decodeSimpleType($reader, $type, $wireType)
327341
case Protobuf::TYPE_UINT64:
328342
case Protobuf::TYPE_INT32:
329343
case Protobuf::TYPE_UINT32:
344+
case Protobuf::TYPE_ENUM:
330345
return $reader->varint();
331346

332347
case Protobuf::TYPE_SINT32: // ZigZag
@@ -351,19 +366,12 @@ protected function decodeSimpleType($reader, $type, $wireType)
351366
return (bool)$reader->varint();
352367

353368
case Protobuf::TYPE_STRING:
354-
$length = $reader->varint();
355-
return $reader->read($length);
356-
357-
case Protobuf::TYPE_MESSAGE:
358-
// Messages are not supported in this method
359-
return null;
360-
361369
case Protobuf::TYPE_BYTES:
362370
$length = $reader->varint();
363371
return $reader->read($length);
364372

365-
case Protobuf::TYPE_ENUM:
366-
return $reader->varint();
373+
case Protobuf::TYPE_MESSAGE:
374+
throw new \RuntimeException('Nested messages are not supported in this method');
367375

368376
default:
369377
// Unknown type, follow wire type rules

library/DrSlump/Protobuf/Codec/Binary/Reader.php

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,24 @@ class Reader
2020
*
2121
* @param resource|string $fdOrString
2222
*/
23-
public function __construct($fdOrString)
23+
public function __construct($fdOrString = NULL)
24+
{
25+
if (NULL !== $fdOrString) {
26+
$this->init($fdOrString);
27+
}
28+
}
29+
30+
public function __destruct()
31+
{
32+
fclose($this->_fd);
33+
}
34+
35+
/**
36+
* Create a new reader from a file descriptor or a string of bytes
37+
*
38+
* @param resource|string $fdOrString
39+
*/
40+
public function init($fdOrString)
2441
{
2542
if (is_resource($fdOrString)) {
2643
$this->_fd = $fdOrString;
@@ -30,10 +47,6 @@ public function __construct($fdOrString)
3047
}
3148
}
3249

33-
public function __destruct()
34-
{
35-
fclose($this->_fd);
36-
}
3750

3851
/**
3952
* Obtain a number of bytes from the string

0 commit comments

Comments
 (0)