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.
@@ -100,15 +96,28 @@ public String toString() {
10096 }
10197 }
10298
99+ /**
100+ * Interval tree node for efficient range queries
101+ */
102+ private static class IntervalNode {
103+ final Pair interval ;
104+ final List <String > labels ;
105+ long maxEnd ;
106+ IntervalNode left , right ;
107+
108+ IntervalNode (Pair interval , String label ) {
109+ this .interval = interval ;
110+ this .labels = new ArrayList <>();
111+ this .labels .add (label );
112+ this .maxEnd = interval .getSecond ();
113+ }
114+ }
115+
103116 // ------------------------------------------------------------------------
104117 // Attributes
105118 // ------------------------------------------------------------------------
106119
107- /**
108- * fEnumMap key is the Pair of low and high, value is the label. Overlap of
109- * keys in the map is allowed.
110- */
111- private final Multimap <Pair , String > fEnumMap = LinkedHashMultimap .create ();
120+ private IntervalNode fEnumRoot ;
112121 private final IntegerDeclaration fContainerType ;
113122 private Pair fLastAdded = new Pair (-1 , -1 );
114123
@@ -143,7 +152,7 @@ public EnumDeclaration(IntegerDeclaration containerType) {
143152 */
144153 public EnumDeclaration (IntegerDeclaration containerType , Map <Pair , String > enumTree ){
145154 fContainerType = containerType ;
146- enumTree .entrySet ().forEach (entry -> fEnumMap . put (entry .getKey (), entry .getValue ()));
155+ enumTree .entrySet ().forEach (entry -> insert (entry .getKey (), entry .getValue ()));
147156 }
148157
149158 // ------------------------------------------------------------------------
@@ -213,11 +222,35 @@ public boolean add(long low, long high, @Nullable String label) {
213222 return false ;
214223 }
215224 Pair key = new Pair (low , high );
216- fEnumMap . put (key , label );
225+ insert (key , label );
217226 fLastAdded = key ;
218227 return true ;
219228 }
220229
230+ private void insert (Pair interval , String label ) {
231+ fEnumRoot = insertNode (fEnumRoot , interval , label );
232+ }
233+
234+ private IntervalNode insertNode (IntervalNode node , Pair interval , String label ) {
235+ if (node == null ) {
236+ return new IntervalNode (interval , label );
237+ }
238+
239+ if (interval .equals (node .interval )) {
240+ node .labels .add (label );
241+ return node ;
242+ }
243+
244+ if (interval .getFirst () < node .interval .getFirst ()) {
245+ node .left = insertNode (node .left , interval , label );
246+ } else {
247+ node .right = insertNode (node .right , interval , label );
248+ }
249+
250+ node .maxEnd = Math .max (node .maxEnd , interval .getSecond ());
251+ return node ;
252+ }
253+
221254 /**
222255 * Add a value following the last previously added value.
223256 *
@@ -242,14 +275,12 @@ public boolean add(@Nullable String label) {
242275 */
243276 public @ Nullable String query (long value ) {
244277 List <String > strValues = new ArrayList <>();
245- fEnumMap .forEach ((k , v ) -> {
246- if (value >= k .getFirst () && value <= k .getSecond ()) {
247- strValues .add (v );
248- }
249- });
278+ queryIntersecting (fEnumRoot , value , strValues );
279+
250280 if (!strValues .isEmpty ()) {
251281 return strValues .size () == 1 ? strValues .get (0 ) : strValues .toString ();
252282 }
283+
253284 /*
254285 * Divide the positive value in bits and see if there is a value for all
255286 * those bits
@@ -258,22 +289,52 @@ public boolean add(@Nullable String label) {
258289 for (int i = 0 ; i < Long .SIZE ; i ++) {
259290 Long bitValue = 1L << i ;
260291 if ((bitValue & value ) != 0 ) {
261- /*
262- * See if there is a value for this bit where lower == upper, no
263- * range accepted here
264- */
265- Pair bitPair = new Pair (bitValue , bitValue );
266- Collection <String > flagValues = fEnumMap .get (bitPair );
267- if (flagValues .isEmpty ()) {
268- // No value for this bit, not an enum flag
292+ List <String > bitFlags = new ArrayList <>();
293+ queryExact (fEnumRoot , bitValue , bitFlags );
294+ if (bitFlags .isEmpty ()) {
269295 return null ;
270296 }
271- flagsSet .add (flagValues .size () == 1 ? flagValues . iterator (). next () : flagValues .toString ());
297+ flagsSet .add (bitFlags .size () == 1 ? bitFlags . get ( 0 ) : bitFlags .toString ());
272298 }
273299 }
274300 return flagsSet .isEmpty () ? null : String .join (" | " , flagsSet ); //$NON-NLS-1$
275301 }
276302
303+ private void queryIntersecting (IntervalNode node , long value , List <String > result ) {
304+ if (node == null || node .maxEnd < value ) {
305+ return ;
306+ }
307+
308+ if (value >= node .interval .getFirst () && value <= node .interval .getSecond ()) {
309+ result .addAll (node .labels );
310+ }
311+
312+ if (node .left != null && node .left .maxEnd >= value ) {
313+ queryIntersecting (node .left , value , result );
314+ }
315+
316+ queryIntersecting (node .right , value , result );
317+ }
318+
319+ private void queryExact (IntervalNode node , long value , List <String > result ) {
320+ if (node == null ) {
321+ return ;
322+ }
323+
324+ if (node .interval .getFirst () == value && node .interval .getSecond () == value ) {
325+ result .addAll (node .labels );
326+ }
327+
328+ if (value < node .interval .getFirst ()) {
329+ queryExact (node .left , value , result );
330+ } else if (value > node .interval .getFirst ()) {
331+ queryExact (node .right , value , result );
332+ } else {
333+ queryExact (node .left , value , result );
334+ queryExact (node .right , value , result );
335+ }
336+ }
337+
277338 /**
278339 * Get a copy of the lookup table.
279340 *
@@ -283,19 +344,41 @@ public boolean add(@Nullable String label) {
283344 */
284345 public Map <Pair , String > getLookupTable () {
285346 Map <Pair , String > table = new LinkedHashMap <>();
286- fEnumMap .asMap ().forEach ((k , v ) -> {
287- table .put (k , v .size () == 1 ? v .iterator ().next () : v .toString ());
288- });
347+ collectEntries (fEnumRoot , table );
289348 return table ;
290349 }
291350
351+ private void collectEntries (IntervalNode node , Map <Pair , String > table ) {
352+ if (node == null ) {
353+ return ;
354+ }
355+
356+ String value = node .labels .size () == 1 ? node .labels .get (0 ) : node .labels .toString ();
357+ table .put (node .interval , value );
358+
359+ collectEntries (node .left , table );
360+ collectEntries (node .right , table );
361+ }
362+
292363 /**
293364 * Gets a set of labels of the enum
294365 *
295366 * @return A set of labels of the enum, can be empty but not null
296367 */
297368 public Set <String > getLabels () {
298- return ImmutableSet .copyOf (fEnumMap .values ());
369+ List <String > labels = new ArrayList <>();
370+ collectLabels (fEnumRoot , labels );
371+ return ImmutableSet .copyOf (labels );
372+ }
373+
374+ private void collectLabels (IntervalNode node , List <String > labels ) {
375+ if (node == null ) {
376+ return ;
377+ }
378+
379+ labels .addAll (node .labels );
380+ collectLabels (node .left , labels );
381+ collectLabels (node .right , labels );
299382 }
300383
301384 @ Override
@@ -313,7 +396,7 @@ public String toString() {
313396
314397 @ Override
315398 public int hashCode () {
316- return Objects .hash (fContainerType , fEnumMap );
399+ return Objects .hash (fContainerType , getLookupTable () );
317400 }
318401
319402 @ Override
@@ -331,11 +414,7 @@ public boolean equals(@Nullable Object obj) {
331414 if (!fContainerType .equals (other .fContainerType )) {
332415 return false ;
333416 }
334- /*
335- * Must iterate through the entry sets as the comparator used in the enum tree
336- * does not respect the contract
337- */
338- return Iterables .elementsEqual (fEnumMap .entries (), other .fEnumMap .entries ());
417+ return Objects .equals (getLookupTable (), other .getLookupTable ());
339418 }
340419
341420 @ Override
@@ -353,11 +432,7 @@ public boolean isBinaryEquivalent(@Nullable IDeclaration obj) {
353432 if (!fContainerType .isBinaryEquivalent (other .fContainerType )) {
354433 return false ;
355434 }
356- /*
357- * Must iterate through the entry sets as the comparator used in the enum tree
358- * does not respect the contract
359- */
360- return Iterables .elementsEqual (fEnumMap .entries (), other .fEnumMap .entries ());
435+ return Objects .equals (getLookupTable (), other .getLookupTable ());
361436 }
362437
363438}
0 commit comments