All Downloads are FREE. Search and download functionalities are using the official Maven repository.

sviolet.thistle.model.bitmap.AbstractBitmap Maven / Gradle / Ivy

/*
 * Copyright (C) 2015-2019 S.Violet
 *
 * 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.
 *
 * Project GitHub: https://github.com/shepherdviolet/thistle
 * Email: [email protected]
 */

package sviolet.thistle.model.bitmap;

import sviolet.thistle.util.conversion.HashUtils;

import java.io.IOException;

/**
 * 

Bitmap抽象实现, 数据访问层未实现

* *

Bitmap能够精确的判断一个元素是否在集合中存在, 但元素的主键必须为不重复的数字, 且数字有界.

* * @see BloomBitmap * @author S.Violet */ public abstract class AbstractBitmap implements BloomBitmap { // 00000001 00000010 00000100 00001000 ... private static final byte[] F = new byte[8]; // 11111110 11111101 11111011 11110111 ... private static final byte[] R = new byte[8]; // Max length of data (byte array) private static final int MAX_BYTE_ARRAY_LENGTH = Integer.MAX_VALUE >> 3; static { for (int i = 0 ; i < 8 ; i++) { R[i] = (byte) ((F[i] = (byte) (0x01 << i)) ^ 0xFF); } } // bit size protected final int size; /** * 创建指定容量的Bitmap * * @param size 容量, 比特数(不是字节数) */ public AbstractBitmap(int size) { if (size < 0) { throw new IllegalArgumentException("The size must be >= 0, but it's " + size); } if ((bitIndexToSlotOffset(size)) > 0) { throw new IllegalArgumentException("The size must be a multiple of 8, but it's " + size); } this.size = size; dataAccess_init(bitIndexToSlotIndex(size)); } /** * 根据二进制数据创建相同容量的Bitmap * * @param data 二进制数据 */ public AbstractBitmap(byte[] data) { if (data == null) { data = new byte[0]; } if (data.length > MAX_BYTE_ARRAY_LENGTH) { throw new IllegalArgumentException("The length of data must be <= " + MAX_BYTE_ARRAY_LENGTH + ", but it's " + data.length); } this.size = data.length << 3; dataAccess_init(bitIndexToSlotIndex(size)); if (data.length > 0) { dataAccess_inject(data, 0); } } /** * @inheritDoc */ public boolean get(int bitIndex) { if (bitIndex < 0 || bitIndex >= size) { throw new IllegalArgumentException("Out of bound, The bitIndex must be >= 0 and < " + size + ", but it's " + bitIndex); } byte slot = dataAccess_getSlot(bitIndexToSlotIndex(bitIndex)); return (slot & F[bitIndexToSlotOffset(bitIndex)]) != 0; } /** * @inheritDoc */ public boolean put(int bitIndex, boolean value) { if (bitIndex < 0 || bitIndex >= size) { throw new IllegalArgumentException("Out of bound, The bitIndex must be >= 0 and < " + size + ", but it's " + bitIndex); } return putBitToSlot(bitIndexToSlotIndex(bitIndex), bitIndexToSlotOffset(bitIndex), value); } /** * 取出指定slot, 计算新值, 最后存回去 */ protected boolean putBitToSlot(int slotIndex, int slotOffset, boolean value) { //get old value byte oldValue = dataAccess_getSlot(slotIndex); //calculate new value byte newValue = value ? (byte) (oldValue | F[slotOffset]) : (byte) (oldValue & R[slotOffset]); //try to put return dataAccess_putSlot(slotIndex, newValue, oldValue); } /** * @inheritDoc */ @Override public byte[] extractAll(){ byte[] result = new byte[bitIndexToSlotIndex(size)]; dataAccess_extract(result, 0); return result; } /** * @inheritDoc */ @Override public void extract(byte[] dst, int byteOffset) { dataAccess_extract(dst, byteOffset); } /** * @inheritDoc */ @Override public void inject(byte[] src, int byteOffset) { dataAccess_inject(src, byteOffset); } /** * @inheritDoc */ @Override public int size() { return size; } /** * 回收内存 */ @Override public void close() throws IOException { // Do nothing } /** * @inheritDoc * * 注意!!! 这个方法不是线程安全的, 计算过程中, 三个Bitmap的数据如果正在变化, 会出问题!!! */ @Override public void computeWith(Bitmap computeWith, Bitmap resultBitmap, ComputeFunction computeFunction) { if (computeWith == null) { throw new IllegalArgumentException("Bitmap 'computeWith' is null"); } if (resultBitmap == null) { throw new IllegalArgumentException("Bitmap 'resultBitmap' is null"); } if (computeFunction == null) { throw new IllegalArgumentException("ComputeFunction is null"); } if (!(computeWith instanceof AbstractBitmap)) { throw new IllegalArgumentException("Bitmap 'computeWith' is not an instance of AbstractBitmap"); } if (!(resultBitmap instanceof AbstractBitmap)) { throw new IllegalArgumentException("Bitmap 'resultBitmap' is not an instance of AbstractBitmap"); } if (size() != computeWith.size() || size() != resultBitmap.size()) { throw new IllegalArgumentException("The size of the three Bitmaps must be the same, this size: " + size() + ", 'computeWith' size:" + computeWith.size() + ", 'resultBitmap' size :" + resultBitmap.size()); } if (size() <= 0) { return; } AbstractBitmap that = (AbstractBitmap) computeWith; AbstractBitmap result = (AbstractBitmap) resultBitmap; for (int i = 0 ; i < bitIndexToSlotIndex(size()) ; i++) { // 不保证写入成功, 如果result的数据正在变化, 这里可能会写入失败(不会报错) result.dataAccess_putSlot(i, computeFunction.compute(this.dataAccess_getSlot(i), that.dataAccess_getSlot(i)), result.dataAccess_getSlot(i)); } } /** * @inheritDoc */ @Override public void bloomAdd(byte[] data){ if (data == null) { data = new byte[0]; } int[] hashes = bloomHash(data); for (int hash : hashes) { put(hash % size, true); } } /** * @inheritDoc */ @Override public boolean bloomContains(byte[] data) { if (data == null) { data = new byte[0]; } int[] hashes = bloomHash(data); for (int hash : hashes) { if (!get(hash % size)) { return false; } } return true; } /** * 布隆hash算法, 可自定义 */ protected int[] bloomHash(byte[] data){ int[] hashes = new int[3]; hashes[0] = HashUtils.djb2(data); hashes[1] = HashUtils.sdbm(data); hashes[2] = HashUtils.fnv1(data); return hashes; } protected int bitIndexToSlotIndex(int bitIndex) { return bitIndex >> 3; } protected int bitIndexToSlotOffset(int bitIndex) { return bitIndex & 0x07; } protected abstract void dataAccess_init(int slotSize); protected abstract byte dataAccess_getSlot(int slotIndex); protected abstract boolean dataAccess_putSlot(int index, byte newValue, byte oldValue); protected abstract void dataAccess_extract(byte[] dst, int offset); protected abstract void dataAccess_inject(byte[] src, int offset); }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy