UUIDにはいくつかの変種やバージョンがあるが、その中でもRFC 4122の中で定義されているバージョン4(以下v4)は単純に乱数で生成するという非常にシンプルな仕組みである。
そのようなシンプルさのため自前で書くのも容易である。
実際にJavascriptでも書いてみた。
UUID生成コードの実装例1
class UUID {
static #uuidIte = ( function* () {
const HEXOCTETS = Object.freeze( [ ...Array(256) ].map( ( e, i ) => i.toString( 16 ).padStart( 2, "0" ).toUpperCase() ) );
const VARSION = 0x40;
const VARIANT = 0x80;
for (;;) {
const bytes = crypto.getRandomValues( new Uint8Array( 16 ) );
yield "" +
HEXOCTETS[ bytes[ 0 ] ] +
HEXOCTETS[ bytes[ 1 ] ] +
HEXOCTETS[ bytes[ 2 ] ] +
HEXOCTETS[ bytes[ 3 ] ] + "-" +
HEXOCTETS[ bytes[ 4 ] ] +
HEXOCTETS[ bytes[ 5 ] ] + "-" +
HEXOCTETS[ bytes[ 6 ] & 0x0f | VARSION ] +
HEXOCTETS[ bytes[ 7 ] ] + "-" +
HEXOCTETS[ bytes[ 8 ] & 0x3f | VARIANT ] +
HEXOCTETS[ bytes[ 9 ] ] + "-" +
HEXOCTETS[ bytes[ 10 ] ] +
HEXOCTETS[ bytes[ 11 ] ] +
HEXOCTETS[ bytes[ 12 ] ] +
HEXOCTETS[ bytes[ 13 ] ] +
HEXOCTETS[ bytes[ 14 ] ] +
HEXOCTETS[ bytes[ 15 ] ];
}
} )();
static randomUUID() {
return this.#uuidIte.next().value;
}
}
consle.log( UUID.randomUUID() ); //xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
乱数はMath.random
でも取得できるが、暗号強度の面でcrypto.getRandomValues
を使用した方が安全である。
また、バイト列であるので表現も簡潔になる。
しかし、意外にもcrypto.getRandomValues
を使用している記事が下記しか見つからなかった。
恐らく暗号強度云々よりも「衝突の危険がないIDを簡便に生成したい」というケースがほとんどだと思われるので、Math.random
を使用したところで危険性が少ないのだろう。
下記にMath.random
を使用した実装例も記載する。
UUID生成コードの実装例2
class UUID {
static #uuidIte = ( function* () {
const HEXOCTETS = Object.freeze( [ ...Array(256) ].map( ( e, i ) => i.toString( 16 ).padStart( 2, "0" ).toUpperCase() ) );
const VARSION = 0x40;
const VARIANT = 0x80;
for (;;) {
const uint32 = new Uint32Array( 4 ).fill( Math.random() * 0x100000000 >>> 0 );
yield "" +
HEXOCTETS[ uint32[ 0 ] & 0xff ] +
HEXOCTETS[ uint32[ 0 ] >>> 8 & 0xff ] +
HEXOCTETS[ uint32[ 0 ] >>> 16 & 0xff ] +
HEXOCTETS[ uint32[ 0 ] >>> 24 & 0xff ] + "-" +
HEXOCTETS[ uint32[ 1 ] & 0xff ] +
HEXOCTETS[ uint32[ 1 ] >>> 8 & 0xff ] + "-" +
HEXOCTETS[ uint32[ 1 ] >>> 16 & 0x0f | VARSION ] +
HEXOCTETS[ uint32[ 1 ] >>> 24 & 0xff ] + "-" +
HEXOCTETS[ uint32[ 2 ] & 0x3f | VARIANT ] +
HEXOCTETS[ uint32[ 2 ] >>> 8 & 0xff ] + "-" +
HEXOCTETS[ uint32[ 2 ] >>> 16 & 0xff ] +
HEXOCTETS[ uint32[ 2 ] >>> 24 & 0xff ] +
HEXOCTETS[ uint32[ 3 ] & 0xff ] +
HEXOCTETS[ uint32[ 3 ] >>> 8 & 0xff ] +
HEXOCTETS[ uint32[ 3 ] >>> 16 & 0xff ] +
HEXOCTETS[ uint32[ 3 ] >>> 24 & 0xff ];
}
} )();
static randomUUID() {
return this.#uuidIte.next().value;
}
}
実行速度を比較するとcrypto.getRandomValues
よりMath.random
を用いた方が圧倒的に速い。
実行環境によっても変わってくるだろうが、仕様を考えるとどの環境も概ね同じ結果になるのではないだろうか。