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