001//////////////////////////////////////////////////////////////////////////////// 002// checkstyle: Checks Java source code for adherence to a set of rules. 003// Copyright (C) 2001-2019 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 * @param indent acceptable indentation level. 037 */ 038 public IndentLevel(int indent) { 039 levels.set(indent); 040 } 041 042 /** 043 * Creates new instance for nested structure. 044 * @param base parent's level 045 * @param offsets offsets from parent's level. 046 */ 047 public IndentLevel(IndentLevel base, int... offsets) { 048 final BitSet src = base.levels; 049 for (int i = src.nextSetBit(0); i >= 0; i = src.nextSetBit(i + 1)) { 050 for (int offset : offsets) { 051 levels.set(i + offset); 052 } 053 } 054 } 055 056 /** 057 * Creates new instance with no acceptable indentation level. 058 * This is only used internally to combine multiple levels. 059 */ 060 private IndentLevel() { 061 } 062 063 /** 064 * Checks whether we have more than one level. 065 * @return whether we have more than one level. 066 */ 067 public final boolean isMultiLevel() { 068 return levels.cardinality() > 1; 069 } 070 071 /** 072 * Checks if given indentation is acceptable. 073 * @param indent indentation to check. 074 * @return true if given indentation is acceptable, 075 * false otherwise. 076 */ 077 public boolean isAcceptable(int indent) { 078 return levels.get(indent); 079 } 080 081 /** 082 * Returns true if indent less than minimal of 083 * acceptable indentation levels, false otherwise. 084 * @param indent indentation to check. 085 * @return true if {@code indent} less than minimal of 086 * acceptable indentation levels, false otherwise. 087 */ 088 public boolean isGreaterThan(int indent) { 089 return levels.nextSetBit(0) > indent; 090 } 091 092 /** 093 * Adds one or more acceptable indentation level. 094 * @param base class to add new indentations to. 095 * @param additions new acceptable indentation. 096 * @return New acceptable indentation level instance. 097 */ 098 public static IndentLevel addAcceptable(IndentLevel base, int... additions) { 099 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}