Skip to content

Commit

Permalink
perf: reduce unnecessary allocations in NewSHA1 and NewMD5
Browse files Browse the repository at this point in the history
  • Loading branch information
anatoly-kussul committed Jan 6, 2025
1 parent 2d3c2a9 commit c51a5ff
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 15 deletions.
40 changes: 25 additions & 15 deletions hash.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,32 +28,42 @@ var (
// NewHash returns a new UUID derived from the hash of space concatenated with
// data generated by h. The hash should be at least 16 byte in length. The
// first 16 bytes of the hash are used to form the UUID. The version of the
// UUID will be the lower 4 bits of version. NewHash is used to implement
// NewMD5 and NewSHA1.
// UUID will be the lower 4 bits of version.
func NewHash(h hash.Hash, space UUID, data []byte, version int) UUID {
h.Reset()
h.Write(space[:]) //nolint:errcheck
h.Write(data) //nolint:errcheck
s := h.Sum(nil)
var uuid UUID
copy(uuid[:], s)
uuid[6] = (uuid[6] & 0x0f) | uint8((version&0xf)<<4)
uuid[8] = (uuid[8] & 0x3f) | 0x80 // RFC 9562 variant
return uuid
return fromHash(s, version)
}

// NewMD5 returns a new MD5 (Version 3) UUID based on the
// supplied name space and data. It is the same as calling:
//
// NewHash(md5.New(), space, data, 3)
// supplied name space and data.
func NewMD5(space UUID, data []byte) UUID {
return NewHash(md5.New(), space, data, 3)
h := md5.New()
h.Write(space[:]) //nolint:errcheck
h.Write(data) //nolint:errcheck
s := h.Sum(make([]byte, 0, md5.Size))
return fromHash(s, 3)
}

// NewSHA1 returns a new SHA1 (Version 5) UUID based on the
// supplied name space and data. It is the same as calling:
//
// NewHash(sha1.New(), space, data, 5)
// supplied name space and data.
func NewSHA1(space UUID, data []byte) UUID {
return NewHash(sha1.New(), space, data, 5)
h := sha1.New()
h.Write(space[:]) //nolint:errcheck
h.Write(data) //nolint:errcheck
s := h.Sum(make([]byte, 0, sha1.Size))
return fromHash(s, 5)
}

// fromHash creates a new UUID from a byte slice.
// Slice should be at least 16 byte in length.
// The first 16 bytes of the hash are used to form the UUID.
// The version of the UUID will be the lower 4 bits of version.
func fromHash(s []byte, version int) (uuid UUID) {
copy(uuid[:], s)
uuid[6] = (uuid[6] & 0x0f) | uint8((version&0xf)<<4)
uuid[8] = (uuid[8] & 0x3f) | 0x80 // RFC 4122 variant
return uuid
}
12 changes: 12 additions & 0 deletions uuid_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,12 @@ func TestMD5(t *testing.T) {
}
}

func BenchmarkMD5(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = NewMD5(NameSpaceDNS, []byte("python.org"))
}
}

func TestSHA1(t *testing.T) {
uuid := NewSHA1(NameSpaceDNS, []byte("python.org")).String()
want := "886313e1-3b8a-5372-9b90-0c9aee199e5d"
Expand All @@ -422,6 +428,12 @@ func TestSHA1(t *testing.T) {
}
}

func BenchmarkSHA1(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = NewSHA1(NameSpaceDNS, []byte("python.org"))
}
}

func TestNodeID(t *testing.T) {
nid := []byte{1, 2, 3, 4, 5, 6}
SetNodeInterface("")
Expand Down

0 comments on commit c51a5ff

Please sign in to comment.