1 | <?php |
||
2 | |||
3 | declare(strict_types=1); |
||
4 | |||
5 | namespace MartanLV\Koki; |
||
6 | |||
7 | /** |
||
8 | * Augmented tree |
||
9 | * Class StaticTree. |
||
10 | * |
||
11 | * @author yourname |
||
12 | */ |
||
13 | class Tree extends Node |
||
14 | { |
||
15 | public $root; |
||
16 | |||
17 | /** |
||
18 | * undocumented function. |
||
19 | * |
||
20 | * @param $intervals array of Interval |
||
21 | * |
||
22 | * @return void |
||
23 | */ |
||
24 | public function __construct(array $intervals = [], bool $preSorted = false) |
||
25 | { |
||
26 | !$preSorted && usort($intervals, function (IntervalInterface $i0, IntervalInterface $i) { |
||
27 | return $i0->getStart() <=> $i->getStart(); |
||
28 | }); |
||
29 | $this->root = $this->toTree($intervals); |
||
30 | } |
||
31 | |||
32 | /** |
||
33 | * An augmented tree can be built from a simple ordered tree, |
||
34 | * for example a binary search tree or self-balancing binary search tree, |
||
35 | * ordered by the 'low' values of the intervals. |
||
36 | */ |
||
37 | public function toTree(array $intervals) |
||
38 | { |
||
39 | $max = 0; |
||
40 | $len = count($intervals); |
||
41 | $mid = (int) floor($len / 2); |
||
42 | |||
43 | if (!$len) { |
||
44 | return; |
||
45 | } |
||
46 | |||
47 | array_walk($intervals, function (IntervalInterface $el) use (&$max) { |
||
48 | if ($max < $el->getEnd()) { |
||
49 | $max = $el->getEnd(); |
||
50 | } |
||
51 | }); |
||
52 | $l_intervals = array_splice($intervals, 0, $mid); |
||
53 | $r_intervals = array_splice($intervals, -$mid); |
||
54 | $interval = $intervals ? reset($intervals) : array_pop($l_intervals); |
||
55 | $interval = $interval ?? array_pop($r_intervals); |
||
56 | |||
57 | $node = new Node( |
||
58 | $interval, |
||
59 | $this->toTree($l_intervals), |
||
60 | $this->toTree($r_intervals), |
||
61 | $max |
||
62 | ); |
||
63 | |||
64 | $node->root = &$this; |
||
65 | |||
66 | return $node; |
||
67 | } |
||
68 | |||
69 | /** |
||
70 | * returns intervals that exclusively fall within range given |
||
71 | * to retrieve eather bound inclusevely, just modify parameters. |
||
72 | * |
||
73 | * @return void |
||
74 | */ |
||
75 | public function select(int $low, int $high): array |
||
76 | { |
||
77 | return $this->root ? $this->root->select($low, $high) : []; |
||
78 | } |
||
79 | |||
80 | public function selectNode(int $low, int $high): array |
||
81 | { |
||
82 | return $this->root ? $this->root->selectNode($low, $high) : []; |
||
83 | } |
||
84 | |||
85 | /** |
||
86 | * rebalance messed up tree overall. |
||
87 | */ |
||
88 | public function balance() |
||
89 | { |
||
90 | // todo |
||
91 | } |
||
92 | |||
93 | /** |
||
94 | * understandable var dump. |
||
95 | */ |
||
96 | public function __debugInfo() |
||
97 | { |
||
98 | $arr = $this->all(); |
||
99 | |||
100 | usort($arr, function (IntervalInterface $i0, IntervalInterface $i) { |
||
101 | return $i0->getStart() <=> $i->getStart(); |
||
102 | }); |
||
103 | |||
104 | return $arr; |
||
105 | } |
||
106 | |||
107 | public function yieldInterSelect(int $low, int $high) |
||
108 | { |
||
109 | return $this->root ? $this->root->yieldInterSelect($low, $high) : []; |
||
110 | } |
||
111 | |||
112 | public function interSelectNode(int $low, int $high): array |
||
113 | { |
||
114 | return $this->root ? $this->root->interSelectNode($low, $high) : []; |
||
115 | } |
||
116 | |||
117 | public function interSelect(int $low, int $high): array |
||
118 | { |
||
119 | return $this->root ? $this->root->interSelect($low, $high) : []; |
||
120 | } |
||
121 | |||
122 | public function yieldSelect(int $low, int $high) |
||
123 | { |
||
124 | return $this->root ? $this->root->yieldSelect($low, $high) : []; |
||
125 | } |
||
126 | |||
127 | /** |
||
128 | * @return void |
||
129 | */ |
||
130 | public function all(): array |
||
131 | { |
||
132 | return $this->root ? $this->root->all() : []; |
||
133 | } |
||
134 | |||
135 | /** |
||
136 | * undocumented function. |
||
137 | * |
||
138 | * @return void |
||
139 | */ |
||
140 | public function yieldAll() |
||
141 | { |
||
142 | return $this->root ? $this->root->yieldAll() : []; |
||
143 | } |
||
144 | |||
145 | public function removeRegion(int $low, int $high) |
||
146 | { |
||
147 | if (!$this->root) { |
||
148 | return []; |
||
149 | } |
||
150 | foreach ($this->interSelectNode($low, $high) as $node) { |
||
151 | $this->remove($node); |
||
152 | } |
||
153 | } |
||
154 | |||
155 | public function remove(IntervalInterface $i) |
||
156 | { |
||
157 | if (!$i->left && !$i->right) { |
||
158 | if ($i->root) { |
||
159 | $i->root = null; |
||
160 | } |
||
161 | |||
162 | return; |
||
163 | } |
||
164 | |||
165 | if ($i->left && $i->right) { |
||
166 | // todo |
||
167 | return; |
||
168 | } |
||
169 | if ($i->left) { |
||
170 | $i->interval = &$i->left->interval; |
||
171 | $i->left = null; |
||
172 | } |
||
173 | |||
174 | if ($i->right) { |
||
175 | } |
||
176 | |||
177 | if ($this->max > $i->getEnd()) { |
||
178 | if ($this->left) { |
||
179 | $this->left->add($i); |
||
180 | } else { |
||
181 | $this->left = new Node($i); |
||
182 | } |
||
183 | } else { |
||
184 | $this->max = $i->getEnd(); |
||
185 | if ($this->right) { |
||
186 | $this->right->add($i); |
||
187 | } else { |
||
188 | $this->right = new Node($i); |
||
189 | } |
||
190 | } |
||
191 | |||
192 | return; |
||
193 | if (!$this->root) { |
||
0 ignored issues
–
show
|
|||
194 | return []; |
||
195 | } |
||
196 | $this->root->remove($i); |
||
197 | } |
||
198 | |||
199 | public function add(IntervalInterface $i) |
||
200 | { |
||
201 | if (!$this->root) { |
||
202 | $this->root = new Node($i); |
||
203 | |||
204 | return; |
||
205 | } |
||
206 | $this->root->add($i); |
||
207 | } |
||
208 | } |
||
209 |
This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.
Unreachable code is most often the result of
return
,die
orexit
statements that have been added for debug purposes.In the above example, the last
return false
will never be executed, because a return statement has already been met in every possible execution path.