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 &lt; 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 }