Skip to content

Instantly share code, notes, and snippets.

@asterite
Created January 14, 2016 00:10
Show Gist options
  • Select an option

  • Save asterite/f62922ac47a2b91899d7 to your computer and use it in GitHub Desktop.

Select an option

Save asterite/f62922ac47a2b91899d7 to your computer and use it in GitHub Desktop.
# to_unsafe AND avoid creating Chars
class URL
property scheme, path, host
property non_relative_flag
end
class Parser
property url
SPECIAL_SCHEME = Set{"ftp", "file", "gopher", "http", "https", "ws", "wss"}
# https://url.spec.whatwg.org/
def initialize(input)
@url = URL.new
@input = input.to_unsafe
@state = :scheme_start
# @buffer = MemoryIO.new
@at_flag = false
@bracket_flag = false
@ptr = 0
end
def c
@input[@ptr]
end
def run
parse_scheme_start
end
def special_scheme?
SPECIAL_SCHEME.includes? url.scheme
end
def parse_scheme_start
if alpha?
parse_scheme
else
# Nothing
end
end
def alpha?
('a'.ord <= c && c <= 'z'.ord) ||
('A'.ord <= c && c <= 'Z'.ord)
end
def parse_scheme
start = @ptr
while true
if alpha? || c === '-' || c === '.' || c === '+'
# @buffer << c.chr
@ptr += 1
elsif c === ':'
@url.scheme = String.new(@input + start, @ptr - start)
# todo file and other special cases
if @input[@ptr + 1] === '/'
# @state = :path_or_authority
@ptr += 1
parse_path_or_authority
break
else
@url.non_relative_flag = true
@url.path = ""
parse_non_relative_path
# @state = :non_relative_path
end
else
# Nothing
break
# @state = :no_scheme
# @ptr = 0
# break
end
end
end
def parse_path_or_authority
if c === '/'
@ptr += 1
parse_authority
else
parse_path
end
end
def parse_authority
while true
if c === '@'
# todo
elsif c === '\0' || c === '/' || c === '?' || c === '#' || (special_scheme? && c === '\\')
@ptr += 1
parse_host
break
end
@ptr += 1
end
end
def parse_host
bracket_flag = false
start = @ptr
while true
if c === ':' && !bracket_flag
# todo if url is special and buffer empty fail
# url.host = @buffer.to_s
# reset_buffer
parse_port
break
elsif c === '\0' || c === '/' || c === '?' || c === '#' || (special_scheme? && c === '\\')
@url.host = String.new(@input + start, @ptr - start)
@ptr -= 1
# todo if url is special and buffer empty fail
# todo host parsing buffer
parse_path
break
else
bracket_flag = true if c == '['.ord
bracket_flag = false if c == ']'.ord
end
@ptr += 1
end
end
def parse_port
end
def parse_path
end
def parse_non_relative_path
end
end
require "benchmark"
require "uri"
par = Parser.new("http://bitfission.com")
par.run
puts [par.url.scheme, par.url.host]
uri = URI.parse("http://bitfission.com")
puts [uri.scheme, uri.host]
Benchmark.ips do |x|
x.report("new") { Parser.new("http://bitfission.com").run }
x.report("old") { URI.parse("http://bitfission.com") }
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment