Skip to content

Commit

Permalink
Use .EqualFold() to parse urn prefixed UUIDs
Browse files Browse the repository at this point in the history
Prior to this commit we used a comparison with the result of ToLower()
to test for a "urn:uuid" prefix in both UUID strings and byte slices.

This commit replaces the ToLower and string comparison with both
strings.EqualFold() and bytes.EqualFold().

This reduces the CPU time across the board for UUIDs that start with
"urn:uuid" and eliminates some allocations when parsing bytes.

The benchmark output was generated by adding "urn:uuid" to the test
input.

goos: linux
goarch: amd64
pkg: github.com/google/uuid
cpu: Intel(R) Core(TM) i7-10510U CPU @ 1.80GHz
                      │ /tmp/output1 │             /tmp/output2              │
                      │    sec/op    │    sec/op     vs base                 │
Parse-8                 35.87n ± ∞ ¹   33.75n ± ∞ ¹        ~ (p=1.000 n=1) ²
ParseBytes-8            65.10n ± ∞ ¹   35.56n ± ∞ ¹        ~ (p=1.000 n=1) ²
ParseBytesUnsafe-8      35.31n ± ∞ ¹   34.70n ± ∞ ¹        ~ (p=1.000 n=1) ²
ParseBytesCopy-8        78.01n ± ∞ ¹   61.21n ± ∞ ¹        ~ (p=1.000 n=1) ²
ParseBadLength-8        3.499n ± ∞ ¹   3.084n ± ∞ ¹        ~ (p=1.000 n=1) ²
ParseLen32Truncated-8   3.335n ± ∞ ¹   3.334n ± ∞ ¹        ~ (p=1.000 n=1) ²
ParseLen36Corrupted-8   63.02n ± ∞ ¹   58.26n ± ∞ ¹        ~ (p=1.000 n=1) ²
geomean                 24.11n         20.51n        -14.92%
¹ need >= 6 samples for confidence interval at level 0.95
² need >= 4 samples to detect a difference at alpha level 0.05

                      │ /tmp/output1 │           /tmp/output2           │
                      │     B/op     │    B/op      vs base             │
Parse-8                  0.000 ± ∞ ¹   0.000 ± ∞ ¹  ~ (p=1.000 n=1) ²
ParseBytes-8             16.00 ± ∞ ¹    0.00 ± ∞ ¹  ~ (p=1.000 n=1) ³
ParseBytesUnsafe-8       0.000 ± ∞ ¹   0.000 ± ∞ ¹  ~ (p=1.000 n=1) ²
ParseBytesCopy-8         48.00 ± ∞ ¹   48.00 ± ∞ ¹  ~ (p=1.000 n=1) ²
ParseBadLength-8         0.000 ± ∞ ¹   0.000 ± ∞ ¹  ~ (p=1.000 n=1) ²
ParseLen32Truncated-8    0.000 ± ∞ ¹   0.000 ± ∞ ¹  ~ (p=1.000 n=1) ²
ParseLen36Corrupted-8    16.00 ± ∞ ¹   16.00 ± ∞ ¹  ~ (p=1.000 n=1) ²
geomean                            ⁴                ?               ⁴ ⁵
¹ need >= 6 samples for confidence interval at level 0.95
² all samples are equal
³ need >= 4 samples to detect a difference at alpha level 0.05
⁴ summaries must be >0 to compute geomean
⁵ ratios must be >0 to compute geomean

                      │ /tmp/output1 │           /tmp/output2           │
                      │  allocs/op   │  allocs/op   vs base             │
Parse-8                  0.000 ± ∞ ¹   0.000 ± ∞ ¹  ~ (p=1.000 n=1) ²
ParseBytes-8             1.000 ± ∞ ¹   0.000 ± ∞ ¹  ~ (p=1.000 n=1) ³
ParseBytesUnsafe-8       0.000 ± ∞ ¹   0.000 ± ∞ ¹  ~ (p=1.000 n=1) ²
ParseBytesCopy-8         1.000 ± ∞ ¹   1.000 ± ∞ ¹  ~ (p=1.000 n=1) ²
ParseBadLength-8         0.000 ± ∞ ¹   0.000 ± ∞ ¹  ~ (p=1.000 n=1) ²
ParseLen32Truncated-8    0.000 ± ∞ ¹   0.000 ± ∞ ¹  ~ (p=1.000 n=1) ²
ParseLen36Corrupted-8    1.000 ± ∞ ¹   1.000 ± ∞ ¹  ~ (p=1.000 n=1) ²
geomean                            ⁴                ?               ⁴ ⁵
¹ need >= 6 samples for confidence interval at level 0.95
² all samples are equal
³ need >= 4 samples to detect a difference at alpha level 0.05
⁴ summaries must be >0 to compute geomean
⁵ ratios must be >0 to compute geomean
  • Loading branch information
ayang64 committed Aug 3, 2023
1 parent 44b5fee commit bcf1f91
Showing 1 changed file with 6 additions and 4 deletions.
10 changes: 6 additions & 4 deletions uuid.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ func Parse(s string) (UUID, error) {

// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
case 36 + 9:
if strings.ToLower(s[:9]) != "urn:uuid:" {
if !strings.EqualFold(s[:9], "urn:uuid:") {
return uuid, fmt.Errorf("invalid urn prefix: %q", s[:9])
}
s = s[9:]
Expand Down Expand Up @@ -101,7 +101,8 @@ func Parse(s string) (UUID, error) {
9, 11,
14, 16,
19, 21,
24, 26, 28, 30, 32, 34} {
24, 26, 28, 30, 32, 34,
} {
v, ok := xtob(s[x], s[x+1])
if !ok {
return uuid, errors.New("invalid UUID format")
Expand All @@ -117,7 +118,7 @@ func ParseBytes(b []byte) (UUID, error) {
switch len(b) {
case 36: // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
case 36 + 9: // urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
if !bytes.Equal(bytes.ToLower(b[:9]), []byte("urn:uuid:")) {
if !bytes.EqualFold(b[:9], []byte("urn:uuid:")) {
return uuid, fmt.Errorf("invalid urn prefix: %q", b[:9])
}
b = b[9:]
Expand Down Expand Up @@ -145,7 +146,8 @@ func ParseBytes(b []byte) (UUID, error) {
9, 11,
14, 16,
19, 21,
24, 26, 28, 30, 32, 34} {
24, 26, 28, 30, 32, 34,
} {
v, ok := xtob(b[x], b[x+1])
if !ok {
return uuid, errors.New("invalid UUID format")
Expand Down

0 comments on commit bcf1f91

Please sign in to comment.