Completed
Push — master ( 74c6f1...c429ae )
by Vincent
03:23
created

SortStream::buildData()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 14
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 10
c 0
b 0
f 0
nc 4
nop 1
dl 0
loc 14
rs 9.9332
1
<?php
2
3
namespace Bdf\Collection\Stream;
4
5
use Bdf\Collection\Util\Optional;
6
use Bdf\Collection\Util\OptionalInterface;
7
use Iterator;
8
use function asort;
9
use function current;
10
use function key;
11
use function next;
12
use function reset;
13
use function sort;
14
use function uasort;
15
use function usort;
16
17
/**
18
 * Implementation of StreamInterface::sort() return value
19
 *
20
 * @internal
21
 */
22
final class SortStream implements Iterator, StreamInterface
23
{
24
    use StreamTrait;
25
26
    /**
27
     * @var StreamInterface
28
     */
29
    private $stream;
30
31
    /**
32
     * @var callable
33
     */
34
    private $comparator;
35
36
    /**
37
     * @var bool
38
     */
39
    private $preserveKeys;
40
41
    /**
42
     * @var array|null
43
     */
44
    private $data = null;
45
46
47
    /**
48
     * SortStream constructor.
49
     *
50
     * @param StreamInterface $stream
51
     * @param callable $comparator
52
     * @param bool $preserveKeys
53
     */
54
    public function __construct(StreamInterface $stream, callable $comparator = null, bool $preserveKeys = true)
55
    {
56
        $this->stream = $stream;
57
        $this->comparator = $comparator;
58
        $this->preserveKeys = $preserveKeys;
59
    }
60
61
    /**
62
     * {@inheritdoc}
63
     */
64
    public function toArray(bool $preserveKeys = true): array
65
    {
66
        if ($this->data === null) {
67
            $this->buildData($preserveKeys && $this->preserveKeys);
68
        }
69
70
        return $this->data;
71
    }
72
73
    /**
74
     * {@inheritdoc}
75
     */
76
    public function forEach(callable $consumer): void
77
    {
78
        foreach ($this->toArray() as $k => $v) {
79
            $consumer($v, $k);
80
        }
81
    }
82
83
    /**
84
     * {@inheritdoc}
85
     */
86
    public function first(): OptionalInterface
87
    {
88
        $empty = true;
89
        $min = null;
90
91
        foreach ($this->stream as $value) {
92
            if ($empty) {
93
                $min = $value;
94
                $empty = false;
95
            } else {
96
                if ($this->comparator === null) {
97
                    if ($value < $min) {
98
                        $min = $value;
99
                    }
100
                } elseif (($this->comparator)($value, $min) < 0) {
101
                    $min = $value;
102
                }
103
            }
104
        }
105
106
        return Optional::nullable($min);
107
    }
108
109
    /**
110
     * {@inheritdoc}
111
     */
112
    public function current()
113
    {
114
        if ($this->data === null) {
115
            $this->buildData();
116
        }
117
118
        return current($this->data);
119
    }
120
121
    /**
122
     * {@inheritdoc}
123
     */
124
    public function next()
125
    {
126
        if ($this->data === null) {
127
            $this->buildData();
128
        }
129
130
        next($this->data);
131
    }
132
133
    /**
134
     * {@inheritdoc}
135
     */
136
    public function key()
137
    {
138
        if ($this->data === null) {
139
            $this->buildData();
140
        }
141
142
        return key($this->data);
143
    }
144
145
    /**
146
     * {@inheritdoc}
147
     */
148
    public function valid()
149
    {
150
        if ($this->data === null) {
151
            $this->buildData();
152
        }
153
154
        return key($this->data) !== null;
155
    }
156
157
    /**
158
     * {@inheritdoc}
159
     */
160
    public function rewind()
161
    {
162
        if ($this->data === null) {
163
            $this->buildData();
164
        }
165
166
        reset($this->data);
167
    }
168
169
    /**
170
     * Build the inner sorted data array
171
     *
172
     * @param bool $preserveKeys
173
     */
174
    private function buildData(bool $preserveKeys = true): void
175
    {
176
        $this->data = $this->stream->toArray($preserveKeys);
177
178
        if ($this->comparator) {
179
            if ($preserveKeys) {
180
                uasort($this->data, $this->comparator);
181
            } else {
182
                usort($this->data, $this->comparator);
183
            }
184
        } elseif($preserveKeys) {
185
            asort($this->data);
186
        } else {
187
            sort($this->data);
188
        }
189
    }
190
}
191