/* * Copyright (C) 2014 Indeed 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.indeed.flamdex.datastruct; import com.indeed.util.mmap.LongArray; import com.indeed.util.mmap.MMapBuffer; import java.io.Closeable; import java.io.File; import java.io.IOException; import java.nio.ByteOrder; import java.nio.channels.FileChannel; /** * @author jsgroth * * copy-paste of FastBitSet that operates on an mmap'd file instead of a long array */ public final class MMapFastBitSet implements Closeable { private final int size; private final int arraySize; private final MMapBuffer buffer; private final int bufferLength; private final LongArray bits; public MMapFastBitSet(File file, int size, FileChannel.MapMode mapMode) throws IOException { this.size = size; this.arraySize = (size + 64) >> 6; this.bufferLength = arraySize * 8; this.buffer = new MMapBuffer(file, 0, bufferLength, mapMode, ByteOrder.LITTLE_ENDIAN); this.bits = buffer.memory().longArray(0, arraySize); } public final boolean get(final int i) { return (bits.get(i >> 6) & (1L << (i & 0x3F))) != 0; } public final void set(final int i) { bits.set(i >> 6, bits.get(i >> 6) | (1L << (i & 0x3F))); } public final void clear(final int i) { bits.set(i >> 6, bits.get(i >> 6) & ~(1L << (i & 0x3F))); } public final void set(final int i, final boolean v) { if (v) set(i); else clear(i); } public final void setRange(final int b, final int e) { final int bt = b >> 6; final int et = e >> 6; if (bt != et) { fill(bits, bt + 1, et, -1L); bits.set(bt, bits.get(bt) | (-1L << (b & 0x3F))); bits.set(et, bits.get(et) | ~(-1L << (e & 0x3F))); } else { bits.set(bt, bits.get(bt) | ((-1L << (b & 0x3F)) & ~(-1L << (e & 0x3F)))); } } public final void clearRange(final int b, final int e) { final int bt = b >> 6; final int et = e >> 6; if (bt != et) { fill(bits, bt + 1, et, 0L); bits.set(bt, bits.get(bt) & ~(-1L << (b & 0x3F))); bits.set(et, bits.get(et) & (-1L << (e & 0x3F))); } else { bits.set(bt, bits.get(bt) & (~(-1L << (b & 0x3F)) | (-1L << (e & 0x3F)))); } } public final void setAll() { fill(bits, 0, arraySize, -1L); } public final void clearAll() { fill(bits, 0, arraySize, 0L); } public final void invertAll() { for (int i = 0; i < arraySize; ++i) bits.set(i, ~bits.get(i)); } public final void and(final MMapFastBitSet other) { for (int i = 0; i < arraySize; ++i) bits.set(i, bits.get(i) & other.bits.get(i)); } public final void or(final MMapFastBitSet other) { for (int i = 0; i < arraySize; ++i) bits.set(i, bits.get(i) | other.bits.get(i)); } public final void nand(final MMapFastBitSet other) { for (int i = 0; i < arraySize; ++i) bits.set(i, ~(bits.get(i) & other.bits.get(i))); } public final void nor(final MMapFastBitSet other) { for (int i = 0; i < arraySize; ++i) bits.set(i, ~(bits.get(i) | other.bits.get(i))); } public final void xor(final MMapFastBitSet other) { for (int i = 0; i < arraySize; ++i) bits.set(i, bits.get(i) ^ other.bits.get(i)); } public final int cardinality() { if (size == 0) return 0; int count = 0; for (int i = 0; i < arraySize - 1; ++i) count += Long.bitCount(bits.get(i)); return count + Long.bitCount(bits.get(arraySize - 1) & ~(-1L << (size & 0x3F))); } public final int size() { return size; } public final long memoryUsage() { return 0; } private static void fill(final LongArray a, final int b, final int e, final long l) { for (int i = b; i < e; ++i) a.set(i, l); } public void sync() throws IOException { buffer.sync(0, bufferLength); } @Override public void close() throws IOException { buffer.close(); } }