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

dorkbox.network.handshake.RandomId65kAllocator.kt Maven / Gradle / Ivy

Go to download

Encrypted, high-performance, and event-driven/reactive network stack for Java 6+

There is a newer version: 6.14
Show newest version
/*
 * Copyright 2020 dorkbox, llc
 *
 * 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 dorkbox.network.handshake

import dorkbox.network.exceptions.AllocationException
import dorkbox.objectPool.ObjectPool
import dorkbox.objectPool.Pool
import kotlinx.atomicfu.atomic
import java.security.SecureRandom

/**
 * An allocator for random IDs, the maximum number of IDs is an unsigned short (65535).
 *
 * The allocator randomly selects values from the given range `[min, max]` and will not return a previously-returned value `x`
 * until `x` has been freed with [free].
 *
 * This implementation uses storage of {max-min}, with a maximum amount of 65534.
 *
 * @param min The minimum ID (inclusive)
 * @param max The maximum ID (exclusive)
 */
class RandomId65kAllocator(private val min: Int = Integer.MIN_VALUE, max: Int = Integer.MAX_VALUE) {

    private val cache: Pool
    private val maxAssignments: Int
    private val assigned = atomic(0)


    init {
        // IllegalArgumentException
        require(max >= min) {
            "Maximum value $max must be >= minimum value $min"
        }

        maxAssignments = (max - min).coerceIn(1, Short.MAX_VALUE * 2)

        // create a shuffled list of ID's. This operation is ONLY performed ONE TIME per endpoint!
        val ids = ArrayList(maxAssignments)
        for (id in min..(min + maxAssignments - 1)) {
            ids.add(id)
        }

        ids.shuffle(SecureRandom())

        // populate the array of randomly assigned ID's.
        cache = ObjectPool.blocking(ids)
    }

    /**
     * Allocate an unused ID. Will never allocate ID '0'
     *
     * @return A new, unused ID
     *
     * @throws AllocationException If there are no non-allocated IDs left
     */
    fun allocate(): Int {
        if (assigned.value == maxAssignments) {
            throw AllocationException("No IDs left to allocate")
        }

        assigned.getAndIncrement()
        return cache.take()
    }

    /**
     * Free an ID for use later. The id is returned to the cache for usage later
     *
     * @param id The ID to free
     */
    fun free(id: Int) {
        val assigned = assigned.decrementAndGet()
        if (assigned < 0) {
            throw AllocationException("Unequal allocate/free method calls.")
        }
        cache.put(id)
    }

    fun isEmpty(): Boolean {
        return assigned.value == 0
    }

    override fun toString(): String {
        return "$assigned"
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy