From 8f3840d9724865c2a1ca1602512b04d365564fc7 Mon Sep 17 00:00:00 2001 From: Joe Wreschnig Date: Sat, 31 Jul 2021 20:18:18 +0200 Subject: [PATCH] Add `ReadRandom` and reimplement `NewRandomFromReader` using it Combined with e.g. `bufio.Reader` this provides fast zero-allocation UUID generation if you do not consider heap memory particularly sensitive, without a global state or lock. --- uuid_test.go | 14 ++++++++++++++ version4.go | 16 +++++++++++++--- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/uuid_test.go b/uuid_test.go index e98d0fe..c47e827 100644 --- a/uuid_test.go +++ b/uuid_test.go @@ -5,6 +5,7 @@ package uuid import ( + "bufio" "bytes" "fmt" "os" @@ -700,3 +701,16 @@ func BenchmarkUUID_NewPooled(b *testing.B) { } }) } + +func BenchmarkUUID_BufioReadRandom(b *testing.B) { + b.RunParallel(func(pb *testing.PB) { + r := bufio.NewReaderSize(rander, randPoolSize) + var uuid UUID + for pb.Next() { + err := ReadRandom(r, &uuid) + if err != nil { + b.Fatal(err) + } + } + }) +} diff --git a/version4.go b/version4.go index 7697802..36bc72f 100644 --- a/version4.go +++ b/version4.go @@ -38,7 +38,8 @@ func NewString() string { // year and having one duplicate. func NewRandom() (UUID, error) { if !poolEnabled { - return NewRandomFromReader(rander) + var uuid UUID + return uuid, ReadRandom(rander, &uuid) } return newRandomFromPool() } @@ -46,13 +47,22 @@ func NewRandom() (UUID, error) { // NewRandomFromReader returns a UUID based on bytes read from a given io.Reader. func NewRandomFromReader(r io.Reader) (UUID, error) { var uuid UUID + return uuid, ReadRandom(r, &uuid) +} + +// ReadRandom fills a random (version 4) UUID based on bytes read from a +// given io.Reader. When combined with e.g. a bufio.Reader, this is an +// efficient way to generate many UUIDs quickly. +// +// If an error was returned, the UUID may still be modified. +func ReadRandom(r io.Reader, uuid *UUID) error { _, err := io.ReadFull(r, uuid[:]) if err != nil { - return Nil, err + return err } uuid[6] = (uuid[6] & 0x0f) | 0x40 // Version 4 uuid[8] = (uuid[8] & 0x3f) | 0x80 // Variant is 10 - return uuid, nil + return nil } func newRandomFromPool() (UUID, error) {