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

Commit f28a3ff

Browse files
committed
Merge pull request #21 from fusonic/generator_support
Generator support
2 parents 896ea6c + 0af31d0 commit f28a3ff

28 files changed

Lines changed: 2707 additions & 2398 deletions

src/Fusonic/Linq/Helper/LinqHelper.php

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,13 +43,20 @@ public static function assertArgumentIsIterable($param, $argumentName)
4343
}
4444
}
4545

46+
public static function assertValueIsIterable($param)
47+
{
48+
if (!self::isIterable($param)) {
49+
throw new \UnexpectedValueException("Value must be an array, or implement either the \IteratorAggregate or \Iterator interface");
50+
}
51+
}
52+
4653
public static function getIteratorOrThrow($value)
4754
{
4855
if (is_array($value)) {
4956
return new ArrayIterator($value);
5057
}
5158
else if($value instanceof \IteratorAggregate) {
52-
return $value->getIterator();
59+
return $value;
5360
}
5461
else if($value instanceof \Iterator) {
5562
return $value;

src/Fusonic/Linq/Helper/Set.php

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
<?php
2+
/*
3+
* This file is part of Fusonic-linq.
4+
* https://github.com/fusonic/fusonic-linq
5+
*
6+
* (c) Fusonic GmbH
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Fusonic\Linq\Helper;
13+
14+
15+
class Set
16+
{
17+
private $objects = array();
18+
19+
/**
20+
* If the value is not in the set, it will be added and true is returned. otherwise false is returned.
21+
* @return bool
22+
*/
23+
public function add($value)
24+
{
25+
return !$this->find($value, true);
26+
}
27+
28+
/**
29+
* If the value is in the set, it will be removed and true is returned. otherwise false is returned.
30+
* @param $value
31+
* @return bool
32+
*/
33+
public function remove($value)
34+
{
35+
$hash = self::hash($value);
36+
if(array_key_exists($hash, $this->objects)) {
37+
unset($this->objects[$hash]);
38+
return true;
39+
}
40+
return false;
41+
}
42+
43+
/**
44+
* Returns true if the value exist in the set. Otherwise false.
45+
* @return bool
46+
*/
47+
public function contains($value)
48+
{
49+
$hash = self::hash($value);
50+
return array_key_exists($hash, $this->objects);
51+
}
52+
53+
// Finds the given value and returns true if it was found. Otherwise return false.
54+
private function find($value, $add = false)
55+
{
56+
$hash = self::hash($value);
57+
if(array_key_exists($hash, $this->objects)) {
58+
return true;
59+
}
60+
else if($add) {
61+
$this->objects[$hash] = $value;
62+
}
63+
return false;
64+
}
65+
66+
private static function hash($value)
67+
{
68+
if (is_object($value)) {
69+
return spl_object_hash($value);
70+
} elseif (is_scalar($value)) {
71+
return "s_$value";
72+
} elseif (is_array($value)) {
73+
return 'a_' . md5(json_encode($value));
74+
} else if($value === null) {
75+
return null;
76+
}
77+
else throw new \InvalidArgumentException("Value type is not supported.");
78+
}
79+
}

src/Fusonic/Linq/Iterator/ChunkIterator.php

Lines changed: 17 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -13,84 +13,38 @@
1313
namespace Fusonic\Linq\Iterator;
1414

1515
use Fusonic\Linq\Linq;
16-
use Iterator;
16+
use Traversable;
1717

1818
/**
1919
* Iterates over an iterator, returning Linq objects of the given chunk size.
2020
*/
21-
class ChunkIterator implements Iterator
21+
class ChunkIterator implements \IteratorAggregate
2222
{
23-
/**
24-
* @var Iterator
25-
*/
2623
private $iterator;
27-
28-
/**
29-
* @var array
30-
*/
31-
private $chunk;
32-
33-
/**
34-
* @var int
35-
*/
36-
private $i = 0;
37-
38-
/**
39-
* @var int
40-
*/
4124
private $chunkSize;
4225

43-
public function __construct(Iterator $iterator, $chunkSize)
26+
public function __construct(Traversable $iterator, $chunkSize)
4427
{
4528
$this->iterator = $iterator;
4629
$this->chunkSize = $chunkSize;
4730
}
4831

49-
/**
50-
* @return Linq
51-
*/
52-
public function current()
53-
{
54-
return new Linq($this->chunk);
55-
}
56-
57-
public function next()
58-
{
59-
$this->iterator->next();
60-
$this->chunk = $this->getNextChunk();
61-
$this->i++;
62-
}
63-
64-
private function getNextChunk()
32+
public function getIterator()
6533
{
6634
$chunk = [];
67-
while ($this->iterator->valid()) {
68-
$chunk[] = $this->iterator->current();
69-
70-
if (count($chunk) < $this->chunkSize) {
71-
$this->iterator->next();
72-
} else {
73-
break;
35+
$current = 0;
36+
foreach ($this->iterator as $d) {
37+
$current++;
38+
$chunk[] = $d;
39+
40+
if ($current >= $this->chunkSize) {
41+
yield Linq::from($chunk);
42+
$chunk = [];
43+
$current = 0;
7444
}
7545
}
76-
77-
return $chunk;
78-
}
79-
80-
public function key()
81-
{
82-
return $this->i;
83-
}
84-
85-
public function valid()
86-
{
87-
return !empty($this->chunk);
88-
}
89-
90-
public function rewind()
91-
{
92-
$this->iterator->rewind();
93-
$this->i = 0;
94-
$this->chunk = $this->getNextChunk();
46+
if(count($chunk) > 0) {
47+
yield Linq::from($chunk);
48+
}
9549
}
96-
}
50+
}

src/Fusonic/Linq/Iterator/DistinctIterator.php

Lines changed: 11 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -12,51 +12,25 @@
1212

1313
namespace Fusonic\Linq\Iterator;
1414

15-
use Iterator;
15+
use Fusonic\Linq\Helper\Set;
16+
use Traversable;
1617

17-
class DistinctIterator extends \IteratorIterator
18+
final class DistinctIterator implements \IteratorAggregate
1819
{
1920
private $iterator;
20-
private $distinct;
2121

22-
public function __construct(Iterator $iterator)
22+
public function __construct(Traversable $iterator)
2323
{
2424
$this->iterator = $iterator;
2525
}
2626

27-
public function current()
27+
public function getIterator()
2828
{
29-
return $this->distinct->current();
30-
}
31-
32-
public function next()
33-
{
34-
$this->distinct->next();
35-
}
36-
37-
public function key()
38-
{
39-
return $this->distinct->key();
40-
}
41-
42-
public function valid()
43-
{
44-
return $this->distinct->valid();
45-
}
46-
47-
public function rewind()
48-
{
49-
if ($this->distinct === null) {
50-
$this->getDistincts();
29+
$set = new Set();
30+
foreach($this->iterator as $value) {
31+
if($set->add($value)) {
32+
yield $value;
33+
}
5134
}
52-
53-
$this->distinct->rewind();
54-
}
55-
56-
private function getDistincts()
57-
{
58-
$data = iterator_to_array($this->iterator);
59-
$distinct = array_unique($data);
60-
$this->distinct = new \ArrayIterator($distinct);
6135
}
62-
}
36+
}

src/Fusonic/Linq/Iterator/ExceptIterator.php

Lines changed: 14 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -12,54 +12,30 @@
1212

1313
namespace Fusonic\Linq\Iterator;
1414

15-
use ArrayIterator;
16-
use Iterator;
15+
use Fusonic\Linq\Helper\Set;
16+
use Traversable;
1717

18-
class ExceptIterator implements Iterator
18+
final class ExceptIterator implements \IteratorAggregate
1919
{
2020
private $first;
2121
private $second;
22-
private $result;
2322

24-
public function __construct(Iterator $first, Iterator $second)
23+
public function __construct(Traversable $first, Traversable $second)
2524
{
2625
$this->first = $first;
2726
$this->second = $second;
2827
}
2928

30-
public function current()
29+
public function getIterator()
3130
{
32-
return $this->result->current();
33-
}
34-
35-
public function next()
36-
{
37-
$this->result->next();
38-
}
39-
40-
public function key()
41-
{
42-
return $this->result->key();
43-
}
44-
45-
public function valid()
46-
{
47-
return $this->result->valid();
48-
}
49-
50-
public function rewind()
51-
{
52-
if ($this->result === null) {
53-
$this->getResult();
31+
$set = new Set();
32+
foreach($this->second as $second) {
33+
$set->add($second);
34+
}
35+
foreach($this->first as $first) {
36+
if(!$set->contains($first)) {
37+
yield $first;
38+
}
5439
}
55-
56-
$this->result->rewind();
57-
}
58-
59-
private function getResult()
60-
{
61-
$firstArray = iterator_to_array($this->first);
62-
$secondArray = iterator_to_array($this->second);
63-
$this->result = new ArrayIterator(array_diff($firstArray, $secondArray));
6440
}
65-
}
41+
}

0 commit comments

Comments
 (0)