1 /** 2 * [The "BSD license"] 3 * Copyright (c) 2016 Terence Parr 4 * Copyright (c) 2016 Sam Harwell 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. The name of the author may not be used to endorse or promote products 17 * derived from this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 module antlr.v4.runtime.misc.Interval; 32 33 import std.algorithm; 34 import std.conv; 35 36 // Class Interval 37 /** 38 * @uml 39 * An immutable inclusive interval a..b 40 */ 41 class Interval 42 { 43 44 public static immutable int INTERVAL_POOL_MAX_VALUE = 1000; 45 46 public static const Interval INVALID = new Interval(-1, -2); 47 48 private static Interval[] cache = new Interval[INTERVAL_POOL_MAX_VALUE+1]; 49 50 public int a; 51 52 public int b; 53 54 public static int creates = 0; 55 56 public static int misses = 0; 57 58 public static int hits = 0; 59 60 public static int outOfRange = 0; 61 62 /** 63 * @uml 64 * @pure 65 * @safe 66 */ 67 public this(int a, int b) @safe pure 68 { 69 this.a = a; 70 this.b = b; 71 } 72 73 /** 74 * @uml 75 * Interval objects are used readonly so share all with the 76 * same single value a==b up to some max size. Use an array as a perfect hash. 77 * Return shared object for 0..INTERVAL_POOL_MAX_VALUE or a new 78 * Interval object with a..a in it. On Java.g4, 218623 IntervalSets 79 * have a..a (set with 1 element). 80 * @safe 81 */ 82 public static Interval of(int a, int b) @safe 83 { 84 // cache just a..a 85 if (a != b || a < 0 || a > INTERVAL_POOL_MAX_VALUE) { 86 return new Interval(a, b); 87 } 88 if (cache[a] is null) { 89 cache[a] = new Interval(a, a); 90 } 91 return cache[a]; 92 } 93 94 /** 95 * @uml 96 * return number of elements between a and b inclusively. x..x is length 1. 97 * if b < a, then length is 0. 9..10 has length 2. 98 * @pure 99 * @safe 100 */ 101 public int length() @safe pure 102 { 103 if (b < a) return 0; 104 return b - a + 1; 105 } 106 107 /** 108 * @uml 109 * @pure 110 * @safe 111 */ 112 public bool equals(Object o) @safe pure 113 { 114 Interval other = cast(Interval)o; 115 return this.a == other.a && this.b == other.b; 116 } 117 118 unittest 119 { 120 auto a = new Interval(1, 2); 121 auto b = new Interval(1, 2); 122 assert(a.equals(b), a.toString); 123 } 124 125 /** 126 * @uml 127 * @pure 128 * @safe 129 */ 130 public int hashCode() @safe pure 131 { 132 int hash = 23; 133 hash = hash * 31 + a; 134 hash = hash * 31 + b; 135 return hash; 136 } 137 138 /** 139 * @uml 140 * Does this start completely before other? Disjoint 141 * @pure 142 * @safe 143 */ 144 public bool startsBeforeDisjoint(Interval other) @safe pure 145 { 146 return this.a<other.a && this.b<other.a; 147 } 148 149 /** 150 * @uml 151 * Does this start at or before other? Nondisjoint 152 * @pure 153 * @safe 154 */ 155 public bool startsBeforeNonDisjoint(Interval other) @safe pure 156 { 157 return this.a<=other.a && this.b>=other.a; 158 } 159 160 /** 161 * @uml 162 * Does this.a start after other.b? May or may not be disjoint 163 * @pure 164 * @safe 165 */ 166 public bool startsAfter(Interval other) @safe pure 167 { 168 return this.a > other.a; 169 } 170 171 /** 172 * @uml 173 * Does this start completely after other? Disjoint 174 * @pure 175 * @safe 176 */ 177 public bool startsAfterDisjoint(Interval other) @safe pure 178 { 179 return this.a > other.b; 180 } 181 182 /** 183 * @uml 184 * Does this start after other? NonDisjoint 185 * @pure 186 * @safe 187 */ 188 public bool startsAfterNonDisjoint(Interval other) @safe pure 189 { 190 return this.a > other.a && this.a <= other.b; // this.b>=other.b implied 191 } 192 193 /** 194 * @uml 195 * Are both ranges disjoint? I.e., no overlap? 196 * @pure 197 * @safe 198 */ 199 public bool disjoint(Interval other) @safe pure 200 { 201 return startsBeforeDisjoint(other) || startsAfterDisjoint(other); 202 } 203 204 /** 205 * @uml 206 * Are two intervals adjacent such as 0..41 and 42..42? 207 * @pure 208 * @safe 209 */ 210 public bool adjacent(Interval other) @safe pure 211 { 212 return this.a == other.b+1 || this.b == other.a-1; 213 } 214 215 unittest 216 { 217 auto a = new Interval(1 , 2); 218 auto b = new Interval(3 , 10); 219 assert(b.adjacent(a)); 220 assert(!b.adjacent(new Interval(1, 6))); 221 assert(!b.adjacent(new Interval(10, 16))); 222 } 223 224 /** 225 * @uml 226 * @pure 227 * @safe 228 */ 229 public bool properlyContains(Interval other) @safe pure 230 { 231 return other.a >= this.a && other.b <= this.b; 232 } 233 234 /** 235 * @uml 236 * Return the interval computed from combining this and other 237 * @safe 238 */ 239 public Interval unionInterval(Interval other) @safe 240 { 241 return Interval.of(min(a, other.a), max(b, other.b)); 242 } 243 244 unittest 245 { 246 auto a = new Interval(1, 2); 247 auto b = new Interval(3, 10); 248 auto c = new Interval(1, 10); 249 auto d = new Interval(7, 10); 250 assert(b.unionInterval(a).equals(c)); 251 assert(c.unionInterval(a).equals(c)); 252 assert(a.unionInterval(c).equals(c)); 253 assert(c.unionInterval(d).equals(c)); 254 assert(d.unionInterval(c).equals(c)); 255 assert(!d.unionInterval(c).equals(d)); 256 } 257 258 /** 259 * @uml 260 * Return the interval in common between this and o 261 * @safe 262 */ 263 public Interval intersection(Interval other) @safe 264 { 265 return Interval.of(max(a, other.a), min(b, other.b)); 266 } 267 268 /** 269 * @uml 270 * Return the interval with elements from this not in other; 271 * other must not be totally enclosed (properly contained) 272 * within this, which would result in two disjoint intervals 273 * instead of the single one returned by this method. 274 * @safe 275 */ 276 public Interval differenceNotProperlyContained(Interval other) @safe 277 { 278 Interval diff = null; 279 // other.a to left of this.a (or same) 280 if ( other.startsBeforeNonDisjoint(this) ) { 281 diff = Interval.of(max(this.a, other.b + 1), 282 this.b); 283 } 284 285 // other.a to right of this.a 286 else if ( other.startsAfterNonDisjoint(this) ) { 287 diff = Interval.of(this.a, other.a - 1); 288 } 289 return diff; 290 } 291 292 /** 293 * @uml 294 * @override 295 * @pure 296 * @safe 297 */ 298 public override string toString() @safe pure 299 { 300 return to!string(a) ~ ".." ~ to!string(b); 301 } 302 303 }