Completed
Push — master ( da3ca6...f77e5d )
by Siro Díaz
01:51
created

CircularLinkedList   B

Complexity

Total Complexity 53

Size/Duplication

Total Lines 375
Duplicated Lines 34.93 %

Coupling/Cohesion

Components 1
Dependencies 3

Importance

Changes 0
Metric Value
wmc 53
lcom 1
cbo 3
dl 131
loc 375
rs 7.4757
c 0
b 0
f 0

22 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 7 7 1
A insertBeginning() 0 12 2
A insertEnd() 6 6 1
A insertAt() 14 14 2
A getLast() 0 5 2
A searchLast() 0 7 2
A get() 8 8 2
B search() 0 22 6
B contains() 0 22 5
A indexOf() 19 19 4
A lastIndexOf() 19 19 4
B remove() 11 29 5
A getAll() 17 17 4
A deleteBeginning() 14 14 2
A deleteAt() 0 15 2
A deleteEnd() 16 16 2
A clear() 0 5 2
A rewind() 0 4 1
A current() 0 3 1
A key() 0 3 1
A next() 0 4 1
A valid() 0 3 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like CircularLinkedList often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use CircularLinkedList, and based on these observations, apply Extract Interface, too.

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;
13
use DataStructures\Lists\ListAbstract;
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 extends ListAbstract {
25
    use ArrayAccessTrait;
26
    protected $head;
27
    private $tail;
28
    private $current;
29
    private $position;
30
31 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...
32
        $this->head = null;
33
        $this->tail = &$this->head;
34
        $this->size = 0;
35
        $this->position = 0;
36
        $this->current = &$this->head;
37
    }
38
39
    
40
    /**
41
     * Inserts at the beginning of the list.
42
     *
43
     * @param mixed $data
44
     */
45
    protected function insertBeginning($data) {
46
        $newNode = new SimpleLinkedListNode($data);
47
        if($this->head === null) {
48
            $newNode->next = &$this->head;
49
            $this->head = &$newNode;
50
            $this->tail = &$newNode;
51
        } else {
52
            $this->tail->next = &$newNode;
53
            $newNode->next = $this->head;
54
            $this->head = &$newNode;
55
        }
56
    }
57
58
    /**
59
     * Add a new node in the specified index.
60
     *
61
     * @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...
62
     * @param mixed $data the data to be stored.
63
     */
64 View Code Duplication
    protected function insertEnd($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...
65
        $newNode = new SimpleLinkedListNode($data);
66
        $this->tail->next = &$newNode;
67
        $newNode->next = &$this->head;
68
        $this->tail = &$newNode;
69
    }
70
71
    /**
72
     * Add a new node in the specified index.
73
     *
74
     * @param integer $index the position.
75
     * @param mixed $data the data to be stored.
76
     */
77 View Code Duplication
    protected function insertAt($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...
78
        $newNode = new SimpleLinkedListNode($data);
79
        $current = $this->head;
80
        $prev = null;
81
        $i = 0;
82
        while($i < $index) {
83
            $prev = $current;
84
            $current = $current->next;
85
            $i++;
86
        }
87
        
88
        $prev->next = &$newNode;
89
        $newNode->next = &$current;
90
    }
91
92
    /**
93
     * Returns the last node data with O(1).
94
     *
95
     * @return mixed null if the list is empty.
96
     */
97
    public function getLast() {
98
        $node = $this->searchLast();
99
100
        return $node !== null ? $node->data : null;
101
    }
102
103
    /**
104
     * Returns the last node with O(1).
105
     *
106
     * @return mixed null if the list is empty.
107
     */
108
    protected function searchLast() {
109
        if($this->head === null) {
110
            return null;
111
        }
112
113
        return $this->tail;
114
    }
115
    
116
    /**
117
     * Returns the data stored in the given position.
118
     * If index is 0 or size - 1 the method is O(1) else O(n).
119
     *
120
     * @param integer $index the position.
121
     * @throws OutOfBoundsException if it is out of limits (< 0 or > size - 1)
122
     * @return mixed the data stored in $index node.
123
     */
124 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...
125
        $node = $this->search($index);
126
        if($node === null) {
127
            return null;
128
        }
129
130
        return $node->data;
131
    }
132
133
    /**
134
     * Returns the node stored in the given position.
135
     * If index is 0 or (size - 1) the method is O(1) else O(n).
136
     *
137
     * @param integer $index the position.
138
     * @throws OutOfBoundsException if it is out of limits (< 0 or > size - 1)
139
     * @return DataStructures\Lists\Nodes\SimpleLinkedListNode the node stored in $index.
140
     */
141
    protected function search($index) {
142
        if($index < 0 || $index > $this->size - 1) {
143
            throw new OutOfBoundsException();
144
        }
145
146
        if($index === 0) {
147
            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 147 which is incompatible with the return type documented by DataStructures\Lists\CircularLinkedList::search of type DataStructures\Lists\Dat...es\SimpleLinkedListNode.
Loading history...
148
        }
149
150
        if($index === $this->size - 1) {
151
            return $this->searchLast();
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->searchLast(); of type null|DataStructures\List...es\SimpleLinkedListNode adds the type DataStructures\Lists\Nodes\SimpleLinkedListNode to the return on line 151 which is incompatible with the return type documented by DataStructures\Lists\CircularLinkedList::search of type DataStructures\Lists\Dat...es\SimpleLinkedListNode.
Loading history...
152
        }
153
154
        $i = 0;
155
        $current = $this->head;
156
        while($i < $index) {
157
            $current = $current->next;
158
            $i++;
159
        }
160
161
        return $current;
162
    }
163
164
    /**
165
     * {@inheritDoc}
166
     */
167
    public function contains($data) : bool {
168
        if($this->size === 0) {
169
            return false;
170
        }
171
172
        $current = $this->head->next;
173
        $prev = $this->head;
174
        while($current !== $this->head) {
175
            if($prev->data === $data) {
176
                return true;
177
            }
178
            
179
            $prev = $current;
180
            $current = $current->next;
181
        }
182
183
        if($prev->data === $data) {
184
            return true;
185
        }
186
187
        return false;
188
    }
189
190
    /**
191
     * {@inheritDoc}
192
     */
193 View Code Duplication
    public function indexOf($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...
194
        if($this->head === null) {
195
            return false;
196
        }
197
        
198
        $current = $this->head;
199
        $i = 0;
200
        
201
        while($i < $this->size) {
202
            if($current->data === $data) {
203
                return $i;
204
            }
205
206
            $current = $current->next;
207
            $i++;
208
        }
209
210
        return false;
211
    }
212
213
    /**
214
     * {@inheritDoc}
215
     */
216 View Code Duplication
    public function lastIndexOf($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...
217
        if($this->head === null) {
218
            return false;
219
        }
220
        
221
        $current = $this->head;
222
        $i = 0;
223
        $pos = false;
224
        while($i < $this->size) {
225
            if($current->data === $data) {
226
                $pos = $i;
227
            }
228
229
            $current = $current->next;
230
            $i++;
231
        }
232
        
233
        return $pos;
234
    }
235
236
    /**
237
     * {@inheritDoc}
238
     */
239
    public function remove($data) {
240
        $current = $this->head;
241
        $prev = $this->tail;
242
        $i = 0;
243
        
244
        if($this->head === null) {
245
            return null;
246
        }
247
248
        if($this->head->data === $data) {
249
            $this->head = &$this->head->next;
250
            $this->tail->next = &$this->head;
251
            $this->size--;
252
            return $current->data;
253
        }
254 View Code Duplication
        while($i < $this->size) {
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...
255
            if($prev->data === $data) {
256
                $prev->next = &$current->next;
257
                $this->size--;
258
259
                return $current->data;
260
            }
261
262
            $prev = $current;
263
            $current = $current->next;
264
        }
265
266
        return null;
267
    }
268
269
    /**
270
     * Generator for retrieve all nodes stored.
271
     * 
272
     * @return null if the head is null (or list is empty)
273
     */
274 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...
275
        if($this->head === null) {
276
            return;
277
        }
278
        
279
        if($this->head->next === $this->tail) {
280
            yield $this->head->data;
281
        } else {
282
            $current = $this->head;
283
            $i = 0;
284
            while($i < $this->size) {
285
                yield $current->data;
286
                $current = $current->next;
287
                $i++;
288
            }
289
        }
290
    }
291
292
    /**
293
     * {@inheritDoc}
294
     */
295 View Code Duplication
    protected 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...
296
        // if only there is an element
297
        if($this->head->next === $this->head) {
298
            $temp = $this->head;
299
            $this->head = null;
300
            return $temp->data;
301
        }
302
        
303
        $temp = $this->head;
304
        $this->head = &$this->head->next;
305
        $this->tail->next = &$this->head;
306
307
        return $temp->data;
308
    }
309
310
    /**
311
     * {@inheritDoc}
312
     */
313
    protected function deleteAt($index) {
314
        $i = 0;
315
        $prev = $this->head;
316
        $current = $this->head;
317
        
318
        while($i < $index) {
319
            $prev = $current;
320
            $current = $current->next;
321
            $i++;
322
        }
323
324
        $prev->next = &$current->next;
325
326
        return $current->data;
327
    }
328
329
    /**
330
     * {@inheritDoc}
331
     */
332 View Code Duplication
    protected 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...
333
        $prev = $this->head;
334
        $current = $this->head;
335
        
336
        while($current !== $this->tail) {
337
            $prev = $current;
338
            $current = $current->next;
339
        }
340
        
341
        $temp = $current;
342
        $prev->next = &$this->head;
343
        $this->tail = &$prev;
344
        $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...
345
346
        return $temp->data;
347
    }
348
349
    public function clear() {
350
        while($this->head !== null) {
351
            $this->shift();
352
        }
353
    }
354
355
    /**
356
     * Reset the cursor position.
357
     */
358
    public function rewind() {
359
        $this->position = 0;
360
        $this->current = &$this->head;
361
    }
362
363
    /**
364
     * Returns the current node data.
365
     *
366
     * @return mixed
367
     */
368
    public function current() {
369
        return $this->current->data;
370
    }
371
372
    /**
373
     * Key or index that indicates the cursor position.
374
     *
375
     * @return integer The current position.
376
     */
377
    public function key() {
378
        return $this->position;
379
    }
380
381
    /**
382
     * Move the cursor to the next node and increments the
383
     * position counter.
384
     */
385
    public function next() {
386
        ++$this->position;
387
        $this->current = $this->current->next;
388
    }
389
390
    /**
391
     * Returns if the current pointer position is valid.
392
     *
393
     * @return boolean true if pointer is not last, else false.
394
     */
395
    public function valid() {
396
        return $this->position < $this->size;
397
    }
398
}