1 ///////////////////////////////////////////////////////////////////////////////////////////////
2 // checkstyle: Checks Java source code and other text files for adherence to a set of rules.
3 // Copyright (C) 2001-2024 the original author or authors.
4 //
5 // This library is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU Lesser General Public
7 // License as published by the Free Software Foundation; either
8 // version 2.1 of the License, or (at your option) any later version.
9 //
10 // This library is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 // Lesser General Public License for more details.
14 //
15 // You should have received a copy of the GNU Lesser General Public
16 // License along with this library; if not, write to the Free Software
17 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 ///////////////////////////////////////////////////////////////////////////////////////////////
19
20 package com.puppycrawl.tools.checkstyle.checks.indentation;
21
22 import java.util.BitSet;
23
24 /**
25 * Encapsulates representation of notion of expected indentation levels.
26 * Provide a way to have multiple acceptable levels.
27 * This class is immutable.
28 */
29 public class IndentLevel {
30
31 /** Set of acceptable indentation levels. */
32 private final BitSet levels = new BitSet();
33
34 /**
35 * Creates new instance with one acceptable indentation level.
36 *
37 * @param indent acceptable indentation level.
38 */
39 public IndentLevel(int indent) {
40 levels.set(indent);
41 }
42
43 /**
44 * Creates new instance for nested structure.
45 *
46 * @param base parent's level
47 * @param offsets offsets from parent's level.
48 */
49 public IndentLevel(IndentLevel base, int... offsets) {
50 final BitSet src = base.levels;
51 for (int i = src.nextSetBit(0); i >= 0; i = src.nextSetBit(i + 1)) {
52 for (int offset : offsets) {
53 levels.set(i + offset);
54 }
55 }
56 }
57
58 /**
59 * Creates new instance with no acceptable indentation level.
60 * This is only used internally to combine multiple levels.
61 */
62 private IndentLevel() {
63 }
64
65 /**
66 * Checks whether we have more than one level.
67 *
68 * @return whether we have more than one level.
69 */
70 public final boolean isMultiLevel() {
71 return levels.cardinality() > 1;
72 }
73
74 /**
75 * Checks if given indentation is acceptable.
76 *
77 * @param indent indentation to check.
78 * @return true if given indentation is acceptable,
79 * false otherwise.
80 */
81 public boolean isAcceptable(int indent) {
82 return levels.get(indent);
83 }
84
85 /**
86 * Returns true if indent less than minimal of
87 * acceptable indentation levels, false otherwise.
88 *
89 * @param indent indentation to check.
90 * @return true if {@code indent} less than minimal of
91 * acceptable indentation levels, false otherwise.
92 */
93 public boolean isGreaterThan(int indent) {
94 return levels.nextSetBit(0) > indent;
95 }
96
97 /**
98 * Adds one or more acceptable indentation level.
99 *
100 * @param base class to add new indentations to.
101 * @param additions new acceptable indentation.
102 * @return New acceptable indentation level instance.
103 */
104 public static IndentLevel addAcceptable(IndentLevel base, int... additions) {
105 final IndentLevel result = new IndentLevel();
106 result.levels.or(base.levels);
107 for (int addition : additions) {
108 result.levels.set(addition);
109 }
110 return result;
111 }
112
113 /**
114 * Combines 2 acceptable indentation level classes.
115 *
116 * @param base class to add new indentations to.
117 * @param addition new acceptable indentation.
118 * @return New acceptable indentation level instance.
119 */
120 public static IndentLevel addAcceptable(IndentLevel base, IndentLevel addition) {
121 final IndentLevel result = new IndentLevel();
122 result.levels.or(base.levels);
123 result.levels.or(addition.levels);
124 return result;
125 }
126
127 /**
128 * Returns first indentation level.
129 *
130 * @return indentation level.
131 */
132 public int getFirstIndentLevel() {
133 return levels.nextSetBit(0);
134 }
135
136 /**
137 * Returns last indentation level.
138 *
139 * @return indentation level.
140 */
141 public int getLastIndentLevel() {
142 return levels.length() - 1;
143 }
144
145 @Override
146 public String toString() {
147 final String result;
148 if (levels.cardinality() == 1) {
149 result = String.valueOf(levels.nextSetBit(0));
150 }
151 else {
152 final StringBuilder sb = new StringBuilder(50);
153 for (int i = levels.nextSetBit(0); i >= 0;
154 i = levels.nextSetBit(i + 1)) {
155 if (sb.length() > 0) {
156 sb.append(", ");
157 }
158 sb.append(i);
159 }
160 result = sb.toString();
161 }
162 return result;
163 }
164
165 }