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