1 ////////////////////////////////////////////////////////////////////////////////
2 // checkstyle: Checks Java source code for adherence to a set of rules.
3 // Copyright (C) 2001-2019 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 * @param indent acceptable indentation level.
37 */
38 public IndentLevel(int indent) {
39 levels.set(indent);
40 }
41
42 /**
43 * Creates new instance for nested structure.
44 * @param base parent's level
45 * @param offsets offsets from parent's level.
46 */
47 public IndentLevel(IndentLevel base, int... offsets) {
48 final BitSet src = base.levels;
49 for (int i = src.nextSetBit(0); i >= 0; i = src.nextSetBit(i + 1)) {
50 for (int offset : offsets) {
51 levels.set(i + offset);
52 }
53 }
54 }
55
56 /**
57 * Creates new instance with no acceptable indentation level.
58 * This is only used internally to combine multiple levels.
59 */
60 private IndentLevel() {
61 }
62
63 /**
64 * Checks whether we have more than one level.
65 * @return whether we have more than one level.
66 */
67 public final boolean isMultiLevel() {
68 return levels.cardinality() > 1;
69 }
70
71 /**
72 * Checks if given indentation is acceptable.
73 * @param indent indentation to check.
74 * @return true if given indentation is acceptable,
75 * false otherwise.
76 */
77 public boolean isAcceptable(int indent) {
78 return levels.get(indent);
79 }
80
81 /**
82 * Returns true if indent less than minimal of
83 * acceptable indentation levels, false otherwise.
84 * @param indent indentation to check.
85 * @return true if {@code indent} less than minimal of
86 * acceptable indentation levels, false otherwise.
87 */
88 public boolean isGreaterThan(int indent) {
89 return levels.nextSetBit(0) > indent;
90 }
91
92 /**
93 * Adds one or more acceptable indentation level.
94 * @param base class to add new indentations to.
95 * @param additions new acceptable indentation.
96 * @return New acceptable indentation level instance.
97 */
98 public static IndentLevel addAcceptable(IndentLevel base, int... additions) {
99 final IndentLevel result = new IndentLevel();
100 result.levels.or(base.levels);
101 for (int addition : additions) {
102 result.levels.set(addition);
103 }
104 return result;
105 }
106
107 /**
108 * Combines 2 acceptable indentation level classes.
109 * @param base class to add new indentations to.
110 * @param addition new acceptable indentation.
111 * @return New acceptable indentation level instance.
112 */
113 public static IndentLevel addAcceptable(IndentLevel base, IndentLevel addition) {
114 final IndentLevel result = new IndentLevel();
115 result.levels.or(base.levels);
116 result.levels.or(addition.levels);
117 return result;
118 }
119
120 /**
121 * Returns first indentation level.
122 * @return indentation level.
123 */
124 public int getFirstIndentLevel() {
125 return levels.nextSetBit(0);
126 }
127
128 /**
129 * Returns last indentation level.
130 * @return indentation level.
131 */
132 public int getLastIndentLevel() {
133 return levels.length() - 1;
134 }
135
136 @Override
137 public String toString() {
138 final String result;
139 if (levels.cardinality() == 1) {
140 result = String.valueOf(levels.nextSetBit(0));
141 }
142 else {
143 final StringBuilder sb = new StringBuilder(50);
144 for (int i = levels.nextSetBit(0); i >= 0;
145 i = levels.nextSetBit(i + 1)) {
146 if (sb.length() > 0) {
147 sb.append(", ");
148 }
149 sb.append(i);
150 }
151 result = sb.toString();
152 }
153 return result;
154 }
155
156 }