Implement progress

This commit is contained in:
Andrea Marco Sartori 2023-01-22 09:49:24 +10:00
parent 9f5e808962
commit 403abb8859
4 changed files with 181 additions and 44 deletions

View File

@ -54,27 +54,13 @@ final class JsonParser implements IteratorAggregate
}
/**
* Set the simdjson decoder
* Retrieve the lazily iterable JSON
*
* @param bool $decodesToArray
* @return static
* @return Traversable<string|int, mixed>
*/
public function simdjson(bool $decodesToArray = true): static
public function getIterator(): Traversable
{
return $this->decoder(new SimdjsonDecoder($decodesToArray));
}
/**
* Set the JSON decoder
*
* @param Decoder $decoder
* @return static
*/
public function decoder(Decoder $decoder): static
{
$this->config->decoder = $decoder;
return $this;
return $this->parser;
}
/**
@ -106,6 +92,55 @@ final class JsonParser implements IteratorAggregate
return $this;
}
/**
* Traverse the lazily iterable JSON
*
* @param Closure|null $callback
* @return void
*/
public function traverse(Closure $callback = null): void
{
$callback ??= fn () => true;
foreach ($this as $key => $value) {
$callback($value, $key, $this);
}
}
/**
* Set the simdjson decoder
*
* @param bool $decodesToArray
* @return static
*/
public function simdjson(bool $decodesToArray = true): static
{
return $this->decoder(new SimdjsonDecoder($decodesToArray));
}
/**
* Set the JSON decoder
*
* @param Decoder $decoder
* @return static
*/
public function decoder(Decoder $decoder): static
{
$this->config->decoder = $decoder;
return $this;
}
/**
* Retrieve the parsing progress
*
* @return Progress
*/
public function progress(): Progress
{
return $this->parser->progress();
}
/**
* The number of bytes to read in each chunk
*
@ -141,29 +176,4 @@ final class JsonParser implements IteratorAggregate
return $this;
}
/**
* Traverse the lazily iterable JSON
*
* @param Closure|null $callback
* @return void
*/
public function traverse(Closure $callback = null): void
{
$callback ??= fn () => true;
foreach ($this as $key => $value) {
$callback($value, $key, $this);
}
}
/**
* Retrieve the lazily iterable JSON
*
* @return Traversable<string|int, mixed>
*/
public function getIterator(): Traversable
{
return $this->parser;
}
}

View File

@ -17,6 +17,13 @@ use Traversable;
*/
final class Lexer implements IteratorAggregate
{
/**
* The parsing progress.
*
* @var Progress
*/
private Progress $progress;
/**
* The buffer to yield.
*
@ -45,6 +52,7 @@ final class Lexer implements IteratorAggregate
*/
public function __construct(private Source $source)
{
$this->progress = new Progress();
}
/**
@ -55,7 +63,7 @@ final class Lexer implements IteratorAggregate
public function getIterator(): Traversable
{
foreach ($this->source as $chunk) {
for ($i = 0, $size = strlen($chunk); $i < $size; $i++) {
for ($i = 0, $size = strlen($chunk); $i < $size; $i++, $this->progress->advance()) {
$character = $chunk[$i];
$this->inString = $this->inString($character);
$this->isEscaping = $character == '\\' && !$this->isEscaping;
@ -100,4 +108,14 @@ final class Lexer implements IteratorAggregate
yield Tokenizer::instance()->toToken($character);
}
}
/**
* Retrieve the parsing progress
*
* @return Progress
*/
public function progress(): Progress
{
return $this->progress->setTotal($this->source->size());
}
}

View File

@ -80,4 +80,14 @@ final class Parser implements IteratorAggregate
}
}
}
/**
* Retrieve the parsing progress
*
* @return Progress
*/
public function progress(): Progress
{
return $this->lexer->progress();
}
}

99
src/Progress.php Normal file
View File

@ -0,0 +1,99 @@
<?php
namespace Cerbero\JsonParser;
/**
* The parsing progress.
*
*/
final class Progress
{
/**
* The current progress.
*
* @var int
*/
private int $current = 0;
/**
* The total possible progress.
*
* @var int|null
*/
private ?int $total = null;
/**
* Advance the progress
*
* @return static
*/
public function advance(): static
{
$this->current++;
return $this;
}
/**
* Retrieve the current progress
*
* @return int
*/
public function current(): int
{
return $this->current;
}
/**
* Set the total possible progress
*
* @param int|null $total
* @return static
*/
public function setTotal(?int $total): static
{
$this->total ??= $total;
return $this;
}
/**
* Retrieve the total possible progress
*
* @return int|null
*/
public function total(): ?int
{
return $this->total;
}
/**
* Retrieve the formatted percentage of the progress
*
* @return string|null
*/
public function format(): ?string
{
return is_null($percentage = $this->percentage()) ? null : number_format($percentage, 1) . '%';
}
/**
* Retrieve the percentage of the progress
*
* @return float|null
*/
public function percentage(): ?float
{
return is_null($fraction = $this->fraction()) ? null : $fraction * 100;
}
/**
* Retrieve the fraction of the progress
*
* @return float|null
*/
public function fraction(): ?float
{
return $this->total ? $this->current / $this->total : null;
}
}