Skip to content

Instantly share code, notes, and snippets.

@brianrourkeboll
Created December 7, 2023 18:02
Show Gist options
  • Save brianrourkeboll/c76c868ece9e512b427b6b708142450a to your computer and use it in GitHub Desktop.
Save brianrourkeboll/c76c868ece9e512b427b6b708142450a to your computer and use it in GitHub Desktop.
open System
open BenchmarkDotNet.Attributes
open BenchmarkDotNet.Running
type token =
| DOT_DOT
| DOT
| RBRACK
| MINUS
| QMARK_QMARK
| QMARK
| COLON_EQUALS
| COLON_COLON
| STAR
| START
| AMP
| RARROW
| LARROW
| EQUALS
| LESS of bool
| DOLLAR
| PERCENT_OP of string
| INFIX_COMPARE_OP of string
| INFIX_AMP_OP of string
| INFIX_BAR_OP of string
| PREFIX_OP of string
| INFIX_AT_HAT_OP of string
| PLUS_MINUS_OP of string
| INFIX_STAR_STAR_OP of string
| INFIX_STAR_DIV_MOD_OP of string
| GREATER of bool
module Option =
let (|TyparsCloseOp|_|) (txt: string) =
let angles = txt |> Seq.takeWhile (fun c -> c = '>') |> Seq.toList
let afterAngles = txt |> Seq.skipWhile (fun c -> c = '>') |> Seq.toList
if List.isEmpty angles then None else
let afterOp =
match (System.String(Array.ofSeq afterAngles)) with
| "." -> Some DOT
| "]" -> Some RBRACK
| "-" -> Some MINUS
| ".." -> Some DOT_DOT
| "?" -> Some QMARK
| "??" -> Some QMARK_QMARK
| ":=" -> Some COLON_EQUALS
| "::" -> Some COLON_COLON
| "*" -> Some STAR
| "&" -> Some AMP
| "->" -> Some RARROW
| "<-" -> Some LARROW
| "=" -> Some EQUALS
| "<" -> Some (LESS false)
| "$" -> Some DOLLAR
| "%" -> Some (PERCENT_OP("%") )
| "%%" -> Some (PERCENT_OP("%%"))
| "" -> None
| s ->
match List.ofSeq afterAngles with
| '=' :: _
| '!' :: '=' :: _
| '<' :: _
| '>' :: _
| '$' :: _ -> Some (INFIX_COMPARE_OP s)
| '&' :: _ -> Some (INFIX_AMP_OP s)
| '|' :: _ -> Some (INFIX_BAR_OP s)
| '!' :: _
| '?' :: _
| '~' :: _ -> Some (PREFIX_OP s)
| '@' :: _
| '^' :: _ -> Some (INFIX_AT_HAT_OP s)
| '+' :: _
| '-' :: _ -> Some (PLUS_MINUS_OP s)
| '*' :: '*' :: _ -> Some (INFIX_STAR_STAR_OP s)
| '*' :: _
| '/' :: _
| '%' :: _ -> Some (INFIX_STAR_DIV_MOD_OP s)
| _ -> None
Some([| for _c in angles do yield GREATER |], afterOp)
module ValueOption =
[<return: Struct>]
let (|TyparsCloseOp|_|) (txt: string) =
let angles = txt |> Seq.takeWhile (fun c -> c = '>') |> Seq.toList
let afterAngles = txt |> Seq.skipWhile (fun c -> c = '>') |> Seq.toList
if List.isEmpty angles then ValueNone else
let afterOp =
match (System.String(Array.ofSeq afterAngles)) with
| "." -> ValueSome DOT
| "]" -> ValueSome RBRACK
| "-" -> ValueSome MINUS
| ".." -> ValueSome DOT_DOT
| "?" -> ValueSome QMARK
| "??" -> ValueSome QMARK_QMARK
| ":=" -> ValueSome COLON_EQUALS
| "::" -> ValueSome COLON_COLON
| "*" -> ValueSome STAR
| "&" -> ValueSome AMP
| "->" -> ValueSome RARROW
| "<-" -> ValueSome LARROW
| "=" -> ValueSome EQUALS
| "<" -> ValueSome (LESS false)
| "$" -> ValueSome DOLLAR
| "%" -> ValueSome (PERCENT_OP("%") )
| "%%" -> ValueSome (PERCENT_OP("%%"))
| "" -> ValueNone
| s ->
match List.ofSeq afterAngles with
| '=' :: _
| '!' :: '=' :: _
| '<' :: _
| '>' :: _
| '$' :: _ -> ValueSome (INFIX_COMPARE_OP s)
| '&' :: _ -> ValueSome (INFIX_AMP_OP s)
| '|' :: _ -> ValueSome (INFIX_BAR_OP s)
| '!' :: _
| '?' :: _
| '~' :: _ -> ValueSome (PREFIX_OP s)
| '@' :: _
| '^' :: _ -> ValueSome (INFIX_AT_HAT_OP s)
| '+' :: _
| '-' :: _ -> ValueSome (PLUS_MINUS_OP s)
| '*' :: '*' :: _ -> ValueSome (INFIX_STAR_STAR_OP s)
| '*' :: _
| '/' :: _
| '%' :: _ -> ValueSome (INFIX_STAR_DIV_MOD_OP s)
| _ -> ValueNone
ValueSome([| for _c in angles do yield GREATER |], afterOp)
module Simplified =
[<return: Struct>]
let (|Equals|_|) (s: string) (span: ReadOnlySpan<char>) =
if span.SequenceEqual(s.AsSpan()) then ValueSome Equals
else ValueNone
[<return: Struct>]
let (|StartsWith|_|) (s: string) (span: ReadOnlySpan<char>) =
if span.StartsWith(s.AsSpan()) then ValueSome StartsWith
else ValueNone
[<return: Struct>]
let (|TyparsCloseOp|_|) (txt: string) =
let angles = txt.AsSpan().IndexOfAnyExcept '>'
if angles < 0 then ValueNone else
let afterAngles = txt.AsSpan angles
let afterOp =
match afterAngles with
| Equals "." -> ValueSome DOT
| Equals "]" -> ValueSome RBRACK
| Equals "-" -> ValueSome MINUS
| Equals ".." -> ValueSome DOT_DOT
| Equals "?" -> ValueSome QMARK
| Equals "??" -> ValueSome QMARK_QMARK
| Equals ":=" -> ValueSome COLON_EQUALS
| Equals "::" -> ValueSome COLON_COLON
| Equals "*" -> ValueSome STAR
| Equals "&" -> ValueSome AMP
| Equals "->" -> ValueSome RARROW
| Equals "<-" -> ValueSome LARROW
| Equals "=" -> ValueSome EQUALS
| Equals "<" -> ValueSome (LESS false)
| Equals "$" -> ValueSome DOLLAR
| Equals "%" -> ValueSome (PERCENT_OP "%")
| Equals "%%" -> ValueSome (PERCENT_OP "%%")
| StartsWith "="
| StartsWith "!="
| StartsWith "<"
| StartsWith ">"
| StartsWith "$" -> ValueSome (INFIX_COMPARE_OP (afterAngles.ToString()))
| StartsWith "&" -> ValueSome (INFIX_AMP_OP (afterAngles.ToString()))
| StartsWith "|" -> ValueSome (INFIX_BAR_OP (afterAngles.ToString()))
| StartsWith "!"
| StartsWith "?"
| StartsWith "~" -> ValueSome (PREFIX_OP (afterAngles.ToString()))
| StartsWith "@"
| StartsWith "^" -> ValueSome (INFIX_AT_HAT_OP (afterAngles.ToString()))
| StartsWith "+"
| StartsWith "-" -> ValueSome (PLUS_MINUS_OP (afterAngles.ToString()))
| StartsWith "**" -> ValueSome (INFIX_STAR_STAR_OP (afterAngles.ToString()))
| StartsWith "*"
| StartsWith "/"
| StartsWith "%" -> ValueSome (INFIX_STAR_DIV_MOD_OP (afterAngles.ToString()))
| _ -> ValueNone
ValueSome(Array.init angles (fun _ -> GREATER), afterOp)
[<MemoryDiagnoser>]
type Benchmarks () =
[<Params(">=", ">>>>>>>>>>>>>>:=", ">>>!=*+-%^@@@@.........")>]
member val Input : string = null with get, set
[<Benchmark(Baseline = true)>]
member this.Option () = match this.Input with Option.TyparsCloseOp _ | _ -> ()
[<Benchmark>]
member this.ValueOption () = match this.Input with ValueOption.TyparsCloseOp _ | _ -> ()
[<Benchmark>]
member this.Simplified () = match this.Input with Simplified.TyparsCloseOp _ | _ -> ()
ignore (BenchmarkRunner.Run<Benchmarks> ())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment