View Javadoc
1   /*
2    * SPDX-FileCopyrightText: Copyright (c) 2011-2025 Yegor Bugayenko
3    * SPDX-License-Identifier: MIT
4    */
5   package com.qulice.checkstyle;
6   
7   import com.google.common.base.Predicate;
8   import com.google.common.collect.FluentIterable;
9   import java.util.ArrayList;
10  import java.util.Collection;
11  import java.util.Iterator;
12  
13  /**
14   * Represents a set of LineRange objects. For example, an instance of this class
15   * could represent all the line ranges for methods in a given Java source code
16   * file.
17   *
18   * @since 0.16
19   */
20  public final class LineRanges {
21  
22      /**
23       * ArrayList of line ranges.
24       */
25      private final LineRanges.LocalCollection lines =
26          new LineRanges.LocalCollection();
27  
28      /**
29       * Adds a line range to the collection.
30       * @param line The line range to add to the collection
31       */
32      public void add(final LineRange line) {
33          this.lines.collection().add(line);
34      }
35  
36      /**
37       * Returns an iterator for this collection.
38       * @return Iterator pointing to the internal collections elements.
39       */
40      public Iterator<LineRange> iterator() {
41          return this.lines.collection().iterator();
42      }
43  
44      /**
45       * Detects if the given line number is within any of the line ranges.
46       * @param line The given line number to check
47       * @return True if the given line number is within any line range.
48       */
49      public boolean inRange(final int line) {
50          return !this.lines.collection().isEmpty()
51              && FluentIterable.from(this.lines.collection())
52              .anyMatch(new LineRanges.LineWithAny(line));
53      }
54  
55      /**
56       * Gets the subset of LineRanges that are within all given ranges. Does
57       * not return null; instead, returns empty range if there are no matches.
58       * @param ranges The ranges to filter on.
59       * @return Returns all LineRange elements that are within range.
60       */
61      public LineRanges within(final LineRanges ranges) {
62          final LineRanges result = new LineRanges();
63          final Iterator<LineRange> iterator = ranges.iterator();
64          while (iterator.hasNext()) {
65              final LineRange next = iterator.next();
66              for (final LineRange line : this.lines.collection()) {
67                  if (next.within(line)) {
68                      result.add(line);
69                  }
70              }
71          }
72          return result;
73      }
74  
75      /**
76       * Clears the collection.
77       */
78      public void clear() {
79          this.lines.collection().clear();
80      }
81  
82      /**
83       * Predicate to determine if a given line is within range of any of
84       * the line ranges.
85       *
86       * @since 0.1
87       */
88      private static final class LineWithAny implements Predicate<LineRange> {
89  
90          /**
91           * The given line.
92           */
93          private final int given;
94  
95          /**
96           * Default constructor.
97           * @param line The given line to check against all the line ranges.
98           */
99          private LineWithAny(final int line) {
100             this.given = line;
101         }
102 
103         @Override
104         public boolean apply(final LineRange range) {
105             return range != null && range.within(this.given);
106         }
107     }
108 
109     /**
110      * Thread-safe collection of line ranges.
111      *
112      * @since 0.1
113      */
114     private static final class LocalCollection
115         extends ThreadLocal<Collection<LineRange>> {
116 
117         /**
118          * Internal Collection.
119          */
120         private final transient Collection<LineRange> ranges =
121             new ArrayList<>(20);
122 
123         /**
124          * Get the collection specific to the current thread only.
125          * @return The collection for this thread.
126          */
127         public Collection<LineRange> collection() {
128             return this.ranges;
129         }
130     }
131 }