gielfeldt/iterators

View on GitHub
src/UniqueIterator.php

Summary

Maintainability
A
0 mins
Test Coverage
<?php

namespace Gielfeldt\Iterators;

class UniqueIterator extends \FilterIterator
{
    protected $found;
    protected $callback;
    protected $method;

    const ASSUME_SORTED = 1;
    const REINDEX = 2;
    const UNIQUE_CURRENT = [__CLASS__, 'filterCurrent'];
    const UNIQUE_KEY = [__CLASS__, 'filterKey'];

    public function __construct(\Traversable $iterator, int $flags = 0, callable $callback = self::UNIQUE_CURRENT)
    {
        parent::__construct($iterator);
        $this->callback = \Closure::fromCallable($callback);

        if ($flags & self::ASSUME_SORTED) {
            $this->method = \Closure::fromCallable([$this, 'filterAssumeSorted']);
        } else {
            $this->method = \Closure::fromCallable([$this, 'filterAssumeUnsorted']);
        }
    }

    public function rewind()
    {
        $this->found = [];
        return parent::rewind();
    }

    public function filterAssumeUnsorted($key)
    {
        if (isset($this->found[$key])) {
            return false;
        }
        $this->found[$key] = true;
        return true;
    }

    public function filterAssumeSorted($key)
    {
        if (isset($this->found[$key])) {
            return false;
        }
        $this->found = [$key => true];
        return true;
    }

    public static function filterCurrent($iterator)
    {
        return $iterator->current();
    }

    public static function filterKey($iterator)
    {
        return $iterator->key();
    }

    public function accept()
    {
        $key = ($this->callback)($this->getInnerIterator());
        $key = is_scalar($key) ? $key : (is_object($key) ? spl_object_hash($key) : serialize($key));
        return ($this->method)($key);
    }
}