Created
November 6, 2018 04:39
-
-
Save jgaskins/4a408897edb990b4134212790f5b9dc5 to your computer and use it in GitHub Desktop.
Optimizing UUID generation from strings in Crystal
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require "uuid" | |
require "benchmark" | |
struct UUID | |
def self.optimized(value : String, variant = nil, version = nil) | |
bytes = uninitialized UInt8[16] | |
case value.size | |
when 36 # Hyphenated | |
{8, 13, 18, 23}.each do |offset| | |
if value[offset] != '-' | |
raise ArgumentError.new "Invalid UUID string format, expected hyphen at char #{offset}" | |
end | |
end | |
{0, 2, 4, 6, 9, 11, 14, 16, 19, 21, 24, 26, 28, 30, 32, 34}.each_with_index do |offset, i| | |
optimized_string_has_hex_pair_at! value, offset | |
bytes[i] = (value[offset].to_u8(16) * 16) + value[offset + 1].to_u8(16) | |
end | |
when 32 # Hexstring | |
16.times do |i| | |
optimized_string_has_hex_pair_at! value, i * 2 | |
bytes[i] = (value[i * 2].to_u8(16) * 16) + value[i * 2 + 1].to_u8(16) | |
end | |
when 45 # URN | |
raise ArgumentError.new "Invalid URN UUID format, expected string starting with \"urn:uuid:\"" unless value.starts_with? "urn:uuid:" | |
{9, 11, 13, 15, 18, 20, 23, 25, 28, 30, 33, 35, 37, 39, 41, 43}.each_with_index do |offset, i| | |
optimized_string_has_hex_pair_at! value, offset | |
bytes[i] = (value[offset].to_u8(16) * 16) + value[offset + 1].to_u8(16) | |
end | |
else | |
raise ArgumentError.new "Invalid string length #{value.size} for UUID, expected 32 (hexstring), 36 (hyphenated) or 45 (urn)" | |
end | |
new(bytes, variant, version) | |
end | |
private def self.optimized_string_has_hex_pair_at!(value : String, i) | |
unless value[i].to_u8?(16) && value[i + 1].to_u8?(16) | |
raise ArgumentError.new [ | |
"Invalid hex character at position #{i * 2} or #{i * 2 + 1}", | |
"expected '0' to '9', 'a' to 'f' or 'A' to 'F'", | |
].join(", ") | |
end | |
end | |
end | |
string = UUID.random.to_s | |
# Sanity check to ensure they're correct | |
puts UUID.new(string) | |
puts UUID.optimized(string) | |
Benchmark.ips do |x| | |
x.report("string") { UUID.new(string) } | |
x.report("optimized") { UUID.optimized(string) } | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment