Skip to content

Commit c2490e1

Browse files
Merge pull request #39 from worksolutions/fix-iterator-behavior
Support iterator state pattern
2 parents fbc8076 + c9b355f commit c2490e1

File tree

10 files changed

+948
-13
lines changed

10 files changed

+948
-13
lines changed

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"description": "Collections library for php language",
44
"minimum-stability": "dev",
55
"license": "MIT",
6-
"version": "1.1.1",
6+
"version": "1.1.2",
77
"authors": [
88
{
99
"name": "Maxim Sokolovsky",

src/WS/Utils/Collections/CollectionFactory.php

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@
55

66
namespace WS\Utils\Collections;
77

8+
use Iterator;
9+
use IteratorAggregate;
810
use RuntimeException;
11+
use WS\Utils\Collections\Exception\UnsupportedException;
912

1013
class CollectionFactory
1114
{
@@ -37,7 +40,7 @@ public static function generate(int $times, ?callable $generator = null): Collec
3740
/**
3841
* Generate collection of int numbers between $from and $to. If $to arg is absent $from - is count of numbers
3942
* @param int $from
40-
* @param int $to
43+
* @param int|null $to
4144
* @return Collection
4245
*/
4346
public static function numbers(int $from, ?int $to = null): Collection
@@ -68,8 +71,21 @@ public static function fromStrict(array $values): Collection
6871
return new ArrayStrictList($values);
6972
}
7073

74+
/**
75+
* @throws UnsupportedException
76+
*/
7177
public static function fromIterable(iterable $iterable): Collection
7278
{
79+
if (self::isStatePatternIterator($iterable)) {
80+
if ($iterable instanceof IteratorAggregate) {
81+
/** @noinspection PhpUnhandledExceptionInspection */
82+
$iterable = $iterable->getIterator();
83+
}
84+
if (!$iterable instanceof Iterator) {
85+
throw new UnsupportedException('Only Iterator interface can be applied to IteratorCollection');
86+
}
87+
return new IteratorCollection($iterable);
88+
}
7389
$list = ArrayList::of();
7490
foreach ($iterable as $item) {
7591
$list->add($item);
@@ -82,4 +98,21 @@ public static function empty(): Collection
8298
{
8399
return ArrayList::of();
84100
}
101+
102+
private static function isStatePatternIterator(iterable $iterable): bool
103+
{
104+
$i = 2;
105+
$lastItem = null;
106+
foreach ($iterable as $item) {
107+
if ($i === 0) {
108+
break;
109+
}
110+
if (is_object($item) && $item === $lastItem) {
111+
return true;
112+
}
113+
$lastItem = $item;
114+
$i--;
115+
}
116+
return false;
117+
}
85118
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?php
2+
3+
namespace WS\Utils\Collections\Exception;
4+
5+
use RuntimeException;
6+
7+
class UnsupportedException extends RuntimeException
8+
{
9+
}
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
<?php
2+
3+
namespace WS\Utils\Collections;
4+
5+
use Iterator;
6+
use WS\Utils\Collections\Exception\UnsupportedException;
7+
8+
/**
9+
* Collection which support Traversable interface
10+
*/
11+
class IteratorCollection implements Collection
12+
{
13+
14+
/**
15+
* @var Iterator
16+
*/
17+
private $iterator;
18+
19+
public function __construct(Iterator $iterator)
20+
{
21+
$this->iterator = $iterator;
22+
}
23+
24+
/**
25+
* @throws UnsupportedException
26+
* @codeCoverageIgnore
27+
*/
28+
public function add($element): bool
29+
{
30+
throw new UnsupportedException();
31+
}
32+
33+
/**
34+
* @throws UnsupportedException
35+
* @codeCoverageIgnore
36+
*/
37+
public function addAll(iterable $elements): bool
38+
{
39+
throw new UnsupportedException();
40+
}
41+
42+
/**
43+
* @throws UnsupportedException
44+
* @codeCoverageIgnore
45+
*/
46+
public function merge(Collection $collection): bool
47+
{
48+
throw new UnsupportedException();
49+
}
50+
51+
/**
52+
* @throws UnsupportedException
53+
* @codeCoverageIgnore
54+
*/
55+
public function clear(): void
56+
{
57+
throw new UnsupportedException();
58+
}
59+
60+
/**
61+
* @throws UnsupportedException
62+
* @codeCoverageIgnore
63+
*/
64+
public function remove($element): bool
65+
{
66+
throw new UnsupportedException();
67+
}
68+
69+
/**
70+
* @throws UnsupportedException
71+
* @codeCoverageIgnore
72+
*/
73+
public function contains($element): bool
74+
{
75+
throw new UnsupportedException();
76+
}
77+
78+
/**
79+
* @throws UnsupportedException
80+
* @codeCoverageIgnore
81+
*/
82+
public function equals(Collection $collection): bool
83+
{
84+
throw new UnsupportedException();
85+
}
86+
87+
public function size(): int
88+
{
89+
$this->iterator->rewind();
90+
$count = 0;
91+
while ($this->iterator->valid()) {
92+
$this->iterator->next();
93+
$count++;
94+
}
95+
96+
return $count;
97+
}
98+
99+
/**
100+
* @codeCoverageIgnore
101+
* @return bool
102+
*/
103+
public function isEmpty(): bool
104+
{
105+
return $this->size() === 0;
106+
}
107+
108+
public function stream(): Stream
109+
{
110+
return new IteratorStream($this);
111+
}
112+
113+
/**
114+
* @codeCoverageIgnore
115+
* @return array
116+
*/
117+
public function toArray(): array
118+
{
119+
throw new UnsupportedException();
120+
}
121+
122+
/**
123+
* @codeCoverageIgnore
124+
* @return Collection
125+
*/
126+
public function copy(): Collection
127+
{
128+
throw new UnsupportedException();
129+
}
130+
131+
public function getIterator()
132+
{
133+
return $this->iterator;
134+
}
135+
}

0 commit comments

Comments
 (0)