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

org.fernice.flare.selector.Bloom.kt Maven / Gradle / Ivy

/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */
package org.fernice.flare.selector

const val HASH_BLOOM_MASK = 0x00ffffff

private const val KEY_SIZE = 12
private const val KEY_MASK = (1 shl KEY_SIZE) - 1

private const val ARRAY_SIZE = 1 shl KEY_SIZE

sealed class BloomFilter(private val storage: BloomStorage) {

    fun insertHash(hash: Int) {
        storage.adjustFirstSlot(hash, true)
        storage.adjustSecondSlot(hash, true)
    }

    fun removeHash(hash: Int) {
        storage.adjustFirstSlot(hash, false)
        storage.adjustSecondSlot(hash, false)
    }

    fun mightContainHash(hash: Int): Boolean {
        return !storage.isFirstSlotEmpty(hash) && !storage.isSecondSlotEmpty(hash)
    }

    fun clear() {
        storage.clear()
    }
}

class CountingBloomFilter : BloomFilter(CountingBloomStorage())

class NonCountingBloomFilter : BloomFilter(NonCountingBloomStorage())

private fun hash1(hash: Int): Int {
    return hash and KEY_SIZE
}

private fun hash2(hash: Int): Int {
    return (hash shr KEY_SIZE) and KEY_MASK
}

interface BloomStorage {

    fun isSlotEmpty(index: Int): Boolean

    fun adjustSlot(index: Int, increment: Boolean)

    fun clear()

    fun isFirstSlotEmpty(hash: Int): Boolean {
        return isSlotEmpty(indexFirstSlot(hash))
    }

    fun isSecondSlotEmpty(hash: Int): Boolean {
        return isSlotEmpty(indexSecondSlot(hash))
    }

    fun adjustFirstSlot(hash: Int, increment: Boolean) {
        adjustSlot(indexFirstSlot(hash), increment)
    }

    fun adjustSecondSlot(hash: Int, increment: Boolean) {
        adjustSlot(indexSecondSlot(hash), increment)
    }

    fun indexFirstSlot(hash: Int): Int {
        return hash1(hash)
    }

    fun indexSecondSlot(hash: Int): Int {
        return hash2(hash)
    }
}

class CountingBloomStorage : BloomStorage {

    private val counters = ByteArray(ARRAY_SIZE)

    override fun isSlotEmpty(index: Int): Boolean {
        return counters[index] == (0x00).toByte()
    }

    override fun adjustSlot(index: Int, increment: Boolean) {
        val count = counters[index]

        if (count != (0xff).toByte()) {
            counters[index] = if (increment) {
                count.inc()
            } else {
                count.dec()
            }
        }
    }

    override fun clear() {
        for (i in counters.indices) {
            counters[i] = 0
        }
    }
}

class NonCountingBloomStorage : BloomStorage {

    private val flags = IntArray(ARRAY_SIZE / 32)

    override fun isSlotEmpty(index: Int): Boolean {
        val bit = 1 shl (index % 32)
        val bits = flags[index / 32]

        return (bits and bit) != 0
    }

    override fun adjustSlot(index: Int, increment: Boolean) {
        val bit = 1 shl (index % 32)
        val bits = flags[index / 32]

        if (increment) {
            flags[index / 32] = bits or bit
        }
    }

    override fun clear() {
        for (i in flags.indices) {
            flags[i] = 0
        }
    }
}





© 2015 - 2025 Weber Informatics LLC | Privacy Policy