1 /* 2 * Copyright (c) 2012-2018 The ANTLR Project. All rights reserved. 3 * Use of this file is governed by the BSD 3-clause license that 4 * can be found in the LICENSE.txt file in the project root. 5 */ 6 7 module antlr.v4.runtime.misc.Interval; 8 9 import std.algorithm; 10 import std.conv; 11 12 /** 13 * @uml 14 * An immutable inclusive interval a..b 15 */ 16 class Interval 17 { 18 19 public static immutable int INTERVAL_POOL_MAX_VALUE = 1000; 20 21 public static const Interval INVALID = new Interval(-1, -2); 22 23 private static Interval[] cache = new Interval[INTERVAL_POOL_MAX_VALUE+1]; 24 25 public int a; 26 27 public int b; 28 29 public static int creates = 0; 30 31 public static int misses = 0; 32 33 public static int hits = 0; 34 35 public static int outOfRange = 0; 36 37 /** 38 * @uml 39 * @pure 40 * @safe 41 */ 42 public this(int a, int b) @safe pure 43 { 44 this.a = a; 45 this.b = b; 46 } 47 48 /** 49 * @uml 50 * Interval objects are used readonly so share all with the 51 * same single value a==b up to some max size. Use an array as a perfect hash. 52 * Return shared object for 0..INTERVAL_POOL_MAX_VALUE or a new 53 * Interval object with a..a in it. On Java.g4, 218623 IntervalSets 54 * have a..a (set with 1 element). 55 * @safe 56 */ 57 public static Interval of(int a, int b) @safe 58 { 59 // cache just a..a 60 if (a != b || a < 0 || a > INTERVAL_POOL_MAX_VALUE) { 61 return new Interval(a, b); 62 } 63 if (cache[a] is null) { 64 cache[a] = new Interval(a, a); 65 } 66 return cache[a]; 67 } 68 69 /** 70 * @uml 71 * return number of elements between a and b inclusively. x..x is length 1. 72 * if b < a, then length is 0. 9..10 has length 2. 73 * @pure 74 * @safe 75 */ 76 public int length() @safe pure 77 { 78 if (b < a) return 0; 79 return b - a + 1; 80 } 81 82 /** 83 * @uml 84 * @pure 85 * @safe 86 */ 87 public bool equals(Object o) @safe pure 88 { 89 Interval other = cast(Interval)o; 90 return this.a == other.a && this.b == other.b; 91 } 92 93 unittest 94 { 95 auto a = new Interval(1, 2); 96 auto b = new Interval(1, 2); 97 assert(a.equals(b), a.toString); 98 } 99 100 /** 101 * @uml 102 * @pure 103 * @safe 104 */ 105 public int hashCode() @safe pure 106 { 107 int hash = 23; 108 hash = hash * 31 + a; 109 hash = hash * 31 + b; 110 return hash; 111 } 112 113 /** 114 * @uml 115 * Does this start completely before other? Disjoint 116 * @pure 117 * @safe 118 */ 119 public bool startsBeforeDisjoint(Interval other) @safe pure 120 { 121 return this.a<other.a && this.b<other.a; 122 } 123 124 /** 125 * @uml 126 * Does this start at or before other? Nondisjoint 127 * @pure 128 * @safe 129 */ 130 public bool startsBeforeNonDisjoint(Interval other) @safe pure 131 { 132 return this.a<=other.a && this.b>=other.a; 133 } 134 135 /** 136 * @uml 137 * Does this.a start after other.b? May or may not be disjoint 138 * @pure 139 * @safe 140 */ 141 public bool startsAfter(Interval other) @safe pure 142 { 143 return this.a > other.a; 144 } 145 146 /** 147 * @uml 148 * Does this start completely after other? Disjoint 149 * @pure 150 * @safe 151 */ 152 public bool startsAfterDisjoint(Interval other) @safe pure 153 { 154 return this.a > other.b; 155 } 156 157 /** 158 * @uml 159 * Does this start after other? NonDisjoint 160 * @pure 161 * @safe 162 */ 163 public bool startsAfterNonDisjoint(Interval other) @safe pure 164 { 165 return this.a > other.a && this.a <= other.b; // this.b>=other.b implied 166 } 167 168 /** 169 * @uml 170 * Are both ranges disjoint? I.e., no overlap? 171 * @pure 172 * @safe 173 */ 174 public bool disjoint(Interval other) @safe pure 175 { 176 return startsBeforeDisjoint(other) || startsAfterDisjoint(other); 177 } 178 179 /** 180 * @uml 181 * Are two intervals adjacent such as 0..41 and 42..42? 182 * @pure 183 * @safe 184 */ 185 public bool adjacent(Interval other) @safe pure 186 { 187 return this.a == other.b+1 || this.b == other.a-1; 188 } 189 190 unittest 191 { 192 auto a = new Interval(1 , 2); 193 auto b = new Interval(3 , 10); 194 assert(b.adjacent(a)); 195 assert(!b.adjacent(new Interval(1, 6))); 196 assert(!b.adjacent(new Interval(10, 16))); 197 } 198 199 /** 200 * @uml 201 * @pure 202 * @safe 203 */ 204 public bool properlyContains(Interval other) @safe pure 205 { 206 return other.a >= this.a && other.b <= this.b; 207 } 208 209 /** 210 * @uml 211 * Return the interval computed from combining this and other 212 * @safe 213 */ 214 public Interval unionInterval(Interval other) @safe 215 { 216 return Interval.of(min(a, other.a), max(b, other.b)); 217 } 218 219 unittest 220 { 221 auto a = new Interval(1, 2); 222 auto b = new Interval(3, 10); 223 auto c = new Interval(1, 10); 224 auto d = new Interval(7, 10); 225 assert(b.unionInterval(a).equals(c)); 226 assert(c.unionInterval(a).equals(c)); 227 assert(a.unionInterval(c).equals(c)); 228 assert(c.unionInterval(d).equals(c)); 229 assert(d.unionInterval(c).equals(c)); 230 assert(!d.unionInterval(c).equals(d)); 231 } 232 233 /** 234 * @uml 235 * Return the interval in common between this and o 236 * @safe 237 */ 238 public Interval intersection(Interval other) @safe 239 { 240 return Interval.of(max(a, other.a), min(b, other.b)); 241 } 242 243 /** 244 * @uml 245 * Return the interval with elements from this not in other; 246 * other must not be totally enclosed (properly contained) 247 * within this, which would result in two disjoint intervals 248 * instead of the single one returned by this method. 249 * @safe 250 */ 251 public Interval differenceNotProperlyContained(Interval other) @safe 252 { 253 Interval diff = null; 254 // other.a to left of this.a (or same) 255 if ( other.startsBeforeNonDisjoint(this) ) { 256 diff = Interval.of(max(this.a, other.b + 1), 257 this.b); 258 } 259 260 // other.a to right of this.a 261 else if ( other.startsAfterNonDisjoint(this) ) { 262 diff = Interval.of(this.a, other.a - 1); 263 } 264 return diff; 265 } 266 267 /** 268 * @uml 269 * @override 270 * @pure 271 * @safe 272 */ 273 public override string toString() @safe pure 274 { 275 return to!string(a) ~ ".." ~ to!string(b); 276 } 277 278 }