Passed
Push — master ( eff209...0e7332 )
by Edward
05:02
created

RangeSet::getRanges()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 1
eloc 1
c 1
b 0
f 1
nc 1
nop 0
dl 0
loc 3
rs 10
1
<?php
2
3
namespace Remorhaz\UniLex\RegExp\FSM;
4
5
use Remorhaz\UniLex\Exception;
6
7
class RangeSet
8
{
9
10
    /**
11
     * @var Range[]
12
     */
13
    private $rangeList = [];
14
15
    public static function loadUnsafe(Range ...$rangeList): self
16
    {
17
        $rangeSet = new self();
18
        $rangeSet->rangeList = $rangeList;
19
20
        return $rangeSet;
21
    }
22
23
    /**
24
     * RangeSet constructor.
25
     *
26
     * @param Range ...$rangeList
27
     * @throws Exception
28
     */
29
    public function __construct(Range ...$rangeList)
30
    {
31
        if (!empty($rangeList)) {
32
            $this->addRange(...$rangeList);
33
        }
34
    }
35
36
    /**
37
     * @param array ...$rangeDataList
38
     * @return RangeSet
39
     * @throws Exception
40
     */
41
    public static function import(array ...$rangeDataList): self
42
    {
43
        return new self(...Range::importList(...$rangeDataList));
44
    }
45
46
    public function export(): array
47
    {
48
        $rangeDataList = [];
49
        foreach ($this->getRanges() as $range) {
50
            $rangeDataList[] = $range->export();
51
        }
52
53
        return $rangeDataList;
54
    }
55
56
    /**
57
     * @param Range ...$rangeList
58
     * @throws Exception
59
     */
60
    public function addRange(Range ...$rangeList): void
61
    {
62
        $rangeList = $this->getSortedRangeList(...$rangeList);
63
        $existingIndex = 0;
64
        $addedIndex = 0;
65
        $newRangeList = [];
66
        /** @var Range $rangeBuffer */
67
        $rangeBuffer = null;
68
        while (true) {
69
            $existingRange = $this->rangeList[$existingIndex] ?? null;
70
            $addedRange = $rangeList[$addedIndex] ?? null;
71
72
            if (isset($existingRange)) {
73
                if (isset($addedRange) && $existingRange->getStart() > $addedRange->getStart()) {
74
                    $pickedRange = $addedRange;
75
                    $addedIndex++;
76
                } else {
77
                    $pickedRange = $existingRange;
78
                    $existingIndex++;
79
                }
80
            } elseif (isset($addedRange)) {
81
                $pickedRange = $addedRange;
82
                $addedIndex++;
83
            } else {
84
                if (isset($rangeBuffer)) {
85
                    $newRangeList[] = $rangeBuffer;
86
                }
87
                break;
88
            }
89
90
            if (isset($rangeBuffer)) {
91
                if ($rangeBuffer->containsFinishOf($pickedRange)) {
92
                    continue;
93
                }
94
                if ($rangeBuffer->containsStartOf($pickedRange) || $pickedRange->follows($rangeBuffer)) {
95
                    $rangeBuffer = $pickedRange->copyAfterStartOf($rangeBuffer);
96
                    continue;
97
                }
98
                $newRangeList[] = $rangeBuffer;
99
            }
100
            $rangeBuffer = $pickedRange;
101
        }
102
103
        $this->rangeList = $newRangeList;
104
    }
105
106
    /**
107
     * @return Range[]
108
     */
109
    public function getRanges(): array
110
    {
111
        return $this->rangeList;
112
    }
113
114
    public function isEmpty(): bool
115
    {
116
        return empty($this->rangeList);
117
    }
118
119
    private function getSortedRangeList(Range ...$rangeList): array
120
    {
121
        if (isset($rangeList[1])) {
122
            $sortByFrom = function (Range $rangeOne, Range $rangeTwo): int {
123
                return $rangeOne->getStart() <=> $rangeTwo->getStart();
124
            };
125
            usort($rangeList, $sortByFrom);
126
        }
127
128
        return $rangeList;
129
    }
130
}
131