/*
* Copyright 2015 MiLaboratory.com
*
* 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.milaboratory.util;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.util.Arrays;
public final class Bit2Array implements java.io.Serializable {
private static final long serialVersionUID = 1L;
byte[] data;
int size;
public Bit2Array(int length) {
this.size = length;
data = new byte[(length + 3) >> 2];
}
Bit2Array(int size, byte[] data) {
//if (data.length != ((size + 3) >> 2))
// throw new IllegalArgumentException();
this.size = size;
this.data = data;
}
public int size() {
return size;
}
public int get(int index) {
return (data[index >> 2] >>> ((index & 3) << 1)) & 0x3;
}
public void set(int index, int value) {
data[index >> 2] &= ~(0x3 << ((index & 3) << 1));
data[index >> 2] |= (value & 0x3) << ((index & 3) << 1);
}
public Bit2Array clone() {
return new Bit2Array(size, Arrays.copyOf(data, data.length));
}
public Bit2Array extend(int size) {
if (size < this.size)
throw new IllegalArgumentException();
return new Bit2Array(size, Arrays.copyOf(data, (size + 3) >> 2));
}
public byte[] toByteArray() {
byte[] data = new byte[size];
for (int i = 0; i < size; ++i)
data[i] = (byte) get(i);
return data;
}
public void copyFrom(Bit2Array other, int otherOffset, int thisOffset, int length) {
if (thisOffset < 0 || thisOffset + length > size ||
otherOffset < 0 || otherOffset + length > other.size)
throw new IndexOutOfBoundsException();
//TODO optimize
for (int i = 0; i < length; ++i)
set(thisOffset + i, other.get(otherOffset + i));
}
@Override
public int hashCode() {
int hash = 7;
hash = 47 * hash + Arrays.hashCode(this.data);
hash = 47 * hash + this.size;
return hash;
}
@Override
public boolean equals(Object obj) {
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
final Bit2Array other = (Bit2Array) obj;
if (this.size != other.size)
return false;
if (!Arrays.equals(this.data, other.data))
return false;
return true;
}
//TODO optimize
public Bit2Array getRange(int from, int to) {
if (from < 0 || (from >= size && size != 0)
|| to < from || to > size)
throw new IndexOutOfBoundsException("from=" + from + ", to=" + to);
Bit2Array ret = new Bit2Array(to - from);
int i = 0;
for (int j = from; j < to; ++j, ++i)
ret.set(i, get(j));
return ret;
}
public void writeTo(DataOutput output) throws IOException {
output.writeInt(size);
output.write(data);
}
public static Bit2Array readFrom(DataInput input) throws IOException {
int size = input.readInt();
byte[] buf = new byte[(size + 3) >> 2];
input.readFully(buf);
return new Bit2Array(size, buf);
}
/*public static Bit2Array wrap(byte[] data, int size) {
return new Bit2Array(size, data);
}*/
public static byte[] extractRawDataArray(Bit2Array array) {
return array.data;
}
public static Bit2Array construct(int size, byte[] data) {
return new Bit2Array(size, data);
}
}