001/////////////////////////////////////////////////////////////////////////////////////////////// 002// checkstyle: Checks Java source code and other text files for adherence to a set of rules. 003// Copyright (C) 2001-2024 the original author or authors. 004// 005// This library is free software; you can redistribute it and/or 006// modify it under the terms of the GNU Lesser General Public 007// License as published by the Free Software Foundation; either 008// version 2.1 of the License, or (at your option) any later version. 009// 010// This library is distributed in the hope that it will be useful, 011// but WITHOUT ANY WARRANTY; without even the implied warranty of 012// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 013// Lesser General Public License for more details. 014// 015// You should have received a copy of the GNU Lesser General Public 016// License along with this library; if not, write to the Free Software 017// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 018/////////////////////////////////////////////////////////////////////////////////////////////// 019 020package com.puppycrawl.tools.checkstyle.checks.indentation; 021 022import java.util.BitSet; 023 024/** 025 * Encapsulates representation of notion of expected indentation levels. 026 * Provide a way to have multiple acceptable levels. 027 * This class is immutable. 028 */ 029public class IndentLevel { 030 031 /** Set of acceptable indentation levels. */ 032 private final BitSet levels = new BitSet(); 033 034 /** 035 * Creates new instance with one acceptable indentation level. 036 * 037 * @param indent acceptable indentation level. 038 */ 039 public IndentLevel(int indent) { 040 levels.set(indent); 041 } 042 043 /** 044 * Creates new instance for nested structure. 045 * 046 * @param base parent's level 047 * @param offsets offsets from parent's level. 048 */ 049 public IndentLevel(IndentLevel base, int... offsets) { 050 final BitSet src = base.levels; 051 for (int i = src.nextSetBit(0); i >= 0; i = src.nextSetBit(i + 1)) { 052 for (int offset : offsets) { 053 levels.set(i + offset); 054 } 055 } 056 } 057 058 /** 059 * Creates new instance with no acceptable indentation level. 060 * This is only used internally to combine multiple levels. 061 */ 062 private IndentLevel() { 063 } 064 065 /** 066 * Checks whether we have more than one level. 067 * 068 * @return whether we have more than one level. 069 */ 070 public final boolean isMultiLevel() { 071 return levels.cardinality() > 1; 072 } 073 074 /** 075 * Checks if given indentation is acceptable. 076 * 077 * @param indent indentation to check. 078 * @return true if given indentation is acceptable, 079 * false otherwise. 080 */ 081 public boolean isAcceptable(int indent) { 082 return levels.get(indent); 083 } 084 085 /** 086 * Returns true if indent less than minimal of 087 * acceptable indentation levels, false otherwise. 088 * 089 * @param indent indentation to check. 090 * @return true if {@code indent} less than minimal of 091 * acceptable indentation levels, false otherwise. 092 */ 093 public boolean isGreaterThan(int indent) { 094 return levels.nextSetBit(0) > indent; 095 } 096 097 /** 098 * Adds one or more acceptable indentation level. 099 * 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}