Path: blob/master/src/java.base/share/classes/sun/security/util/BitArray.java
67766 views
/*1* Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.security.util;2627import java.io.ByteArrayOutputStream;28import java.util.Arrays;2930/**31* A packed array of booleans.32*33* @author Joshua Bloch34* @author Douglas Hoover35*/3637public class BitArray {3839private byte[] repn;40private int length;4142private static final int BITS_PER_UNIT = 8;4344private static int subscript(int idx) {45return idx / BITS_PER_UNIT;46}4748private static int position(int idx) { // bits big-endian in each unit49return 1 << (BITS_PER_UNIT - 1 - (idx % BITS_PER_UNIT));50}5152/**53* Creates a BitArray of the specified size, initialized to zeros.54*/55public BitArray(int length) throws IllegalArgumentException {56if (length < 0) {57throw new IllegalArgumentException("Negative length for BitArray");58}5960this.length = length;6162repn = new byte[(length + BITS_PER_UNIT - 1)/BITS_PER_UNIT];63}6465/**66* Creates a BitArray of the specified size, initialized from the67* specified byte array. The most significant bit of {@code a[0]} gets68* index zero in the BitArray. The array must be large enough to specify69* a value for every bit of the BitArray. i.e. {@code 8*a.length <= length}.70*/71public BitArray(int length, byte[] a) throws IllegalArgumentException {72this(length, a, 0);73}7475/**76* Creates a BitArray of the specified size, initialized from the77* specified byte array starting at the specified offset. The most78* significant bit of {@code a[ofs]} gets index zero in the BitArray.79* The array must be large enough to specify a value for every bit of80* the BitArray, i.e. {@code 8*(a.length - ofs) <= length}.81*/82public BitArray(int length, byte[] a, int ofs)83throws IllegalArgumentException {8485if (length < 0) {86throw new IllegalArgumentException("Negative length for BitArray");87}88if ((a.length - ofs) * BITS_PER_UNIT < length) {89throw new IllegalArgumentException90("Byte array too short to represent " + length + "-bit array");91}9293this.length = length;9495int repLength = ((length + BITS_PER_UNIT - 1)/BITS_PER_UNIT);96int unusedBits = repLength*BITS_PER_UNIT - length;97byte bitMask = (byte) (0xFF << unusedBits);9899/*100normalize the representation:1011. discard extra bytes1022. zero out extra bits in the last byte103*/104repn = new byte[repLength];105System.arraycopy(a, ofs, repn, 0, repLength);106if (repLength > 0) {107repn[repLength - 1] &= bitMask;108}109}110111/**112* Create a BitArray whose bits are those of the given array113* of Booleans.114*/115public BitArray(boolean[] bits) {116length = bits.length;117repn = new byte[(length + 7)/8];118119for (int i=0; i < length; i++) {120set(i, bits[i]);121}122}123124125/**126* Copy constructor (for cloning).127*/128private BitArray(BitArray ba) {129length = ba.length;130repn = ba.repn.clone();131}132133/**134* Returns the indexed bit in this BitArray.135*/136public boolean get(int index) throws ArrayIndexOutOfBoundsException {137if (index < 0 || index >= length) {138throw new ArrayIndexOutOfBoundsException(Integer.toString(index));139}140141return (repn[subscript(index)] & position(index)) != 0;142}143144/**145* Sets the indexed bit in this BitArray.146*/147public void set(int index, boolean value)148throws ArrayIndexOutOfBoundsException {149if (index < 0 || index >= length) {150throw new ArrayIndexOutOfBoundsException(Integer.toString(index));151}152int idx = subscript(index);153int bit = position(index);154155if (value) {156repn[idx] |= bit;157} else {158repn[idx] &= ~bit;159}160}161162/**163* Returns the length of this BitArray.164*/165public int length() {166return length;167}168169/**170* Returns a Byte array containing the contents of this BitArray.171* The bit stored at index zero in this BitArray will be copied172* into the most significant bit of the zeroth element of the173* returned byte array. The last byte of the returned byte array174* will be contain zeros in any bits that do not have corresponding175* bits in the BitArray. (This matters only if the BitArray's size176* is not a multiple of 8.)177*/178public byte[] toByteArray() {179return repn.clone();180}181182public boolean equals(Object obj) {183if (obj == this) return true;184if (obj == null || !(obj instanceof BitArray)) return false;185186BitArray ba = (BitArray) obj;187188if (ba.length != length) return false;189190for (int i = 0; i < repn.length; i += 1) {191if (repn[i] != ba.repn[i]) return false;192}193return true;194}195196/**197* Return a boolean array with the same bit values a this BitArray.198*/199public boolean[] toBooleanArray() {200boolean[] bits = new boolean[length];201202for (int i=0; i < length; i++) {203bits[i] = get(i);204}205return bits;206}207208/**209* Returns a hash code value for this bit array.210*211* @return a hash code value for this bit array.212*/213public int hashCode() {214int hashCode = 0;215216for (int i = 0; i < repn.length; i++)217hashCode = 31*hashCode + repn[i];218219return hashCode ^ length;220}221222223public Object clone() {224return new BitArray(this);225}226227228private static final byte[][] NYBBLE = {229{ (byte)'0',(byte)'0',(byte)'0',(byte)'0'},230{ (byte)'0',(byte)'0',(byte)'0',(byte)'1'},231{ (byte)'0',(byte)'0',(byte)'1',(byte)'0'},232{ (byte)'0',(byte)'0',(byte)'1',(byte)'1'},233{ (byte)'0',(byte)'1',(byte)'0',(byte)'0'},234{ (byte)'0',(byte)'1',(byte)'0',(byte)'1'},235{ (byte)'0',(byte)'1',(byte)'1',(byte)'0'},236{ (byte)'0',(byte)'1',(byte)'1',(byte)'1'},237{ (byte)'1',(byte)'0',(byte)'0',(byte)'0'},238{ (byte)'1',(byte)'0',(byte)'0',(byte)'1'},239{ (byte)'1',(byte)'0',(byte)'1',(byte)'0'},240{ (byte)'1',(byte)'0',(byte)'1',(byte)'1'},241{ (byte)'1',(byte)'1',(byte)'0',(byte)'0'},242{ (byte)'1',(byte)'1',(byte)'0',(byte)'1'},243{ (byte)'1',(byte)'1',(byte)'1',(byte)'0'},244{ (byte)'1',(byte)'1',(byte)'1',(byte)'1'}245};246247private static final int BYTES_PER_LINE = 8;248249/**250* Returns a string representation of this BitArray.251*/252public String toString() {253if (length == 0) {254return "";255}256257ByteArrayOutputStream out = new ByteArrayOutputStream();258259for (int i = 0; i < repn.length - 1; i++) {260out.write(NYBBLE[(repn[i] >> 4) & 0x0F], 0, 4);261out.write(NYBBLE[repn[i] & 0x0F], 0, 4);262263if (i % BYTES_PER_LINE == BYTES_PER_LINE - 1) {264out.write('\n');265} else {266out.write(' ');267}268}269270// in last byte of repn, use only the valid bits271for (int i = BITS_PER_UNIT * (repn.length - 1); i < length; i++) {272out.write(get(i) ? '1' : '0');273}274275return new String(out.toByteArray());276277}278279public BitArray truncate() {280for (int i=length-1; i>=0; i--) {281if (get(i)) {282return new BitArray(i+1, repn, 0);283}284}285return new BitArray(1);286}287288}289290291