package ru.dbotthepony.kstarbound.defs.dungeon;

public final class VectorizedBitSet {
	public final int bits;
	public final int width;
	public final int height;

	private final int[] data;
	private final int mask;
	private final int bitMask;
	private final int bitShift;
	private final int bitShiftInv;

	public VectorizedBitSet(int bits, int width, int height) {
		if (bits <= 0)
			throw new IllegalArgumentException("Zero bits: " + bits);

		this.width = width;
		this.height = height;

		if (bits <= 4) {
			this.bits = 4;

			this.bitShift = 3;
			this.bitShiftInv = 2;

			this.bitMask = 7;
			this.mask = 0xF;
			this.data = new int[(width * height + 7) / 8];
		} else if (bits <= 8) {
			this.bits = 8;
			this.bitMask = 3;

			this.bitShift = 2;
			this.bitShiftInv = 3;

			this.mask = 0xFF;
			this.data = new int[(width * height + 3) / 4];
		} else if (bits <= 16) {
			this.bits = 16;
			this.bitMask = 1;

			this.bitShift = 1;
			this.bitShiftInv = 4;

			this.mask = 0xFFFF;
			this.data = new int[(width * height + 1) / 2];
		} else {
			throw new IllegalArgumentException("Too many bits: " + bits);
		}
	}

	public void set(int x, int y, int value) {
		value = value & this.mask;
		int index = x + y * this.width;
		int arrayIndex = index >>> this.bitShift;
		int innerIndex = (index & this.bitMask) << this.bitShiftInv;
		this.data[arrayIndex] = (this.data[arrayIndex] &~ (this.mask << innerIndex)) | (value << innerIndex);
	}

	public int get(int x, int y) {
		int index = x + y * this.width;
		int arrayIndex = index >>> this.bitShift;
		int innerIndex = (index & this.bitMask) << this.bitShiftInv;

		int values = this.data[arrayIndex];
		return (values >>> innerIndex) & this.mask;
	}
}
