1717import java .nio .ByteOrder ;
1818import java .util .ArrayList ;
1919import java .util .Arrays ;
20- import java .util .Collection ;
2120import java .util .LinkedHashMap ;
2221import java .util .List ;
2322import java .util .Map ;
3029import org .eclipse .tracecompass .ctf .core .event .scope .IDefinitionScope ;
3130
3231import com .google .common .collect .ImmutableSet ;
33- import com .google .common .collect .Iterables ;
34- import com .google .common .collect .LinkedHashMultimap ;
35- import com .google .common .collect .Multimap ;
3632
3733/**
3834 * A CTF enum declaration.
@@ -102,15 +98,28 @@ public String toString() {
10298 }
10399 }
104100
101+ /**
102+ * Interval tree node for efficient range queries
103+ */
104+ private static class IntervalNode {
105+ final Pair interval ;
106+ final List <String > labels ;
107+ long maxEnd ;
108+ IntervalNode left , right ;
109+
110+ IntervalNode (Pair interval , String label ) {
111+ this .interval = interval ;
112+ this .labels = new ArrayList <>();
113+ this .labels .add (label );
114+ this .maxEnd = interval .getSecond ();
115+ }
116+ }
117+
105118 // ------------------------------------------------------------------------
106119 // Attributes
107120 // ------------------------------------------------------------------------
108121
109- /**
110- * fEnumMap key is the Pair of low and high, value is the label. Overlap of
111- * keys in the map is allowed.
112- */
113- private final Multimap <Pair , String > fEnumMap = LinkedHashMultimap .create ();
122+ private IntervalNode fEnumRoot ;
114123 private final IntegerDeclaration fContainerType ;
115124 private Pair fLastAdded = new Pair (-1 , -1 );
116125 private @ Nullable String [] fCache = new String [CACHE_SIZE ];
@@ -146,7 +155,7 @@ public EnumDeclaration(IntegerDeclaration containerType) {
146155 */
147156 public EnumDeclaration (IntegerDeclaration containerType , Map <Pair , String > enumTree ) {
148157 fContainerType = containerType ;
149- enumTree .entrySet ().forEach (entry -> fEnumMap . put (entry .getKey (), entry .getValue ()));
158+ enumTree .entrySet ().forEach (entry -> insert (entry .getKey (), entry .getValue ()));
150159 }
151160
152161 // ------------------------------------------------------------------------
@@ -231,11 +240,35 @@ public boolean add(long low, long high, @Nullable String label) {
231240 }
232241 }
233242 Pair key = new Pair (low , high );
234- fEnumMap . put (key , label );
243+ insert (key , label );
235244 fLastAdded = key ;
236245 return true ;
237246 }
238247
248+ private void insert (Pair interval , String label ) {
249+ fEnumRoot = insertNode (fEnumRoot , interval , label );
250+ }
251+
252+ private IntervalNode insertNode (IntervalNode node , Pair interval , String label ) {
253+ if (node == null ) {
254+ return new IntervalNode (interval , label );
255+ }
256+
257+ if (interval .equals (node .interval )) {
258+ node .labels .add (label );
259+ return node ;
260+ }
261+
262+ if (interval .getFirst () < node .interval .getFirst ()) {
263+ node .left = insertNode (node .left , interval , label );
264+ } else {
265+ node .right = insertNode (node .right , interval , label );
266+ }
267+
268+ node .maxEnd = Math .max (node .maxEnd , interval .getSecond ());
269+ return node ;
270+ }
271+
239272 /**
240273 * Add a value following the last previously added value.
241274 *
@@ -266,14 +299,12 @@ public boolean add(@Nullable String label) {
266299 return fCache [(int ) value ];
267300 }
268301 List <String > strValues = new ArrayList <>();
269- fEnumMap .forEach ((k , v ) -> {
270- if (value >= k .getFirst () && value <= k .getSecond ()) {
271- strValues .add (v );
272- }
273- });
302+ queryIntersecting (fEnumRoot , value , strValues );
303+
274304 if (!strValues .isEmpty ()) {
275305 return strValues .size () == 1 ? strValues .get (0 ) : strValues .toString ();
276306 }
307+
277308 /*
278309 * Divide the positive value in bits and see if there is a value for all
279310 * those bits
@@ -282,22 +313,52 @@ public boolean add(@Nullable String label) {
282313 for (int i = 0 ; i < Long .SIZE ; i ++) {
283314 Long bitValue = 1L << i ;
284315 if ((bitValue & value ) != 0 ) {
285- /*
286- * See if there is a value for this bit where lower == upper, no
287- * range accepted here
288- */
289- Pair bitPair = new Pair (bitValue , bitValue );
290- Collection <String > flagValues = fEnumMap .get (bitPair );
291- if (flagValues .isEmpty ()) {
292- // No value for this bit, not an enum flag
316+ List <String > bitFlags = new ArrayList <>();
317+ queryExact (fEnumRoot , bitValue , bitFlags );
318+ if (bitFlags .isEmpty ()) {
293319 return null ;
294320 }
295- flagsSet .add (flagValues .size () == 1 ? flagValues . iterator (). next () : flagValues .toString ());
321+ flagsSet .add (bitFlags .size () == 1 ? bitFlags . get ( 0 ) : bitFlags .toString ());
296322 }
297323 }
298324 return flagsSet .isEmpty () ? null : String .join (" | " , flagsSet ); //$NON-NLS-1$
299325 }
300326
327+ private void queryIntersecting (IntervalNode node , long value , List <String > result ) {
328+ if (node == null || node .maxEnd < value ) {
329+ return ;
330+ }
331+
332+ if (value >= node .interval .getFirst () && value <= node .interval .getSecond ()) {
333+ result .addAll (node .labels );
334+ }
335+
336+ if (node .left != null && node .left .maxEnd >= value ) {
337+ queryIntersecting (node .left , value , result );
338+ }
339+
340+ queryIntersecting (node .right , value , result );
341+ }
342+
343+ private void queryExact (IntervalNode node , long value , List <String > result ) {
344+ if (node == null ) {
345+ return ;
346+ }
347+
348+ if (node .interval .getFirst () == value && node .interval .getSecond () == value ) {
349+ result .addAll (node .labels );
350+ }
351+
352+ if (value < node .interval .getFirst ()) {
353+ queryExact (node .left , value , result );
354+ } else if (value > node .interval .getFirst ()) {
355+ queryExact (node .right , value , result );
356+ } else {
357+ queryExact (node .left , value , result );
358+ queryExact (node .right , value , result );
359+ }
360+ }
361+
301362 /**
302363 * Get a copy of the lookup table.
303364 *
@@ -307,19 +368,41 @@ public boolean add(@Nullable String label) {
307368 */
308369 public Map <Pair , String > getLookupTable () {
309370 Map <Pair , String > table = new LinkedHashMap <>();
310- fEnumMap .asMap ().forEach ((k , v ) -> {
311- table .put (k , v .size () == 1 ? v .iterator ().next () : v .toString ());
312- });
371+ collectEntries (fEnumRoot , table );
313372 return table ;
314373 }
315374
375+ private void collectEntries (IntervalNode node , Map <Pair , String > table ) {
376+ if (node == null ) {
377+ return ;
378+ }
379+
380+ String value = node .labels .size () == 1 ? node .labels .get (0 ) : node .labels .toString ();
381+ table .put (node .interval , value );
382+
383+ collectEntries (node .left , table );
384+ collectEntries (node .right , table );
385+ }
386+
316387 /**
317388 * Gets a set of labels of the enum
318389 *
319390 * @return A set of labels of the enum, can be empty but not null
320391 */
321392 public Set <String > getLabels () {
322- return ImmutableSet .copyOf (fEnumMap .values ());
393+ List <String > labels = new ArrayList <>();
394+ collectLabels (fEnumRoot , labels );
395+ return ImmutableSet .copyOf (labels );
396+ }
397+
398+ private void collectLabels (IntervalNode node , List <String > labels ) {
399+ if (node == null ) {
400+ return ;
401+ }
402+
403+ labels .addAll (node .labels );
404+ collectLabels (node .left , labels );
405+ collectLabels (node .right , labels );
323406 }
324407
325408 @ Override
@@ -337,7 +420,7 @@ public String toString() {
337420
338421 @ Override
339422 public int hashCode () {
340- return Objects .hash (fContainerType , fEnumMap );
423+ return Objects .hash (fContainerType , getLookupTable () );
341424 }
342425
343426 @ Override
@@ -355,11 +438,7 @@ public boolean equals(@Nullable Object obj) {
355438 if (!fContainerType .equals (other .fContainerType )) {
356439 return false ;
357440 }
358- /*
359- * Must iterate through the entry sets as the comparator used in the
360- * enum tree does not respect the contract
361- */
362- return Iterables .elementsEqual (fEnumMap .entries (), other .fEnumMap .entries ());
441+ return Objects .equals (getLookupTable (), other .getLookupTable ());
363442 }
364443
365444 @ Override
@@ -377,11 +456,7 @@ public boolean isBinaryEquivalent(@Nullable IDeclaration obj) {
377456 if (!fContainerType .isBinaryEquivalent (other .fContainerType )) {
378457 return false ;
379458 }
380- /*
381- * Must iterate through the entry sets as the comparator used in the
382- * enum tree does not respect the contract
383- */
384- return Iterables .elementsEqual (fEnumMap .entries (), other .fEnumMap .entries ());
459+ return Objects .equals (getLookupTable (), other .getLookupTable ());
385460 }
386461
387462}
0 commit comments