diff --git a/sttp/guid/Guid.go b/sttp/guid/Guid.go index 9d8a3ad..04138f0 100644 --- a/sttp/guid/Guid.go +++ b/sttp/guid/Guid.go @@ -24,6 +24,7 @@ package guid import ( + "encoding/binary" "errors" "strconv" @@ -43,23 +44,17 @@ func New() Guid { // IsZero determines if the Guid value is its zero value, i.e., empty. func (g Guid) IsZero() bool { - return Equal(g, Empty) + return g == Empty } // Equal returns true if this Guid and other Guid values are equal. func (g Guid) Equal(other Guid) bool { - return Equal(g, other) + return g == other } // Equal returns true if the a and b Guid values are equal. func Equal(a, b Guid) bool { - for i := 0; i < 16; i++ { - if a[i] != b[i] { - return false - } - } - - return true + return a == b } // Compare returns an integer comparing this Guid (g) to other Guid. The result will be 0 if g==other, -1 if this g < other, and +1 if g > other. @@ -103,18 +98,10 @@ func result(left, right uint32) int { // Components gets the Guid value as its constituent components. func (g Guid) Components() (a uint32, b, c uint16, d [8]byte) { - a = (uint32(g[0]) << 24) | (uint32(g[1]) << 16) | (uint32(g[2]) << 8) | uint32(g[3]) - b = uint16((uint32(g[4]) << 8) | uint32(g[5])) - c = uint16((uint32(g[6]) << 8) | uint32(g[7])) - d[0] = g[8] - d[1] = g[9] - d[2] = g[10] - d[3] = g[11] - d[4] = g[12] - d[5] = g[13] - d[6] = g[14] - d[7] = g[15] - + a = binary.BigEndian.Uint32(g[:4]) + b = binary.BigEndian.Uint16(g[4:6]) + c = binary.BigEndian.Uint16(g[6:8]) + copy(d[:], g[8:16]) return } @@ -143,9 +130,7 @@ func FromBytes(data []byte, swapEndianness bool) (Guid, error) { swapGuidEndianness(&data) } - var g Guid - copy(g[:], data[:16]) - return g, nil + return Guid(data), nil } // ToBytes creates a byte slice from a Guid. diff --git a/sttp/guid/Guid_test.go b/sttp/guid/Guid_test.go index 775c061..71bbea4 100644 --- a/sttp/guid/Guid_test.go +++ b/sttp/guid/Guid_test.go @@ -25,8 +25,8 @@ package guid import ( "bytes" - "strconv" "testing" + "unsafe" ) const ( @@ -39,7 +39,7 @@ const ( gsz string = "{00000000-0000-0000-0000-000000000000}" ) -//gocyclo: ignore +// gocyclo: ignore func TestGuidParsing(t *testing.T) { var g1, g2, g3, g4 Guid var err error @@ -113,12 +113,12 @@ func TestGuidParsing(t *testing.T) { func TestNewGuidRandomness(t *testing.T) { for i := 0; i < 10000; i++ { if New().Equal(New()) || Equal(New(), New()) { - t.Fatalf("TestNewGuidRandomness: encountered non-unique Guid after " + strconv.Itoa(i*4) + "generations") + t.Fatalf("TestNewGuidRandomness: encountered non-unique Guid after %d generations", i*4) } } } -//gocyclo: ignore +// gocyclo: ignore func TestZeroGuid(t *testing.T) { var gz, zero Guid var err error @@ -166,7 +166,7 @@ func TestZeroGuid(t *testing.T) { } } -//gocyclo: ignore +// gocyclo: ignore func TestGuidCompare(t *testing.T) { var g1, g2, g3, g4, g5, g6 Guid var err error @@ -296,16 +296,113 @@ func testGuidToFromBytes(g Guid, gs string, swapEndianness bool, t *testing.T) { } if !bytes.Equal(gbf, gbs) { - t.Fatalf("TestGuidToFromBytes: ToBytes test compare failed for guid " + gs) + t.Fatal("TestGuidToFromBytes: ToBytes test compare failed for guid " + gs) } g1fb, err := FromBytes(gbf, swapEndianness) if err != nil { - t.Fatalf("TestGuidToFromBytes: FromBytes failed for guid " + gs) + t.Fatal("TestGuidToFromBytes: FromBytes failed for guid " + gs) } if !g1fb.Equal(g) { - t.Fatalf("TestGuidToFromBytes: FromBytes test compare failed for guid " + gs) + t.Fatal("TestGuidToFromBytes: FromBytes test compare failed for guid " + gs) + } +} + +func (g Guid) EqualIndirectBaseline(other Guid) bool { + return EqualBaseline(g, other) +} + +func (g Guid) EqualIndirect(other Guid) bool { + return Equal(g, other) +} + +func EqualBaseline(a, b Guid) bool { + for k := range 16 { + if a[k] != b[k] { + return false + break + } + } + return true + +} + +func BenchmarkEqualityIndirect(b *testing.B) { + list := []string{gs1, gs2, gs3, gs4, gs5, gs6, gsz} + glist := [7]Guid{} + for i := range list { + glist[i], _ = Parse(list[i]) + } + b.ResetTimer() + for range b.N { + a, b := glist[0], glist[1] + equal := a.EqualIndirect(b) + _ = equal + } +} + +func BenchmarkEqualityIndirectBaseline(b *testing.B) { + list := []string{gs1, gs2, gs3, gs4, gs5, gs6, gsz} + glist := [7]Guid{} + for i := range list { + glist[i], _ = Parse(list[i]) + } + b.ResetTimer() + for range b.N { + a, b := glist[0], glist[1] + equal := a.EqualIndirectBaseline(b) + _ = equal + } +} + +func BenchmarkEqualityBaseline(b *testing.B) { + list := []string{gs1, gs2, gs3, gs4, gs5, gs6, gsz} + glist := [7]Guid{} + for i := range list { + glist[i], _ = Parse(list[i]) + } + b.ResetTimer() + for range b.N { + equal := true + a, b := glist[0], glist[1] + for k := range 16 { + if a[k] != b[k] { + equal = false + break + } + } + _ = equal + } +} + +func BenchmarkEqualityCurrent(b *testing.B) { + list := []string{gs1, gs2, gs3, gs4, gs5, gs6, gsz} + glist := [7]Guid{} + for i := range list { + glist[i], _ = Parse(list[i]) + } + b.ResetTimer() + for range b.N { + a1 := (*uint64)(unsafe.Pointer(&glist[0][0])) + a2 := (*uint64)(unsafe.Pointer(&glist[0][8])) + b1 := (*uint64)(unsafe.Pointer(&glist[1][0])) + b2 := (*uint64)(unsafe.Pointer(&glist[1][8])) + equal := *a1 == *b1 && *a2 == *b2 + _ = equal + } +} + +func BenchmarkEqualityDirect(b *testing.B) { + list := []string{gs1, gs2, gs3, gs4, gs5, gs6, gsz} + glist := [7]Guid{} + for i := range list { + glist[i], _ = Parse(list[i]) + } + b.ResetTimer() + for range b.N { + equal := glist[0] == glist[1] + _ = equal } }