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 enum 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 { 62 return new Interval(a, b); 63 } 64 if (cache[a] is null) 65 { 66 cache[a] = new Interval(a, a); 67 } 68 return cache[a]; 69 } 70 71 /** 72 * @uml 73 * return number of elements between a and b inclusively. x..x is length 1. 74 * if b < a, then length is 0. 9..10 has length 2. 75 * @pure 76 * @safe 77 */ 78 public int length() @safe pure 79 { 80 if (b < a) 81 return 0; 82 return b - a + 1; 83 } 84 85 /** 86 * @uml 87 * @pure 88 * @safe 89 */ 90 public bool equals(Object o) @safe pure 91 { 92 Interval other = cast(Interval) o; 93 return this.a == other.a && this.b == other.b; 94 } 95 96 unittest 97 { 98 auto a = new Interval(1, 2); 99 auto b = new Interval(1, 2); 100 assert(a.equals(b), a.toString); 101 } 102 103 /** 104 * @uml 105 * @pure 106 * @safe 107 */ 108 public int hashCode() @safe pure 109 { 110 int hash = 23; 111 hash = hash * 31 + a; 112 hash = hash * 31 + b; 113 return hash; 114 } 115 116 /** 117 * @uml 118 * Does this start completely before other? Disjoint 119 * @pure 120 * @safe 121 */ 122 public bool startsBeforeDisjoint(Interval other) @safe pure 123 { 124 return this.a < other.a && this.b < other.a; 125 } 126 127 /** 128 * @uml 129 * Does this start at or before other? Nondisjoint 130 * @pure 131 * @safe 132 */ 133 public bool startsBeforeNonDisjoint(Interval other) @safe pure 134 { 135 return this.a <= other.a && this.b >= other.a; 136 } 137 138 /** 139 * @uml 140 * Does this.a start after other.b? May or may not be disjoint 141 * @pure 142 * @safe 143 */ 144 public bool startsAfter(Interval other) @safe pure 145 { 146 return this.a > other.a; 147 } 148 149 /** 150 * @uml 151 * Does this start completely after other? Disjoint 152 * @pure 153 * @safe 154 */ 155 public bool startsAfterDisjoint(Interval other) @safe pure 156 { 157 return this.a > other.b; 158 } 159 160 /** 161 * @uml 162 * Does this start after other? NonDisjoint 163 * @pure 164 * @safe 165 */ 166 public bool startsAfterNonDisjoint(Interval other) @safe pure 167 { 168 return this.a > other.a && this.a <= other.b; // this.b>=other.b implied 169 } 170 171 /** 172 * @uml 173 * Are both ranges disjoint? I.e., no overlap? 174 * @pure 175 * @safe 176 */ 177 public bool disjoint(Interval other) @safe pure 178 { 179 return startsBeforeDisjoint(other) || startsAfterDisjoint(other); 180 } 181 182 /** 183 * @uml 184 * Are two intervals adjacent such as 0..41 and 42..42? 185 * @pure 186 * @safe 187 */ 188 public bool adjacent(Interval other) @safe pure 189 { 190 return this.a == other.b + 1 || this.b == other.a - 1; 191 } 192 193 unittest 194 { 195 auto a = new Interval(1, 2); 196 auto b = new Interval(3, 10); 197 assert(b.adjacent(a)); 198 assert(!b.adjacent(new Interval(1, 6))); 199 assert(!b.adjacent(new Interval(10, 16))); 200 } 201 202 /** 203 * @uml 204 * @pure 205 * @safe 206 */ 207 public bool properlyContains(Interval other) @safe pure 208 { 209 return other.a >= this.a && other.b <= this.b; 210 } 211 212 /** 213 * @uml 214 * Return the interval computed from combining this and other 215 * @safe 216 */ 217 public Interval unionInterval(Interval other) @safe 218 { 219 return Interval.of(min(a, other.a), max(b, other.b)); 220 } 221 222 unittest 223 { 224 auto a = new Interval(1, 2); 225 auto b = new Interval(3, 10); 226 auto c = new Interval(1, 10); 227 auto d = new Interval(7, 10); 228 assert(b.unionInterval(a).equals(c)); 229 assert(c.unionInterval(a).equals(c)); 230 assert(a.unionInterval(c).equals(c)); 231 assert(c.unionInterval(d).equals(c)); 232 assert(d.unionInterval(c).equals(c)); 233 assert(!d.unionInterval(c).equals(d)); 234 } 235 236 /** 237 * @uml 238 * Return the interval in common between this and o 239 * @safe 240 */ 241 public Interval intersection(Interval other) @safe 242 { 243 return Interval.of(max(a, other.a), min(b, other.b)); 244 } 245 246 /** 247 * @uml 248 * Return the interval with elements from this not in other; 249 * other must not be totally enclosed (properly contained) 250 * within this, which would result in two disjoint intervals 251 * instead of the single one returned by this method. 252 * @safe 253 */ 254 public Interval differenceNotProperlyContained(Interval other) @safe 255 { 256 Interval diff = null; 257 // other.a to left of this.a (or same) 258 if (other.startsBeforeNonDisjoint(this)) 259 { 260 diff = Interval.of(max(this.a, other.b + 1), this.b); 261 } 262 263 // other.a to right of this.a 264 else if (other.startsAfterNonDisjoint(this)) 265 { 266 diff = Interval.of(this.a, other.a - 1); 267 } 268 return diff; 269 } 270 271 /** 272 * @uml 273 * @override 274 * @pure 275 * @safe 276 */ 277 public override string toString() @safe pure 278 { 279 return to!string(a) ~ ".." ~ to!string(b); 280 } 281 282 }