Skip to content
This repository has been archived by the owner on Jan 11, 2023. It is now read-only.

Commit

Permalink
Merge pull request #21 from fusonic/generator_support
Browse files Browse the repository at this point in the history
Generator support
  • Loading branch information
davidroth committed Dec 4, 2015
2 parents 896ea6c + 0af31d0 commit f28a3ff
Show file tree
Hide file tree
Showing 28 changed files with 2,707 additions and 2,398 deletions.
9 changes: 8 additions & 1 deletion src/Fusonic/Linq/Helper/LinqHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,20 @@ public static function assertArgumentIsIterable($param, $argumentName)
}
}

public static function assertValueIsIterable($param)
{
if (!self::isIterable($param)) {
throw new \UnexpectedValueException("Value must be an array, or implement either the \IteratorAggregate or \Iterator interface");
}
}

public static function getIteratorOrThrow($value)
{
if (is_array($value)) {
return new ArrayIterator($value);
}
else if($value instanceof \IteratorAggregate) {
return $value->getIterator();
return $value;
}
else if($value instanceof \Iterator) {
return $value;
Expand Down
79 changes: 79 additions & 0 deletions src/Fusonic/Linq/Helper/Set.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
<?php
/*
* This file is part of Fusonic-linq.
* https://github.com/fusonic/fusonic-linq
*
* (c) Fusonic GmbH
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Fusonic\Linq\Helper;


class Set
{
private $objects = array();

/**
* If the value is not in the set, it will be added and true is returned. otherwise false is returned.
* @return bool
*/
public function add($value)
{
return !$this->find($value, true);
}

/**
* If the value is in the set, it will be removed and true is returned. otherwise false is returned.
* @param $value
* @return bool
*/
public function remove($value)
{
$hash = self::hash($value);
if(array_key_exists($hash, $this->objects)) {
unset($this->objects[$hash]);
return true;
}
return false;
}

/**
* Returns true if the value exist in the set. Otherwise false.
* @return bool
*/
public function contains($value)
{
$hash = self::hash($value);
return array_key_exists($hash, $this->objects);
}

// Finds the given value and returns true if it was found. Otherwise return false.
private function find($value, $add = false)
{
$hash = self::hash($value);
if(array_key_exists($hash, $this->objects)) {
return true;
}
else if($add) {
$this->objects[$hash] = $value;
}
return false;
}

private static function hash($value)
{
if (is_object($value)) {
return spl_object_hash($value);
} elseif (is_scalar($value)) {
return "s_$value";
} elseif (is_array($value)) {
return 'a_' . md5(json_encode($value));
} else if($value === null) {
return null;
}
else throw new \InvalidArgumentException("Value type is not supported.");
}
}
80 changes: 17 additions & 63 deletions src/Fusonic/Linq/Iterator/ChunkIterator.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,84 +13,38 @@
namespace Fusonic\Linq\Iterator;

use Fusonic\Linq\Linq;
use Iterator;
use Traversable;

/**
* Iterates over an iterator, returning Linq objects of the given chunk size.
*/
class ChunkIterator implements Iterator
class ChunkIterator implements \IteratorAggregate
{
/**
* @var Iterator
*/
private $iterator;

/**
* @var array
*/
private $chunk;

/**
* @var int
*/
private $i = 0;

/**
* @var int
*/
private $chunkSize;

public function __construct(Iterator $iterator, $chunkSize)
public function __construct(Traversable $iterator, $chunkSize)
{
$this->iterator = $iterator;
$this->chunkSize = $chunkSize;
}

/**
* @return Linq
*/
public function current()
{
return new Linq($this->chunk);
}

public function next()
{
$this->iterator->next();
$this->chunk = $this->getNextChunk();
$this->i++;
}

private function getNextChunk()
public function getIterator()
{
$chunk = [];
while ($this->iterator->valid()) {
$chunk[] = $this->iterator->current();

if (count($chunk) < $this->chunkSize) {
$this->iterator->next();
} else {
break;
$current = 0;
foreach ($this->iterator as $d) {
$current++;
$chunk[] = $d;

if ($current >= $this->chunkSize) {
yield Linq::from($chunk);
$chunk = [];
$current = 0;
}
}

return $chunk;
}

public function key()
{
return $this->i;
}

public function valid()
{
return !empty($this->chunk);
}

public function rewind()
{
$this->iterator->rewind();
$this->i = 0;
$this->chunk = $this->getNextChunk();
if(count($chunk) > 0) {
yield Linq::from($chunk);
}
}
}
}
48 changes: 11 additions & 37 deletions src/Fusonic/Linq/Iterator/DistinctIterator.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,51 +12,25 @@

namespace Fusonic\Linq\Iterator;

use Iterator;
use Fusonic\Linq\Helper\Set;
use Traversable;

class DistinctIterator extends \IteratorIterator
final class DistinctIterator implements \IteratorAggregate
{
private $iterator;
private $distinct;

public function __construct(Iterator $iterator)
public function __construct(Traversable $iterator)
{
$this->iterator = $iterator;
}

public function current()
public function getIterator()
{
return $this->distinct->current();
}

public function next()
{
$this->distinct->next();
}

public function key()
{
return $this->distinct->key();
}

public function valid()
{
return $this->distinct->valid();
}

public function rewind()
{
if ($this->distinct === null) {
$this->getDistincts();
$set = new Set();
foreach($this->iterator as $value) {
if($set->add($value)) {
yield $value;
}
}

$this->distinct->rewind();
}

private function getDistincts()
{
$data = iterator_to_array($this->iterator);
$distinct = array_unique($data);
$this->distinct = new \ArrayIterator($distinct);
}
}
}
52 changes: 14 additions & 38 deletions src/Fusonic/Linq/Iterator/ExceptIterator.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,54 +12,30 @@

namespace Fusonic\Linq\Iterator;

use ArrayIterator;
use Iterator;
use Fusonic\Linq\Helper\Set;
use Traversable;

class ExceptIterator implements Iterator
final class ExceptIterator implements \IteratorAggregate
{
private $first;
private $second;
private $result;

public function __construct(Iterator $first, Iterator $second)
public function __construct(Traversable $first, Traversable $second)
{
$this->first = $first;
$this->second = $second;
}

public function current()
public function getIterator()
{
return $this->result->current();
}

public function next()
{
$this->result->next();
}

public function key()
{
return $this->result->key();
}

public function valid()
{
return $this->result->valid();
}

public function rewind()
{
if ($this->result === null) {
$this->getResult();
$set = new Set();
foreach($this->second as $second) {
$set->add($second);
}
foreach($this->first as $first) {
if(!$set->contains($first)) {
yield $first;
}
}

$this->result->rewind();
}

private function getResult()
{
$firstArray = iterator_to_array($this->first);
$secondArray = iterator_to_array($this->second);
$this->result = new ArrayIterator(array_diff($firstArray, $secondArray));
}
}
}
Loading

0 comments on commit f28a3ff

Please sign in to comment.