Skip to content

Commit

Permalink
native iterator
Browse files Browse the repository at this point in the history
  • Loading branch information
dakujem committed Jan 19, 2024
1 parent c3744c3 commit bab07ab
Show file tree
Hide file tree
Showing 2 changed files with 106 additions and 10 deletions.
70 changes: 70 additions & 0 deletions src/Iterator/Native.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
<?php

declare(strict_types=1);

namespace Dakujem\Oliva\Iterator;

use Dakujem\Oliva\Seed;
use Dakujem\Oliva\TreeNodeContract;
use Iterator;
use RecursiveIterator;

/**
* An implementation of native `RecursiveIterator`, to be used with `RecursiveIteratorIterator`.
* @see RecursiveIteratorIterator
*
* ```
* new RecursiveIteratorIterator(new Native($root), RecursiveIteratorIterator::SELF_FIRST)
* ```
*
* @author Andrej Rypak <xrypak@gmail.com>
*/
final class Native implements RecursiveIterator
{
private Iterator $iterator;

public function __construct(
TreeNodeContract|iterable $nodes,
) {
$this->iterator = Seed::iterator(
input: $nodes instanceof TreeNodeContract ? [$nodes] : $nodes,
);
}

public function hasChildren(): bool
{
return !$this->current()->isLeaf();
}

public function getChildren(): ?self
{
return new self(
nodes: $this->current()->children(),
);
}

public function current(): TreeNodeContract
{
return $this->iterator->current();
}

public function next(): void
{
$this->iterator->next();
}

public function key(): mixed
{
return $this->iterator->key();
}

public function valid(): bool
{
return $this->iterator->valid();
}

public function rewind(): void
{
$this->iterator->rewind();
}
}
46 changes: 36 additions & 10 deletions tests/iterators.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ declare(strict_types=1);

use Dakujem\Oliva\DataNodeContract;
use Dakujem\Oliva\Iterator\LevelOrderTraversal;
use Dakujem\Oliva\Iterator\Native;
use Dakujem\Oliva\Iterator\PostOrderTraversal;
use Dakujem\Oliva\Iterator\PreOrderTraversal;
use Dakujem\Oliva\Iterator\Support\Counter;
Expand All @@ -16,6 +17,18 @@ require_once __DIR__ . '/../vendor/autoload.php';
Environment::setup();

(function () {
$counter = new Counter();
Assert::same(0, $counter->current());
Assert::same(0, $counter->touch());
Assert::same(1, $counter->touch());
Assert::same(2, $counter->current());
Assert::same(3, $counter->next());
Assert::same(3, $counter->current());

$counter = new Counter(5);
Assert::same(5, $counter->current());


$a = new Node('A');
$b = new Node('B');
$c = new Node('C');
Expand Down Expand Up @@ -219,17 +232,30 @@ Environment::setup();
Assert::same($expected, array_map(fn(DataNodeContract $node) => $node->data(), iterator_to_array($iterator)));


$counter = new Counter();
Assert::same(0, $counter->current());
Assert::same(0, $counter->touch());
Assert::same(1, $counter->touch());
Assert::same(2, $counter->current());
Assert::same(3, $counter->next());
Assert::same(3, $counter->current());
// level-order (?), leaves only (the default)
$str = [];
foreach (new RecursiveIteratorIterator(new Native($root)) as $node) {
$str[] = $node->data();
}
Assert::same('A,C,E,H', implode(',', $str));
$str = [];
foreach (new RecursiveIteratorIterator(new Native($root), RecursiveIteratorIterator::LEAVES_ONLY) as $node) {
$str[] = $node->data();
}
Assert::same('A,C,E,H', implode(',', $str));

$counter = new Counter(5);
Assert::same(5, $counter->current());
//$root->addChild(new)
// pre-order, all nodes
$str = [];
foreach (new RecursiveIteratorIterator(new Native($root), RecursiveIteratorIterator::SELF_FIRST) as $node) {
$str[] = $node->data();
}
Assert::same('F,B,A,D,C,E,G,I,H', implode(',', $str));

// post-order, all nodes
$str = [];
foreach (new RecursiveIteratorIterator(new Native($root), RecursiveIteratorIterator::CHILD_FIRST) as $node) {
$str[] = $node->data();
}
Assert::same('A,C,E,D,B,H,I,G,F', implode(',', $str));
})();

0 comments on commit bab07ab

Please sign in to comment.