Completed
Push — master ( 37a545...2ac5c4 )
by Edward
04:29
created

SliceElementMatcher   A

Complexity

Total Complexity 21

Size/Duplication

Total Lines 72
Duplicated Lines 0 %

Test Coverage

Coverage 0%

Importance

Changes 1
Bugs 0 Features 1
Metric Value
eloc 33
dl 0
loc 72
ccs 0
cts 35
cp 0
rs 10
c 1
b 0
f 1
wmc 21

6 Methods

Rating   Name   Duplication   Size   Complexity  
A isOnStep() 0 3 2
A match() 0 9 4
A __construct() 0 8 1
A detectStart() 0 11 4
A isInRange() 0 5 4
A detectEnd() 0 13 6
1
<?php
2
declare(strict_types=1);
3
4
namespace Remorhaz\JSON\Path\Runtime\Matcher;
5
6
use function is_int;
7
use function max;
8
9
final class SliceElementMatcher implements ChildMatcherInterface
10
{
11
12
    private $count;
13
14
    private $start;
15
16
    private $end;
17
18
    private $step;
19
20
    private $isReverse;
21
22
    public function __construct(int $count, ?int $start, ?int $end, ?int $step)
23
    {
24
        $this->count = $count;
25
        $this->step = $step ?? 1;
26
        $this->isReverse = $step < 0;
27
28
        $this->start = $start;
29
        $this->end = $end;
30
    }
31
32
    public function match($address): bool
33
    {
34
        if (0 == $this->step || !is_int($address)) {
35
            return false;
36
        }
37
        $start = $this->detectStart($this->count);
38
        $end = $this->detectEnd($this->count);
39
40
        return $this->isInRange($address, $start, $end) && $this->isOnStep($address, $start);
41
    }
42
43
    private function detectStart(int $count): int
44
    {
45
        $start = $this->start;
46
        if (!isset($start)) {
47
            $start = $this->isReverse ? -1 : 0;
48
        }
49
        if ($start < 0) {
50
            $start = max($start + $count, 0);
51
        }
52
53
        return $start;
54
    }
55
56
    private function detectEnd(int $count): int
57
    {
58
        $end = $this->end;
59
        if (!isset($end)) {
60
            $end = $this->isReverse ? -$count - 1 : $count;
61
        }
62
        if ($end > $count) {
63
            return $count;
64
        }
65
66
        return $end < 0
67
            ? max($end + $count, $this->isReverse ? -1 : 0)
68
            : $end;
69
    }
70
71
    private function isInRange(int $address, int $start, int $end): bool
72
    {
73
        return $this->isReverse
74
            ? $address <= $start && $address > $end
75
            : $address >= $start && $address < $end;
76
    }
77
78
    private function isOnStep(int $address, int $start): bool
79
    {
80
        return 0 == ($this->isReverse ? $start - $address : $address - $start) % $this->step;
81
    }
82
}
83