Skip to content

Commit

Permalink
Improve JSONConverter::chunkSize implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
nyamsprod committed Oct 11, 2024
1 parent 9789b05 commit 6c773ff
Showing 1 changed file with 41 additions and 24 deletions.
65 changes: 41 additions & 24 deletions src/JsonConverter.php
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,10 @@ final class JsonConverter
private readonly bool $isForceObject;
/** @var non-empty-string */
private readonly string $indentation;
/** @var Closure(string, array-key): string */
/** @var Closure(string): string */
private readonly Closure $internalFormatter;
/** @var Closure(array): array */
private readonly Closure $chunkFormatter;
/** @var int<1, max> */
public readonly int $chunkSize;

Expand Down Expand Up @@ -140,23 +142,44 @@ private function __construct(int $flags, int $depth, int $indentSize, ?Closure $
$this->formatter = $formatter ?? fn (mixed $value) => $value;
$this->isPrettyPrint = ($this->flags & JSON_PRETTY_PRINT) === JSON_PRETTY_PRINT;
$this->isForceObject = ($this->flags & JSON_FORCE_OBJECT) === JSON_FORCE_OBJECT;
$this->chunkFormatter = $this->setChunkFormatter();
$this->internalFormatter = $this->setInternalFormatter();
$this->chunkSize = $chunkSize;
}

/**
* @return Closure(string, array-key): string
* @return Closure(string): string
*/
private function setInternalFormatter(): Closure
{
$callback = match ($this->isForceObject) {
false => fn (string $json, int|string $offset): string => $json,
default => fn (string $json, int|string $offset): string => '"'.json_encode($offset).'":'.$json,
return match ($this->isPrettyPrint) {
false => fn (string $json): string => $json,
default => $this->prettyPrint(...),
};
}

return match ($this->isPrettyPrint) {
false => $callback,
default => fn (string $json, int|string $offset): string => $this->prettyPrint($callback($json, $offset)),
/**
* @return Closure(array): array
*/
private function setChunkFormatter(): Closure
{
return match (true) {
$this->useFlags(JSON_FORCE_OBJECT) => function (array $value): array {
$data = [];
foreach ($value as $offset => $item) {
$data[$offset] = ($this->formatter)($item, $offset);
}

return $data;
},
default => function (array $value): array {
$data = [];
foreach ($value as $offset => $item) {
$data[] = ($this->formatter)($item, $offset);
}

return $data;
},
};
}

Expand Down Expand Up @@ -407,53 +430,47 @@ public function convert(iterable $records): Iterator
}

$offset = 0;
$incr = 0;
$buffer = [];
$current = $records->current();
$records->next();

yield $start;

$incr = 0;
$buffer = [];
while ($records->valid()) {
if ($incr === $this->chunkSize) {
yield $this->format($buffer, $offset - $incr).$separator;
yield $this->format($buffer).$separator;

$incr = 0;
$buffer = [];
}
$incr++;
$buffer[] = $current;

$offset++;
$incr++;
$buffer[$offset] = $current;
$current = $records->current();
$records->next();
}

if ([] !== $buffer) {
yield $this->format($buffer, $offset - $incr).$separator;
yield $this->format($buffer).$separator;
}

yield $this->format([$current], $offset++).$end;
yield $this->format([$offset => $current]).$end;
}

/**
* @throws JsonException
*/
private function format(array $value, int $offset): string
private function format(array $chunk): string
{
$data = [];
foreach ($value as $item) {
$data[] = ($this->formatter)($item, $offset);
++$offset;
}

$json = json_encode(
value: $data,
value: ($this->chunkFormatter)($chunk),
flags: ($this->flags & ~JSON_PRETTY_PRINT) | JSON_THROW_ON_ERROR,
depth: $this->depth
);

return ($this->internalFormatter)(substr($json, 1, -1), $offset);
return ($this->internalFormatter)(substr($json, 1, -1));
}

/**
Expand Down

0 comments on commit 6c773ff

Please sign in to comment.