mirror of
https://github.com/cerbero90/json-parser.git
synced 2025-01-17 13:08:16 +01:00
Optimize time consumption
This commit is contained in:
parent
b74045e9e3
commit
18ea75da4b
@ -6,7 +6,6 @@ use Cerbero\JsonParser\Sources\Source;
|
||||
use Cerbero\JsonParser\Tokens\Token;
|
||||
use Cerbero\JsonParser\Tokens\Tokenizer;
|
||||
use Cerbero\JsonParser\Tokens\Tokens;
|
||||
use Generator;
|
||||
use IteratorAggregate;
|
||||
use Traversable;
|
||||
|
||||
@ -25,25 +24,11 @@ final class Lexer implements IteratorAggregate
|
||||
private Progress $progress;
|
||||
|
||||
/**
|
||||
* The buffer to yield.
|
||||
* The current position.
|
||||
*
|
||||
* @var string
|
||||
* @var int
|
||||
*/
|
||||
private string $buffer = '';
|
||||
|
||||
/**
|
||||
* Whether the current character is escaped.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private bool $isEscaping = false;
|
||||
|
||||
/**
|
||||
* Whether the current character belongs to a string.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private bool $inString = false;
|
||||
private int $position = 0;
|
||||
|
||||
/**
|
||||
* Instantiate the class.
|
||||
@ -62,53 +47,34 @@ final class Lexer implements IteratorAggregate
|
||||
*/
|
||||
public function getIterator(): Traversable
|
||||
{
|
||||
$buffer = '';
|
||||
$inString = $isEscaping = false;
|
||||
|
||||
foreach ($this->source as $chunk) {
|
||||
for ($i = 0, $size = strlen($chunk); $i < $size; $i++, $this->progress->advance()) {
|
||||
for ($i = 0, $size = strlen($chunk); $i < $size; $i++, $this->position++) {
|
||||
$character = $chunk[$i];
|
||||
$this->inString = $this->inString($character);
|
||||
$this->isEscaping = $character == '\\' && !$this->isEscaping;
|
||||
$inString = ($character == '"' && $inString && $isEscaping)
|
||||
|| ($character != '"' && $inString)
|
||||
|| ($character == '"' && !$inString);
|
||||
$isEscaping = $character == '\\' && !$isEscaping;
|
||||
|
||||
yield from $this->yieldOrBufferCharacter($character);
|
||||
if ($inString || !isset(Tokens::BOUNDARIES[$character])) {
|
||||
$buffer .= $character;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($buffer != '') {
|
||||
yield Tokenizer::instance()->toToken($buffer);
|
||||
$buffer = '';
|
||||
}
|
||||
|
||||
if (isset(Tokens::DELIMITERS[$character])) {
|
||||
yield Tokenizer::instance()->toToken($character);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the given character is within a string
|
||||
*
|
||||
* @param string $character
|
||||
* @return bool
|
||||
*/
|
||||
private function inString(string $character): bool
|
||||
{
|
||||
return ($character == '"' && $this->inString && $this->isEscaping)
|
||||
|| ($character != '"' && $this->inString)
|
||||
|| ($character == '"' && !$this->inString);
|
||||
}
|
||||
|
||||
/**
|
||||
* Yield the given character or buffer it
|
||||
*
|
||||
* @param string $character
|
||||
* @return Generator<int, Token>
|
||||
*/
|
||||
private function yieldOrBufferCharacter(string $character): Generator
|
||||
{
|
||||
if ($this->inString || !isset(Tokens::BOUNDARIES[$character])) {
|
||||
$this->buffer .= $character;
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->buffer != '') {
|
||||
yield Tokenizer::instance()->toToken($this->buffer);
|
||||
$this->buffer = '';
|
||||
}
|
||||
|
||||
if (isset(Tokens::DELIMITERS[$character])) {
|
||||
yield Tokenizer::instance()->toToken($character);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the parsing progress
|
||||
*
|
||||
@ -116,6 +82,6 @@ final class Lexer implements IteratorAggregate
|
||||
*/
|
||||
public function progress(): Progress
|
||||
{
|
||||
return $this->progress->setTotal($this->source->size());
|
||||
return $this->progress->setCurrent($this->position)->setTotal($this->source->size());
|
||||
}
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ final class Pointer implements Stringable
|
||||
*
|
||||
* @var Closure
|
||||
*/
|
||||
private Closure $callback;
|
||||
private ?Closure $callback;
|
||||
|
||||
/**
|
||||
* Whether the pointer was found.
|
||||
@ -51,7 +51,7 @@ final class Pointer implements Stringable
|
||||
{
|
||||
$this->referenceTokens = $this->toReferenceTokens();
|
||||
$this->depth = count($this->referenceTokens);
|
||||
$this->callback = $callback ?: fn (mixed $value) => $value;
|
||||
$this->callback = $callback;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -100,6 +100,10 @@ final class Pointer implements Stringable
|
||||
*/
|
||||
public function call(mixed $value, mixed $key): mixed
|
||||
{
|
||||
if ($this->callback === null) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
return call_user_func($this->callback, $value, $key) ?? $value;
|
||||
}
|
||||
|
||||
@ -126,7 +130,9 @@ final class Pointer implements Stringable
|
||||
*/
|
||||
public function matchesTree(Tree $tree): bool
|
||||
{
|
||||
return in_array($this->referenceTokens, [[], $tree->original(), $tree->wildcarded()]);
|
||||
return $this->referenceTokens == []
|
||||
|| $this->referenceTokens == $tree->original()
|
||||
|| $this->referenceTokens == $tree->wildcarded();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -23,13 +23,14 @@ final class Progress
|
||||
private ?int $total = null;
|
||||
|
||||
/**
|
||||
* Advance the progress
|
||||
* Set the current progress
|
||||
*
|
||||
* @param int $current
|
||||
* @return static
|
||||
*/
|
||||
public function advance(): static
|
||||
public function setCurrent(int $current): static
|
||||
{
|
||||
$this->current++;
|
||||
$this->current = $current;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
@ -146,8 +146,9 @@ final class State
|
||||
{
|
||||
$treeChanged = false;
|
||||
$shouldTrackTree = $this->pointer == '' || $this->tree->depth() < $this->pointer->depth();
|
||||
$tokenIsValue = $token->isValue();
|
||||
|
||||
if ($shouldTrackTree && $token->isValue() && !$this->inObject()) {
|
||||
if ($shouldTrackTree && $tokenIsValue && !$this->inObject()) {
|
||||
$this->tree->traverseArray($this->pointer->referenceTokens());
|
||||
$treeChanged = true;
|
||||
}
|
||||
@ -161,27 +162,16 @@ final class State
|
||||
$this->pointer = $this->pointers->matchTree($this->tree);
|
||||
}
|
||||
|
||||
$this->bufferToken($token);
|
||||
|
||||
$token->mutateState($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Buffer the given token
|
||||
*
|
||||
* @param Token $token
|
||||
* @return void
|
||||
*/
|
||||
private function bufferToken(Token $token): void
|
||||
{
|
||||
$shouldBuffer = $this->tree->depth() >= 0
|
||||
&& $this->pointer->matchesTree($this->tree)
|
||||
&& ($this->treeIsDeep() || ($token->isValue() && !$this->expectsKey));
|
||||
&& (($tokenIsValue && !$this->expectsKey) || $this->treeIsDeep());
|
||||
|
||||
if ($shouldBuffer) {
|
||||
$this->buffer .= $token;
|
||||
$this->pointers->markAsFound($this->pointer);
|
||||
}
|
||||
|
||||
$token->mutateState($this);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -22,15 +22,6 @@ final class Tokenizer
|
||||
*/
|
||||
private array $tokensMap;
|
||||
|
||||
/**
|
||||
* Instantiate the class.
|
||||
*
|
||||
*/
|
||||
private function __construct()
|
||||
{
|
||||
$this->setTokensMap();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the singleton instance
|
||||
*
|
||||
@ -41,6 +32,15 @@ final class Tokenizer
|
||||
return static::$instance ??= new static();
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiate the class.
|
||||
*
|
||||
*/
|
||||
private function __construct()
|
||||
{
|
||||
$this->setTokensMap();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the tokens map
|
||||
*
|
||||
|
13
src/Tree.php
13
src/Tree.php
@ -92,16 +92,6 @@ final class Tree
|
||||
$this->original[$this->depth] = $trimmedKey;
|
||||
$this->wildcarded[$this->depth] = $trimmedKey;
|
||||
|
||||
$this->trim();
|
||||
}
|
||||
|
||||
/**
|
||||
* Trim the tree after the latest traversed key
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function trim(): void
|
||||
{
|
||||
array_splice($this->original, $this->depth + 1);
|
||||
array_splice($this->wildcarded, $this->depth + 1);
|
||||
}
|
||||
@ -120,7 +110,8 @@ final class Tree
|
||||
$this->original[$this->depth] = is_int($index) ? $index + 1 : 0;
|
||||
$this->wildcarded[$this->depth] = $referenceToken == '-' ? '-' : $this->original[$this->depth];
|
||||
|
||||
$this->trim();
|
||||
array_splice($this->original, $this->depth + 1);
|
||||
array_splice($this->wildcarded, $this->depth + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
x
Reference in New Issue
Block a user