PushbackIterator::buildChunk()   C
last analyzed

Complexity

Conditions 7
Paths 16

Size

Total Lines 26
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 19
CRAP Score 7

Importance

Changes 0
Metric Value
dl 0
loc 26
ccs 19
cts 19
cp 1
rs 6.7272
c 0
b 0
f 0
cc 7
eloc 16
nc 16
nop 0
crap 7
1
<?php
2
/**
3
 * Async sockets
4
 *
5
 * @copyright Copyright (c) 2015-2017, Efimov Evgenij <[email protected]>
6
 *
7
 * This source file is subject to the MIT license that is bundled
8
 * with this source code in the file LICENSE.
9
 */
10
11
namespace AsyncSockets\RequestExecutor\Pipeline;
12
13
/**
14
 * Class PushbackIterator
15
 */
16
class PushbackIterator implements \Iterator
17
{
18
    /**
19
     * Nested iterator
20
     *
21
     * @var \Iterator
22
     */
23
    private $nestedIterator;
24
25
    /**
26
     * Unread item from previous iteration
27
     *
28
     * @var string[]
29
     */
30
    private $unreadItems;
31
32
    /**
33
     * Result of previous iteration
34
     *
35
     * @var string
36
     */
37
    private $lastIterationResult;
38
39
    /**
40
     * String length to return from this iterator
41
     *
42
     * @var int
43
     */
44
    private $chunkSize;
45
46
    /**
47
     * Iteration key
48
     *
49
     * @var int
50
     */
51
    private $key;
52
53
    /**
54
     * Length of last result push back
55
     *
56
     * @var int
57
     */
58
    private $backLength;
59
60
    /**
61
     * PushbackIterator constructor.
62
     *
63
     * @param \Iterator $nestedIterator Nested iterator
64
     * @param int       $chunkSize      Max length of string to return
65
     */
66 39
    public function __construct(\Iterator $nestedIterator, $chunkSize)
67
    {
68 39
        $this->nestedIterator = $nestedIterator;
69 39
        $this->chunkSize      = $chunkSize;
70 39
        $this->unreadItems    = [];
71 39
    }
72
73
    /**
74
     * @inheritDoc
75
     */
76 21
    public function current()
77
    {
78 21
        return $this->lastIterationResult;
79
    }
80
81
    /**
82
     * @inheritDoc
83
     */
84 18
    public function next()
85
    {
86 18
        ++$this->key;
87
88 18
        $hasUnreadItem = $this->hasUnreadItem();
89 18
        if (!$hasUnreadItem && !$this->backLength) {
90 10
            $this->nestedIterator->next();
91 10
            if (!$this->nestedIterator->valid()) {
92 10
                $this->lastIterationResult = '';
93 10
                return;
94
            }
95 4
        }
96
97 13
        $this->lastIterationResult = $this->buildChunk();
98 13
    }
99
100
    /**
101
     * @inheritDoc
102
     */
103 5
    public function key()
104
    {
105 5
        return $this->key;
106
    }
107
108
    /**
109
     * @inheritDoc
110
     */
111 42
    public function valid()
112
    {
113 42
        return !empty($this->lastIterationResult) || $this->hasUnreadItem() || $this->nestedIterator->valid();
114
    }
115
116
    /**
117
     * @inheritDoc
118
     */
119 39
    public function rewind()
120
    {
121 39
        $this->key                 = 0;
122 39
        $this->backLength          = 0;
123 39
        $this->unreadItems         = [];
124 39
        $this->nestedIterator->rewind();
125 39
        $this->lastIterationResult = $this->buildChunk();
126 39
    }
127
128
    /**
129
     * Return given length of previously read string back into iterator
130
     *
131
     * @param int $length Length of string to return back
132
     *
133
     * @return void
134
     */
135 9
    public function unread($length)
136
    {
137 9
        if (empty($this->lastIterationResult) || $length <= 0) {
138 1
            return;
139
        }
140
141 8
        $itemLength       = strlen($this->lastIterationResult);
142 8
        $this->backLength = min($itemLength, $this->backLength + $length);
143 8
    }
144
145
    /**
146
     * Test if iterator has unread item
147
     *
148
     * @return bool
149
     */
150 43
    private function hasUnreadItem()
151
    {
152 43
        return !empty($this->unreadItems);
153
    }
154
155
    /**
156
     * Build chunk to return to user
157
     *
158
     * @return string
159
     */
160 39
    private function buildChunk()
161
    {
162 39
        $result = '';
163 39
        $this->popLastPushedBackItem();
164
165 39
        $result .= $this->hasUnreadItem() ?
166 39
            array_shift($this->unreadItems) :
167 39
            (string) $this->nestedIterator->current();
168
169 39
        while ($this->hasUnreadItem() && strlen($result) < $this->chunkSize) {
170 1
            $result .= array_shift($this->unreadItems);
171 1
        }
172
173 39
        while (strlen($result) < $this->chunkSize && $this->nestedIterator->valid()) {
174 15
            $this->nestedIterator->next();
175 15
            $result .= (string) $this->nestedIterator->current();
176 15
        }
177
178 39
        $split  = str_split($result, $this->chunkSize);
179 39
        $result = array_shift($split);
180 39
        if (!empty($split)) {
181 6
            $this->unreadItems = array_merge($split, $this->unreadItems);
0 ignored issues
show
Documentation Bug introduced by
It seems like array_merge($split, $this->unreadItems) of type array is incompatible with the declared type array<integer,string> of property $unreadItems.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
182 6
        }
183
184 39
        return $result;
185
    }
186
187
    /**
188
     * @inheritDoc
189
     */
190 3
    public function __toString()
191
    {
192 3
        return $this->valid() ? (string) $this->current() : '';
193
    }
194
195
    /**
196
     * Return an item caused by unread operation
197
     *
198
     * @return void
199
     */
200 39
    private function popLastPushedBackItem()
201
    {
202 39
        if ($this->backLength) {
203 8
            $item = substr(
204 8
                $this->lastIterationResult,
205 8
                strlen($this->lastIterationResult) - $this->backLength,
206 8
                $this->backLength
207 8
            );
208
209 8
            array_unshift($this->unreadItems, $item);
210
211 8
            $this->backLength = 0;
212 8
        }
213 39
    }
214
}
215