xref: /plugin/combo/vendor/antlr/antlr4-php-runtime/src/Interval.php (revision 37748cd8654635afbeca80942126742f0f4cc346)
1*37748cd8SNickeau<?php
2*37748cd8SNickeau
3*37748cd8SNickeaudeclare(strict_types=1);
4*37748cd8SNickeau
5*37748cd8SNickeaunamespace Antlr\Antlr4\Runtime;
6*37748cd8SNickeau
7*37748cd8SNickeauuse Antlr\Antlr4\Runtime\Comparison\Equatable;
8*37748cd8SNickeau
9*37748cd8SNickeau/**
10*37748cd8SNickeau * An immutable inclusive interval start..stop (both start and stop included).
11*37748cd8SNickeau */
12*37748cd8SNickeaufinal class Interval implements Equatable
13*37748cd8SNickeau{
14*37748cd8SNickeau    /** @var int */
15*37748cd8SNickeau    public $start;
16*37748cd8SNickeau
17*37748cd8SNickeau    /** @var int */
18*37748cd8SNickeau    public $stop;
19*37748cd8SNickeau
20*37748cd8SNickeau    public function __construct(int $start, int $stop)
21*37748cd8SNickeau    {
22*37748cd8SNickeau        $this->start = $start;
23*37748cd8SNickeau        $this->stop = $stop;
24*37748cd8SNickeau    }
25*37748cd8SNickeau
26*37748cd8SNickeau    public static function invalid() : self
27*37748cd8SNickeau    {
28*37748cd8SNickeau        static $invalid;
29*37748cd8SNickeau
30*37748cd8SNickeau        return $invalid ?? $invalid = new Interval(-1, -2);
31*37748cd8SNickeau    }
32*37748cd8SNickeau
33*37748cd8SNickeau    public function contains(int $item) : bool
34*37748cd8SNickeau    {
35*37748cd8SNickeau        return $item >= $this->start && $item <= $this->stop;
36*37748cd8SNickeau    }
37*37748cd8SNickeau
38*37748cd8SNickeau    public function getLength() : int
39*37748cd8SNickeau    {
40*37748cd8SNickeau        return $this->stop - $this->start + 1;
41*37748cd8SNickeau    }
42*37748cd8SNickeau
43*37748cd8SNickeau    public function equals(object $other) : bool
44*37748cd8SNickeau    {
45*37748cd8SNickeau        if ($this === $other) {
46*37748cd8SNickeau            return true;
47*37748cd8SNickeau        }
48*37748cd8SNickeau
49*37748cd8SNickeau        return $other instanceof self
50*37748cd8SNickeau            && $this->start === $other->start
51*37748cd8SNickeau            && $this->stop === $other->stop;
52*37748cd8SNickeau    }
53*37748cd8SNickeau
54*37748cd8SNickeau    /**
55*37748cd8SNickeau     * Does this start completely before other? Disjoint.
56*37748cd8SNickeau     */
57*37748cd8SNickeau    public function startsBeforeDisjoint(Interval $other) : bool
58*37748cd8SNickeau    {
59*37748cd8SNickeau        return $this->start < $other->start && $this->stop < $other->start;
60*37748cd8SNickeau    }
61*37748cd8SNickeau
62*37748cd8SNickeau    /**
63*37748cd8SNickeau     * Does this start at or before other? Nondisjoint.
64*37748cd8SNickeau     */
65*37748cd8SNickeau    public function startsBeforeNonDisjoint(Interval $other) : bool
66*37748cd8SNickeau    {
67*37748cd8SNickeau        return $this->start <= $other->start && $this->stop >= $other->start;
68*37748cd8SNickeau    }
69*37748cd8SNickeau
70*37748cd8SNickeau    /**
71*37748cd8SNickeau     * Does this.a start after other.b? May or may not be disjoint.
72*37748cd8SNickeau     */
73*37748cd8SNickeau    public function startsAfter(Interval $other) : bool
74*37748cd8SNickeau    {
75*37748cd8SNickeau        return $this->start > $other->start;
76*37748cd8SNickeau    }
77*37748cd8SNickeau
78*37748cd8SNickeau    /**
79*37748cd8SNickeau     * Does this start completely after other? Disjoint.
80*37748cd8SNickeau     */
81*37748cd8SNickeau    public function startsAfterDisjoint(Interval $other) : bool
82*37748cd8SNickeau    {
83*37748cd8SNickeau        return $this->start > $other->stop;
84*37748cd8SNickeau    }
85*37748cd8SNickeau
86*37748cd8SNickeau    /**
87*37748cd8SNickeau     * Does this start after other? NonDisjoint
88*37748cd8SNickeau     */
89*37748cd8SNickeau    public function startsAfterNonDisjoint(Interval $other) : bool
90*37748cd8SNickeau    {
91*37748cd8SNickeau        // this.b >= other.b implied
92*37748cd8SNickeau        return $this->start > $other->start && $this->start <= $other->stop;
93*37748cd8SNickeau    }
94*37748cd8SNickeau
95*37748cd8SNickeau    /**
96*37748cd8SNickeau     * Are both ranges disjoint? I.e., no overlap?
97*37748cd8SNickeau     */
98*37748cd8SNickeau    public function disjoint(Interval $other) : bool
99*37748cd8SNickeau    {
100*37748cd8SNickeau        return $this->startsBeforeDisjoint($other) || $this->startsAfterDisjoint($other);
101*37748cd8SNickeau    }
102*37748cd8SNickeau
103*37748cd8SNickeau    /**
104*37748cd8SNickeau     * Are two intervals adjacent such as 0..41 and 42..42?
105*37748cd8SNickeau     */
106*37748cd8SNickeau    public function adjacent(Interval $other) : bool
107*37748cd8SNickeau    {
108*37748cd8SNickeau        return $this->start === $other->stop + 1 || $this->stop === $other->start - 1;
109*37748cd8SNickeau    }
110*37748cd8SNickeau
111*37748cd8SNickeau    /**
112*37748cd8SNickeau     * Return the interval computed from combining this and other
113*37748cd8SNickeau     */
114*37748cd8SNickeau    public function union(Interval $other) : self
115*37748cd8SNickeau    {
116*37748cd8SNickeau        return new self(\min($this->start, $other->start), \max($this->stop, $other->stop));
117*37748cd8SNickeau    }
118*37748cd8SNickeau
119*37748cd8SNickeau    /**
120*37748cd8SNickeau     * Return the interval in common between this and o
121*37748cd8SNickeau     */
122*37748cd8SNickeau    public function intersection(Interval $other) : self
123*37748cd8SNickeau    {
124*37748cd8SNickeau        return new self(\max($this->start, $other->start), \min($this->stop, $other->stop));
125*37748cd8SNickeau    }
126*37748cd8SNickeau
127*37748cd8SNickeau    public function __toString() : string
128*37748cd8SNickeau    {
129*37748cd8SNickeau        if ($this->start === $this->stop) {
130*37748cd8SNickeau            return (string) $this->start;
131*37748cd8SNickeau        }
132*37748cd8SNickeau
133*37748cd8SNickeau        return $this->start . '..' . $this->stop;
134*37748cd8SNickeau    }
135*37748cd8SNickeau}
136