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