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