Range   A
last analyzed

Complexity

Total Complexity 28

Size/Duplication

Total Lines 102
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
dl 0
loc 102
ccs 46
cts 46
cp 1
rs 10
c 0
b 0
f 0
wmc 28

8 Methods

Rating   Name   Duplication   Size   Complexity  
A getLength() 0 7 2
A getEnd() 0 3 1
A combine() 0 11 5
A overlaps() 0 8 4
B __construct() 0 20 7
A __toString() 0 7 3
A normalize() 0 20 5
A getStart() 0 3 1
1
<?php declare(strict_types=1);
2
3
namespace DaveRandom\Resume;
4
5
final class Range
6
{
7
    private $start;
8
    private $end;
9
    private $normal;
10
11 35
    public function __construct(int $start, int $end = null)
12
    {
13 35
        $this->start = $start;
14 35
        $this->end = $end;
15
16 35
        if ($end < 0) {
17 1
            throw new InvalidRangeException('End cannot be negative');
18
        }
19
20 34
        $haveEnd = $end !== null;
21
22 34
        if ($haveEnd && $start > $end) {
23 1
            throw new InvalidRangeException('Start cannot be larger than end');
24
        }
25
26 33
        if ($haveEnd && $start < 0) {
27 1
            throw new InvalidRangeException('A range with a negative start cannot specify an end');
28
        }
29
30 32
        $this->normal = $start >= 0 && $haveEnd;
31
    }
32
33 14
    public function getStart(): int
34
    {
35 14
        return $this->start;
36
    }
37
38
    /**
39
     * @return int|null
40
     */
41 10
    public function getEnd()
42
    {
43 10
        return $this->end;
44
    }
45
46 9
    public function getLength(): int
47
    {
48 9
        if (!$this->normal) {
49 3
            throw new LengthNotAvailableException('Cannot retrieve length of a range that is not normalized');
50
        }
51
52 6
        return ($this->end - $this->start) + 1;
53
    }
54
55 13
    public function normalize(int $size): Range
56
    {
57 13
        if ($this->normal) {
58 8
            if ($this->start > $size) {
59 2
                throw new UnsatisfiableRangeException('Not satisfiable by a resource of the specified size');
60
            }
61
62 6
            return $this;
63
        }
64
65 6
        $end = $this->end ?? $size - 1;
66 6
        $start = $this->start < 0
67 2
            ? $end + $this->start + 1
68 6
            : $this->start;
69
70 6
        if ($start > $size) {
71 1
            throw new UnsatisfiableRangeException('Not satisfiable by a resource of the specified size');
72
        }
73
74 5
        return new self(\max($start, 0), \min($end, $size - 1));
75
    }
76
77 7
    public function overlaps(Range $other): bool
78
    {
79 7
        if (!$this->normal || !$other->normal) {
80 3
            throw new IncompatibleRangesException('Cannot test for overlap of ranges that have not been normalized');
81
        }
82
83
        // https://stackoverflow.com/a/3269471/889949
84 4
        return $this->start <= $other->end && $other->start <= $this->end;
85
    }
86
87 6
    public function combine(Range $other): self
88
    {
89 6
        if (!$this->normal || !$other->normal) {
90 3
            throw new IncompatibleRangesException('Cannot combine ranges that have not been normalized');
91
        }
92
93 3
        if (!($this->start <= $other->end && $other->start <= $this->end)) {
94 1
            throw new IncompatibleRangesException('Cannot combine non-overlapping ranges');
95
        }
96
97 2
        return new self(\min($this->start, $other->start), \max($this->end, $other->end));
98
    }
99
100 3
    public function __toString(): string
101
    {
102 3
        $suffix = $this->end !== null || $this->start >= 0
103 2
            ? '-' . $this->end
104 3
            : '';
105
106 3
        return $this->start . $suffix;
107
    }
108
}
109