Last active
September 12, 2016 23:30
-
-
Save manofstick/6467b5b16714209750739b68d7a911bd to your computer and use it in GitHub Desktop.
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
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