com.squareup.okhttp.internal.BitArray Maven / Gradle / Ivy
/*
* Copyright 2014 Square Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.squareup.okhttp.internal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import static java.lang.String.format;
/** A simple bitset which supports left shifting. */
public interface BitArray {
void clear();
void set(int index);
void toggle(int index);
boolean get(int index);
void shiftLeft(int count);
/** Bit set that only supports settings bits 0 - 63. */
public final class FixedCapacity implements BitArray {
long data = 0x0000000000000000L;
@Override public void clear() {
data = 0x0000000000000000L;
}
@Override public void set(int index) {
data |= (1L << checkInput(index));
}
@Override public void toggle(int index) {
data ^= (1L << checkInput(index));
}
@Override public boolean get(int index) {
return ((data >> checkInput(index)) & 1L) == 1;
}
@Override public void shiftLeft(int count) {
data = data << checkInput(count);
}
@Override public String toString() {
return Long.toBinaryString(data);
}
public BitArray toVariableCapacity() {
return new VariableCapacity(this);
}
private static int checkInput(int index) {
if (index < 0 || index > 63) {
throw new IllegalArgumentException(format("input must be between 0 and 63: %s", index));
}
return index;
}
}
/** Bit set that grows as needed. */
public final class VariableCapacity implements BitArray {
long[] data;
// Start offset which allows for cheap shifting. Data is always kept on 64-bit bounds but we
// offset the outward facing index to support shifts without having to move the underlying bits.
private int start; // Valid values are [0..63]
public VariableCapacity() {
data = new long[1];
}
private VariableCapacity(FixedCapacity small) {
data = new long[] {small.data, 0};
}
private void growToSize(int size) {
long[] newData = new long[size];
if (data != null) {
System.arraycopy(data, 0, newData, 0, data.length);
}
data = newData;
}
private int offsetOf(int index) {
index += start;
int offset = index / 64;
if (offset > data.length - 1) {
growToSize(offset + 1);
}
return offset;
}
private int shiftOf(int index) {
return (index + start) % 64;
}
@Override public void clear() {
Arrays.fill(data, 0);
}
@Override public void set(int index) {
checkInput(index);
int offset = offsetOf(index);
data[offset] |= 1L << shiftOf(index);
}
@Override public void toggle(int index) {
checkInput(index);
int offset = offsetOf(index);
data[offset] ^= 1L << shiftOf(index);
}
@Override public boolean get(int index) {
checkInput(index);
int offset = offsetOf(index);
return (data[offset] & (1L << shiftOf(index))) != 0;
}
@Override public void shiftLeft(int count) {
start -= checkInput(count);
if (start < 0) {
int arrayShift = (start / -64) + 1;
long[] newData = new long[data.length + arrayShift];
System.arraycopy(data, 0, newData, arrayShift, data.length);
data = newData;
start = 64 + (start % 64);
}
}
@Override public String toString() {
StringBuilder builder = new StringBuilder("{");
List ints = toIntegerList();
for (int i = 0, count = ints.size(); i < count; i++) {
if (i > 0) {
builder.append(',');
}
builder.append(ints.get(i));
}
return builder.append('}').toString();
}
List toIntegerList() {
List ints = new ArrayList();
for (int i = 0, count = data.length * 64 - start; i < count; i++) {
if (get(i)) {
ints.add(i);
}
}
return ints;
}
private static int checkInput(int index) {
if (index < 0) {
throw new IllegalArgumentException(format("input must be a positive number: %s", index));
}
return index;
}
}
}