{-# LANGUAGE ForeignFunctionInterface #-}
module Synthesizer.LLVM.Storable.LazySizeIterator where

import qualified Numeric.NonNegative.Chunky  as Chunky
import qualified Data.StorableVector.Lazy.Pattern as SVP
import qualified Data.StorableVector.Lazy as SVL

import Data.Word (Word)

import Foreign.StablePtr (StablePtr, newStablePtr, freeStablePtr, deRefStablePtr)
import Foreign.Ptr (FunPtr)
import Data.IORef (IORef, newIORef, readIORef, writeIORef)
import qualified Data.List.HT as ListHT


newtype T = Cons (IORef [SVL.ChunkSize])

{-
For problems about Storable constraint, see ChunkIterator.
-}
foreign import ccall "&nextSize"
   nextCallBack :: FunPtr (StablePtr T -> IO Word)

foreign export ccall "nextSize"
   next :: StablePtr T -> IO Word


new :: SVP.LazySize -> IO (StablePtr T)
new ls =
   newStablePtr . Cons =<< newIORef (Chunky.toChunks (Chunky.normalize ls))

dispose :: StablePtr T -> IO ()
dispose = freeStablePtr

{- |
Zero pieces are filtered out.
If 'next' returns 0 then the end of the lazy size is reached.
-}
next :: StablePtr T -> IO Word
next stable =
   deRefStablePtr stable >>= \state ->
   case state of
      Cons listRef ->
         readIORef listRef >>=
         ListHT.switchL
            (return 0)
            (\(SVL.ChunkSize time) xs ->
               writeIORef listRef xs >>
               return (fromIntegral time))