(* -*- mode: sml -*-
 * $Id: methcall.smlnj,v 1.2 2001/07/09 00:25:28 doug Exp $
 * http://www.bagley.org/~doug/shootout/
 * from Stephen Weeks
 *)


structure Test : sig
    val main : (string * string list) -> OS.Process.status
end = struct

fun for (start, stop, f) =
   let
      fun loop i =
     if i > stop
        then ()
     else (f i; loop (i + 1))
   in
      loop start
   end

structure Toggle =
   struct
      datatype 'a t = T of {
                state: 'a ref,
                value: 'a t -> 'a,
                activate: 'a t -> 'a t
                }

      fun new state =
     T {state = ref state,
        value = fn T {state, ...} => !state,
        activate = fn this as T {state, ...} => (state := not(!state); this)}

      fun activate (this as T {activate, ...}) = activate this
      fun value (this as T {value, ...}) = value this
   end

structure Ntoggle =
   struct
      datatype 'a t = T of {
                state: 'a ref,
                value: 'a t -> 'a,
                activate: 'a t -> 'a t,
                countMax: int,
                counter: int ref
                }

      fun new (state, countMax) =
     T {
        state = ref state,
        value = fn T {state, ...} => !state,
        activate = (fn this as T {state, counter, countMax, ...} =>
            let
               val newCounter = 1 + !counter
               val _ = counter := newCounter
               val _ = 
                  if !counter >= countMax
                 then (state := not(!state);
                       counter := 0)
                  else ()
            in
               this
            end),
        countMax = countMax,
        counter = ref 0
        }

      fun activate (this as T {activate, ...}) = activate this
      fun value (this as T {value, ...}) = value this
   end

fun atoi s = case Int.fromString s of SOME num => num | NONE => 0
fun printl [] = print "\n" | printl(h::t) = ( print h ; printl t )
   
fun main (name, args) =
   let
      val n = atoi (hd (args @ ["1"]))
      val v = ref true
      val tog = Toggle.new true
      val _ = for (0, n - 1, fn _ => v := Toggle.value (Toggle.activate tog))
      val _ = print (if !v then "true\n" else "false\n")
      val _ = v := true
      val ntog = Ntoggle.new (!v, 3)
      val _ = for (0, n - 1, fn _ => v := Ntoggle.value (Ntoggle.activate ntog))
      val _ = print (if !v then "true\n" else "false\n")
   in
      OS.Process.success
   end
end

val _ = SMLofNJ.exportFn("methcall", Test.main);