Issues (18)

src/Node.php (9 issues)

1
<?php
2
3
declare(strict_types=1);
4
5
namespace MartanLV\Koki;
6
7
/**
8
 * Class Node.
9
 *
10
 * @author yourname
11
 */
12
class Node
13
{
14
    public $root;
15
    /**
16
     * @var Interval
17
     */
18
    public $interval;
19
    /**
20
     * @var int
21
     */
22
    public $max;
23
    /**
24
     * @var Node
25
     */
26
    public $left;
27
    /**
28
     * @var Node
29
     */
30
    public $right;
31
32
    /**
33
     * undocumented function.
34
     *
35
     * @return void
36
     */
37
    public function __construct(IntervalInterface $interval, $left = null, $right = null, $max = 0)
38
    {
39
        $this->interval = $interval;
0 ignored issues
show
Documentation Bug introduced by
$interval is of type MartanLV\Koki\IntervalInterface, but the property $interval was declared to be of type MartanLV\Koki\Interval. Are you sure that you always receive this specific sub-class here, or does it make sense to add an instanceof check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a given class or a super-class is assigned to a property that is type hinted more strictly.

Either this assignment is in error or an instanceof check should be added for that assignment.

class Alien {}

class Dalek extends Alien {}

class Plot
{
    /** @var  Dalek */
    public $villain;
}

$alien = new Alien();
$plot = new Plot();
if ($alien instanceof Dalek) {
    $plot->villain = $alien;
}
Loading history...
40
        $this->left = $left;
41
        $this->right = $right;
42
        $this->max = $max ? $max : $interval->getEnd();
43
    }
44
45
    /**
46
     * returns intervals that fall within interval range.
47
     *
48
     * @return void
49
     */
50
    public function all(): array
51
    {
52
        return iterator_to_array($this->yieldAll(), false);
0 ignored issues
show
$this->yieldAll() of type void is incompatible with the type Traversable expected by parameter $iterator of iterator_to_array(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

52
        return iterator_to_array(/** @scrutinizer ignore-type */ $this->yieldAll(), false);
Loading history...
Bug Best Practice introduced by
The expression return iterator_to_array...his->yieldAll(), false) returns the type array which is incompatible with the documented return type void.
Loading history...
Are you sure the usage of $this->yieldAll() targeting MartanLV\Koki\Node::yieldAll() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
53
    }
54
55
    /**
56
     * undocumented function.
57
     *
58
     * @return void
59
     */
60
    public function yieldAll()
61
    {
62
        return $this->yieldSelect(-1, $this->max + 1);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->yieldSelect(-1, $this->max + 1) returns the type Generator which is incompatible with the documented return type void.
Loading history...
63
    }
64
65
    /**
66
     * returns intervals that touches a given range.
67
     *
68
     * @return void
69
     */
70
    public function interSelectNode(int $low, int $high): array
71
    {
72
        return iterator_to_array($this->yieldInterSelectNode($low, $high), false);
0 ignored issues
show
Bug Best Practice introduced by
The expression return iterator_to_array...de($low, $high), false) returns the type array which is incompatible with the documented return type void.
Loading history...
73
    }
74
75
    /**
76
     * returns intervals that touches a given range.
77
     *
78
     * @return void
79
     */
80
    public function interSelect(int $low, int $high): array
81
    {
82
        return iterator_to_array($this->yieldInterSelect($low, $high), false);
0 ignored issues
show
Bug Best Practice introduced by
The expression return iterator_to_array...ct($low, $high), false) returns the type array which is incompatible with the documented return type void.
Loading history...
83
    }
84
85
    /**
86
     * returns intervals that fall within interval range.
87
     *
88
     * @return void
89
     */
90
    public function select(int $low, int $high): array
91
    {
92
        return iterator_to_array($this->yieldSelect($low, $high), false);
0 ignored issues
show
Bug Best Practice introduced by
The expression return iterator_to_array...ct($low, $high), false) returns the type array which is incompatible with the documented return type void.
Loading history...
93
    }
94
95
    public function selectNode(int $low, int $high): array
96
    {
97
        return iterator_to_array($this->yieldSelectNode($low, $high), false);
98
    }
99
100
    /**
101
     * returns intervals that touches a given range.
102
     *
103
     * @return generator
0 ignored issues
show
The type MartanLV\Koki\generator was not found. Did you mean generator? If so, make sure to prefix the type with \.
Loading history...
104
     */
105
    public function yieldInterSelectNode(int $low, int $high)
106
    {
107
        $edgeR = $high >= $this->interval->getStart() && $high <= $this->interval->getEnd();
108
        $edgeL = $low >= $this->interval->getStart() && $low <= $this->interval->getEnd();
109
        $part = $this->interval->getStart() >= $low && $this->interval->getEnd() <= $high;
110
        $whole = $this->interval->getStart() <= $low && $this->interval->getEnd() >= $high;
111
112
        $currentNodeMatches = $edgeR || $edgeL || $part || $whole;
113
        if ($currentNodeMatches) {
114
            yield $this;
115
        }
116
117
        if ($this->right && $this->interval->getStart() <= $high) {
118
            yield from $this->right->yieldInterSelectNode($low, $high);
119
        }
120
121
        if ($this->left && $this->left->max >= $low) {
122
            yield from $this->left->yieldInterSelectNode($low, $high);
123
        }
124
    }
125
126
    /**
127
     * returns intervals that touches a given range.
128
     *
129
     * @return generator
130
     */
131
    public function yieldInterSelect(int $low, int $high)
132
    {
133
        $edgeR = $high >= $this->interval->getStart() && $high <= $this->interval->getEnd();
134
        $edgeL = $low >= $this->interval->getStart() && $low <= $this->interval->getEnd();
135
        $part = $this->interval->getStart() >= $low && $this->interval->getEnd() <= $high;
136
        $whole = $this->interval->getStart() <= $low && $this->interval->getEnd() >= $high;
137
138
        $currentNodeMatches = $edgeR || $edgeL || $part || $whole;
139
        if ($currentNodeMatches) {
140
            yield $this->interval;
141
        }
142
143
        if ($this->right && $this->interval->getStart() <= $high) {
144
            yield from $this->right->yieldInterSelect($low, $high);
145
        }
146
147
        if ($this->left && $this->left->max >= $low) {
148
            yield from $this->left->yieldInterSelect($low, $high);
149
        }
150
    }
151
152
    /**
153
     * returns intervals that fall within interval range.
154
     *
155
     * @return generator
156
     */
157
    public function yieldSelectNode(int $low, int $high)
158
    {
159
        /*
160
         * does current node matches?
161
         */
162
        if ($this->interval->getEnd() < $high && $this->interval->getStart() > $low) {
163
            yield $this;
164
        }
165
166
        /*
167
         * since the node's low value is less than the "select end" value,
168
         * we must search in the right subtree. If it exists.
169
         */
170
        if ($this->right && $this->interval->getStart() < $high) {
171
            yield from $this->right->yieldSelectNode($low, $high);
172
        }
173
        /*
174
         * If the left subtree's max exceeds the quiery's low value,
175
         * so we must search the left subtree as well.
176
         */
177
        if ($this->left && $this->left->max > $low) {
178
            yield from $this->left->yieldSelectNode($low, $high);
179
        }
180
    }
181
182
    /**
183
     * returns intervals that fall within interval range.
184
     *
185
     * @return generator
186
     */
187
    public function yieldSelect(int $low, int $high)
188
    {
189
        /*
190
         * does current node matches?
191
         */
192
        if ($this->interval->getEnd() < $high && $this->interval->getStart() > $low) {
193
            yield $this->interval;
194
        }
195
196
        /*
197
         * since the node's low value is less than the "select end" value,
198
         * we must search in the right subtree. If it exists.
199
         */
200
        if ($this->right && $this->interval->getStart() < $high) {
201
            yield from $this->right->yieldSelect($low, $high);
202
        }
203
        /*
204
         * If the left subtree's max exceeds the quiery's low value,
205
         * so we must search the left subtree as well.
206
         */
207
        if ($this->left && $this->left->max > $low) {
208
            yield from $this->left->yieldSelect($low, $high);
209
        }
210
    }
211
212
    public function remove(IntervalInterface $i)
213
    {
214
        if ($this->max > $i->getEnd()) {
215
            if ($this->left) {
216
                $this->left->add($i);
217
            } else {
218
                $this->left = new self($i);
219
            }
220
        } else {
221
            $this->max = $i->getEnd();
222
            if ($this->right) {
223
                $this->right->add($i);
224
            } else {
225
                $this->right = new self($i);
226
            }
227
        }
228
    }
229
230
    public function add(IntervalInterface $i)
231
    {
232
        if ($this->max > $i->getEnd()) {
233
            if ($this->left) {
234
                $this->left->add($i);
235
            } else {
236
                $this->left = new self($i);
237
                $this->left->root = &$this;
238
            }
239
        } else {
240
            $this->max = $i->getEnd();
241
            if ($this->right) {
242
                $this->right->add($i);
243
            } else {
244
                $this->right = new self($i);
245
                $this->right->root = &$this;
246
            }
247
        }
248
    }
249
}
250