/*
*
* Copyright 2016 Robert Winkler and Bohdan Storozhuk
*
* 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 io.github.resilience4j.circuitbreaker.internal;
/**
* A ring bit set which stores bits up to a maximum size of bits.
*/
class RingBitSet {
private final int size;
private final BitSetMod bitSet;
private boolean notFull;
private int index = -1;
private volatile int length;
private volatile int cardinality = 0;
/**
* Creates a ring bit set whose size is large enough to explicitly
* represent bits with indices in the range {@code 0} through
* {@code bitSetSize-1}. All bits are initially {@code false}.
*
* @param bitSetSize the size of the ring bit set
* @throws NegativeArraySizeException if the specified initial size
* is negative
*/
RingBitSet(int bitSetSize) {
notFull = true;
size = bitSetSize;
bitSet = new BitSetMod(bitSetSize);
}
/**
* Creates a ring bit set whose size is large enough to explicitly
* represent bits with indices in the range {@code 0} through
* {@code bitSetSize-1}. The bits from the source ring bit set are copied into the new ring bit set.
*
* @param bitSetSize the size of the ring bit set
* @param sourceSet the source ring bit set
* @throws NegativeArraySizeException if the specified initial size
* is negative
*/
RingBitSet(int bitSetSize, RingBitSet sourceSet) {
this(bitSetSize);
int targetLength = Integer.min(bitSetSize, sourceSet.length);
int sourceIndex = sourceSet.index;
int forwardIndex = sourceSet.size - sourceIndex;
for (int i = 0; i < targetLength; i++) {
this.setNextBit(sourceSet.bitSet.get(sourceIndex));
// looping sourceIndex backwards without conditional statements
forwardIndex = (forwardIndex + 1) % sourceSet.size;
sourceIndex = (sourceSet.size - forwardIndex) % sourceSet.size;
}
}
/**
* Sets the bit at the next index to the specified value.
*
* @param value a boolean value to set
* @return the number of bits set to {@code true}
*/
public synchronized int setNextBit(boolean value) {
increaseLength();
index = (index + 1) % size;
int previous = bitSet.set(index, value);
int current = value ? 1 : 0;
cardinality = cardinality - previous + current;
return cardinality;
}
/**
* Returns the number of bits set to {@code true} in this {@code RingBitSet}.
*
* @return the number of bits set to {@code true} in this {@code RingBitSet}
*/
public int cardinality() {
return cardinality;
}
/**
* Returns the number of bits of space actually in use by this
* {@code RingBitSet} to represent bit values.
* The maximum element in the set is the size - 1st element.
*
* @return the number of bits currently in this ring bit set
*/
public int size() {
return bitSet.size();
}
/**
* Returns the "logical size" up to the maximum size of this {@code RingBitSet}.
* Returns zero if the {@code RingBitSet} contains no set bits.
*
* @return the logical size of this {@code RingBitSet}
*/
public int length() {
return length;
}
/**
* Prints the current state of internal bit set.
* @return string representation on internal bit set.
*/
@Override
public String toString() {
StringBuilder result = new StringBuilder();
for (int i = 0; i < size; i++) {
result.append(bitSet.get(i) ? '1' : '0');
}
return result.toString();
}
/**
* Returns the current index of this {@code RingBitSet}.
* Use only for debugging and testing
*
* @return the current index of this {@code RingBitSet}
*/
synchronized int getIndex() {
return index;
}
private void increaseLength() {
if (notFull) {
int nextLength = length + 1;
if (nextLength < size) {
length = nextLength;
} else {
length = size;
notFull = false;
}
}
}
}