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

cn.imkarl.core.common.random.NanoId.kt Maven / Gradle / Ivy

package cn.imkarl.core.common.random

import java.security.SecureRandom
import java.util.*
import kotlin.math.ceil
import kotlin.math.floor
import kotlin.math.ln


/**
 * The default random number generator used by this class.
 * Creates cryptographically strong NanoId Strings.
 */
private val DEFAULT_NUMBER_GENERATOR: SecureRandom = SecureRandom()

/**
 * The default alphabet used by this class.
 * Creates url-friendly NanoId Strings using 64 unique symbols.
 */
private val DEFAULT_ALPHABET = "_-0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray()

/**
 * The default size used by this class.
 * Creates NanoId Strings with slightly more unique values than UUID v4.
 */
private const val DEFAULT_SIZE = 21

/**
 * 生成一个url友好的、伪随机生成的 NanoId 字符串。
 *
 * 生成的 NanoId 字符串将有21个符号
 * NanoId 字符串是使用加密强伪随机数生成器生成的。
 *
 * @return 一个随机生成的NanoId字符串
 */
fun randomNanoId(): String {
    return randomNanoId(DEFAULT_NUMBER_GENERATOR, DEFAULT_ALPHABET, DEFAULT_SIZE)
}

/**
 * Static factory to retrieve a NanoId String.
 *
 * The string is generated using the given random number generator.
 *
 * @param random   The random number generator.
 * @param alphabet The symbols used in the NanoId String.
 * @param size     The number of symbols in the NanoId String.
 * @return A randomly generated NanoId String.
 */
internal fun randomNanoId(random: Random, alphabet: CharArray, size: Int): String {
    require(!(alphabet.isEmpty() || alphabet.size >= 256)) { "alphabet must contain between 1 and 255 symbols." }
    require(size > 0) { "size must be greater than zero." }
    val mask = (2 shl floor(ln((alphabet.size - 1).toDouble()) / ln(2.0)).toInt()) - 1
    val step = ceil(1.6 * mask * size / alphabet.size).toInt()
    val idBuilder = StringBuilder()
    while (true) {
        val bytes = ByteArray(step)
        random.nextBytes(bytes)
        for (i in 0 until step) {
            val alphabetIndex = bytes[i].toInt() and mask
            if (alphabetIndex < alphabet.size) {
                idBuilder.append(alphabet[alphabetIndex])
                if (idBuilder.length == size) {
                    return idBuilder.toString()
                }
            }
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy