Skip to content

Instantly share code, notes, and snippets.

@manofstick
Last active September 12, 2016 23:30
Show Gist options
  • Save manofstick/6467b5b16714209750739b68d7a911bd to your computer and use it in GitHub Desktop.
Save manofstick/6467b5b16714209750739b68d7a911bd to your computer and use it in GitHub Desktop.
open System.Collections.Generic
let validate = false
#if FROM_MAX
let lowerBound = System.Int32.MaxValue - 100000000
let upperBound = System.Int32.MaxValue
#else
#if FROM_MIN
let lowerBound = System.Int32.MinValue
let upperBound = System.Int32.MinValue + 100000000
#else
#if FULL_RANGE
let lowerBound = // System.Int32.MinValue
let upperBound = System.Int32.MaxValue
#else
let lowerBound = -100000000
let upperBound = 100000000
#endif
#endif
#endif
type private PricePointIteratorStates =
| PreMoveNext = 0
| MoveNext = 1
| PostMoveNext = 2
| InvalidCurrent = 3
type internal PricePointIterator () =
let mutable _state = PricePointIteratorStates.PreMoveNext
let mutable _idx = Unchecked.defaultof<_>
let mutable _current = Unchecked.defaultof<int>
member private __.setNextState next =
_state <- next
member private __.gotoState next =
__.setNextState next
__.executeState ()
member private this.state_pre_move_next () =
_idx <- lowerBound - 1
_current <- Unchecked.defaultof<_>
this.gotoState PricePointIteratorStates.MoveNext
member private this.state_move_next () =
_idx <- _idx + 1
let mutable found = _idx % 3 = 0
let mutable complete = _idx = upperBound
while not found && not complete do
_idx <- _idx + 1
found <- _idx % 3 = 0
complete <- _idx = upperBound
if found then
_current <- _idx
if complete then
this.setNextState PricePointIteratorStates.PostMoveNext
found
member private this.state_post_move_next () =
_current <- Unchecked.defaultof<_>
this.gotoState PricePointIteratorStates.InvalidCurrent
member private __.state_invalid_current () =
_current <- Unchecked.defaultof<_>
false
member private __.executeState () =
match _state with
| PricePointIteratorStates.PreMoveNext -> __.state_pre_move_next ()
| PricePointIteratorStates.MoveNext -> __.state_move_next ()
| PricePointIteratorStates.PostMoveNext -> __.state_post_move_next ()
| PricePointIteratorStates.InvalidCurrent -> __.state_invalid_current ()
| _ -> failwith "invalid state"
interface System.Collections.IEnumerator with
member __.Current =
// As per https://msdn.microsoft.com/en-us/library/system.collections.ienumerator.current%28v=vs.110%29.aspx
// i.e. Current can throw an exception if called after MoveNext returns false
match _state with
| PricePointIteratorStates.InvalidCurrent -> raise (System.InvalidOperationException ())
| _ -> box _current
member this.MoveNext () =
this.executeState ()
member __.Reset () =
failwith "No reset"
interface System.IDisposable with
member __.Dispose () = ()
interface System.Collections.Generic.IEnumerator<int> with
member __.Current =
// As per https://msdn.microsoft.com/en-us/library/58e146b7(v=vs.110).aspx
// i.e. Current always returned, it is just undefined in some states
_current
[<EntryPoint>]
let main argv =
let s = seq {
for i = lowerBound to upperBound do
if i % 3 = 0 then yield i }
let t = { new System.Collections.Generic.IEnumerable<int> with
member x.GetEnumerator(): IEnumerator<int> = upcast (new PricePointIterator ())
member x.GetEnumerator(): System.Collections.IEnumerator = upcast (new PricePointIterator ()) }
if validate then
printfn "\nvalidating..."
let s' = s |> Seq.toList
let t' = t |> Seq.toList
if s' <> t' then
printfn "--> failed :-("
else
printfn "--> success :-)"
printfn "\ntiming..."
let sw = System.Diagnostics.Stopwatch.StartNew ()
let sLength = s |> Seq.length
printfn "seq time = %dms (count=%d)" sw.ElapsedMilliseconds sLength
let sw = System.Diagnostics.Stopwatch.StartNew ()
let tLength = t |> Seq.length
printfn "manual state machine time = %dms (count=%d)" sw.ElapsedMilliseconds tLength
0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment