Completed
Push — master ( 547e17...d8178d )
by Siro Díaz
01:37
created

CircularLinkedList::offsetExists()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 7
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 5
nc 2
nop 1
1
<?php
2
/**
3
 * DataStructures for PHP
4
 *
5
 * @link      https://github.com/SiroDiaz/DataStructures
6
 * @copyright Copyright (c) 2017 Siro Díaz Palazón
7
 * @license   https://github.com/SiroDiaz/DataStructures/blob/master/README.md (MIT License)
8
 */
9
namespace DataStructures\Lists;
10
11
use DataStructures\Lists\Traits\{CountTrait, ArrayAccessTrait};
12
use DataStructures\Lists\Nodes\SimpleLinkedListNode as Node;
13
use DataStructures\Lists\Interfaces\ListInterface;
14
use OutOfBoundsException;
15
16
/**
17
 * CircularLinkedList
18
 *
19
 * CircularLinkedList is a single and circular linked list that has
20
 * a pointer to the next node and also and last node points to head.
21
 *
22
 * @author Siro Diaz Palazon <[email protected]>
23
 */
24
class CircularLinkedList implements ListInterface {
25
    use CountTrait, ArrayAccessTrait;
26
    private $head;
27
    private $tail;
28
    private $size;
29
    private $current;
30
    private $position;
31
32 View Code Duplication
    public function __construct() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
33
        $this->head = null;
34
        $this->tail = &$this->head;
35
        $this->size = 0;
36
        $this->position = 0;
37
        $this->current = &$this->head;
38
    }
39
40
    /**
41
     * Inserts data in the specified position.
42
     *
43
     * @param integer $index the position.
44
     * @param mixed $data the data to store.
45
     */
46 View Code Duplication
    public function insert($index, $data) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
47
        if($index < 0) {
48
            throw new OutOfBoundsException();
49
        }
50
51
        if($index === 0) {
52
            $this->insertBeginning($data);
53
        } else if($index >= $this->size) {
54
            $this->insertEnd($data);
55
        } else if($index > 0 && $index < $this->size) {
56
            $this->insertAt($index, $data);
57
        }
58
        
59
        $this->size++;
60
    }
61
62
    /**
63
     * Inserts at the beginning of the list.
64
     *
65
     * @param mixed $data
66
     */
67
    private function insertBeginning($data) {
68
        $newNode = new Node($data);
69 View Code Duplication
        if($this->head === null) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
70
            $newNode->next = &$this->head;
71
            $this->head = &$newNode;
72
            $this->tail = &$newNode;
73
        } else {
74
            $this->tail->next = &$newNode;
75
            $newNode->next = &$this->head;
76
            $this->head = &$newNode;
77
        }
78
    }
79
80
    /**
81
     * Add a new node in the specified index.
82
     *
83
     * @param integer $index the position.
0 ignored issues
show
Bug introduced by
There is no parameter named $index. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
84
     * @param mixed $data the data to be stored.
85
     */
86
    private function insertEnd($data) {
87
        $newNode = new Node($data);
88
        $this->tail->next = &$newNode;
89
        $newNode->next = &$this->head;
90
        $this->tail = &$newNode;
91
    }
92
93
    /**
94
     * Add a new node in the specified index.
95
     *
96
     * @param integer $index the position.
97
     * @param mixed $data the data to be stored.
98
     */
99
    private function insertAt($index, $data) {
100
        $newNode = new Node($data);
101
        $current = $this->head;
102
        $prev = null;
103
        $i = 0;
104
        while($i < $index) {
105
            $prev = $current;
106
            $current = $current->next;
107
            $i++;
108
        }
109
        
110
        $prev->next = &$newNode;
111
        $newNode->next = &$current;
112
    }
113
114
    /**
115
     * Adds at the end of the list new node containing
116
     * the data to be stored.
117
     *
118
     * @param mixed $data The data
119
     */
120
    public function push($data) {
121
        $this->insert($this->size, $data);
122
    }
123
124
    /**
125
     * Adds at the beginning a node in the list.
126
     *
127
     * @param mixed $data
128
     * @return mixed the data stored.
129
     */
130
    public function unshift($data) {
131
        $this->insert(0, $data);
132
    }
133
134
    /**
135
     * Returns the last node data with O(1).
136
     *
137
     * @return mixed null if the list is empty.
138
     */
139
    public function getLast() {
140
        if($this->head === null) {
141
            return null;
142
        }
143
144
        return $this->tail->data;
145
    }
146
147
    /**
148
     * Returns the last node with O(1).
149
     *
150
     * @return mixed null if the list is empty.
151
     */
152
    protected function searchLast() {
153
        if($this->head === null) {
154
            return null;
155
        }
156
157
        return $this->tail;
158
    }
159
    
160
    /**
161
     * Returns the data stored in the given position.
162
     * If index is 0 or size - 1 the method is O(1) else O(n).
163
     *
164
     * @param integer $index the position.
165
     * @throws OutOfBoundsException if it is out of limits (< 0 or > size - 1)
166
     * @return mixed the data stored in $index node.
167
     */
168 View Code Duplication
    public function get($index) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
169
        if($index < 0 || $index > $this->size - 1) {
170
            throw new OutOfBoundsException();
171
        }
172
173
        if($index === 0) {
174
            return $this->head->data;
175
        }
176
177
        if($index === $this->size - 1) {
178
            return $this->getLast();
179
        }
180
181
        $i = 0;
182
        $current = $this->head;
183
        while($i < $index) {
184
            $current = $current->next;
185
            $i++;
186
        }
187
188
        return $current->data;
189
    }
190
191
    /**
192
     * Returns the node stored in the given position.
193
     * If index is 0 or (size - 1) the method is O(1) else O(n).
194
     *
195
     * @param integer $index the position.
196
     * @throws OutOfBoundsException if it is out of limits (< 0 or > size - 1)
197
     * @return DataStructures\Lists\Nodes\SimpleLinkedListNode|null the node stored in $index.
198
     */
199 View Code Duplication
    protected function search($index) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
200
        if($index < 0 || $index > $this->size - 1) {
201
            throw new OutOfBoundsException();
202
        }
203
204
        if($index === 0) {
205
            return $this->head;
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->head; of type null|DataStructures\List...es\SimpleLinkedListNode adds the type DataStructures\Lists\Nodes\SimpleLinkedListNode to the return on line 205 which is incompatible with the return type documented by DataStructures\Lists\CircularLinkedList::search of type DataStructures\Lists\Dat...mpleLinkedListNode|null.
Loading history...
206
        }
207
208
        if($index === $this->size - 1) {
209
            return $this->getLast();
210
        }
211
212
        $i = 0;
213
        $current = $this->head;
214
        while($i < $index) {
215
            $current = $current->next;
216
            $i++;
217
        }
218
219
        return $current;
220
    }
221
222
    /**
223
     * Generator for retrieve all nodes stored.
224
     * 
225
     * @return null if the head is null (or list is empty)
226
     */
227 View Code Duplication
    public function getAll() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
228
        if($this->head === null) {
229
            return;
230
        }
231
        
232
        if($this->head->next === $this->tail) {
233
            yield $this->head->data;
234
        } else {
235
            $current = $this->head;
236
            $i = 0;
237
            while($i < $this->size) {
238
                yield $current->data;
239
                $current = $current->next;
240
                $i++;
241
            }
242
        }
243
    }
244
    
245
    /**
246
     * Delete a node in the given position and returns it back.
247
     *
248
     * @param integer $index the position.
249
     * @throws OutOfBoundsException if index is negative
250
     *  or is greater than the size of the list.
251
     */
252 View Code Duplication
    public function delete($index) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
253
        if($index < 0 || ($index > 0 && $index > $this->size - 1)) {
254
            throw new OutOfBoundsException();
255
        }
256
257
        // if the list is empty
258
        if($this->head === null) {
259
            return null;
260
        }
261
        
262
        // if only there is an element
263
        if($this->head->next === $this->head) {
264
            $temp = $this->head;
265
            $this->head = null;
266
            $this->size--;
267
268
            return $temp->data;
269
        }
270
271
        if($index === 0) {
272
            return $this->deleteBeginning();
273
        } else if($index === $this->size - 1) {
274
            return $this->deleteEnd();
275
        } else {
276
            return $this->deleteAt($index);
277
        }
278
    }
279
280
    /**
281
     * Deletes at the beginnig of the list and returns the data stored.
282
     *
283
     * @return mixed the data stored in the node.
284
     */
285 View Code Duplication
    private function deleteBeginning() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
286
        $temp = $this->head;
287
        $this->head = &$this->head->next;
288
        $this->tail->next = &$this->head;
289
        $this->size--;
290
291
        return $temp->data;
292
    }
293
294
    /**
295
     * Deletes at the specified position and returns the data stored.
296
     *
297
     * @param integer $index the position.
298
     * @return mixed the data stored in the node.
299
     */
300 View Code Duplication
    private function deleteAt($index) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
301
        $i = 0;
302
        $prev = $this->head;
303
        $current = $this->head;
304
        
305
        while($i < $index) {
306
            $prev = $current;
307
            $current = $current->next;
308
            $i++;
309
        }
310
311
        $temp = $current;
312
        $prev->next = &$current->next;
313
        $current = null;
0 ignored issues
show
Unused Code introduced by
$current is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
314
        $this->size--;
315
316
        return $temp->data;
317
    }
318
319
    /**
320
     * Deletes at the end of the list and returns the data stored.
321
     *
322
     * @return mixed the data stored in the node.
323
     */
324 View Code Duplication
    private function deleteEnd() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
325
        $prev = $this->head;
326
        $current = $this->head;
327
        
328
        while($current !== $this->tail) {
329
            $prev = $current;
330
            $current = $current->next;
331
        }
332
        
333
        $temp = $current;
334
        $prev->next = &$this->head;
335
        $this->tail = &$prev;
336
        $current = null;
0 ignored issues
show
Unused Code introduced by
$current is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
337
338
        $this->size--;
339
340
        return $temp->data;
341
    }
342
343
    /**
344
     * Deletes the first node of the list and returns it.
345
     *
346
     * @return mixed the data.
347
     */
348
    public function shift() {
349
        return $this->delete(0);
350
    }
351
352
    /**
353
     * Removes and returns the last node in the list.
354
     *
355
     * @return mixed data in node.
356
     */
357
    public function pop() {
358
        return $this->delete($this->size - 1);
359
    }
360
361
    /**
362
     * Removes all nodes of the list. It removes from the beginning.
363
     */
364
    public function clear() {
365
        while($this->head !== null) {
366
            $this->shift();
367
        }
368
    }
369
370
    /**
371
     * Converts/exports the list content into array type.
372
     *
373
     * @return array data stored in all nodes.
374
     */
375
    public function toArray() : array {
376
        $arr = [];
377
        foreach($this->getAll() as $node) {
378
            $arr[] = $node;
379
        }
380
381
        return $arr;
382
    }
383
384
    /**
385
     * Reset the cursor position.
386
     */
387
    public function rewind() {
388
        $this->position = 0;
389
        $this->current = &$this->head;
390
    }
391
392
    /**
393
     * Returns the current node data.
394
     *
395
     * @return mixed
396
     */
397
    public function current() {
398
        return $this->current->data;
399
    }
400
401
    /**
402
     * Key or index that indicates the cursor position.
403
     *
404
     * @return integer The current position.
405
     */
406
    public function key() {
407
        return $this->position;
408
    }
409
410
    /**
411
     * Move the cursor to the next node and increments the
412
     * position counter.
413
     */
414
    public function next() {
415
        ++$this->position;
416
        $this->current = $this->current->next;
417
    }
418
419
    /**
420
     * Returns if the current pointer position is valid.
421
     *
422
     * @return boolean true if pointer is not last, else false.
423
     */
424
    public function valid() {
425
        return $this->position < $this->size;
426
    }
427
}