{-# OPTIONS_GHC -funbox-strict-fields -ddump-simpl-stats -O2 #-}
{-  -dverbose-core2core -}
module Main (main) where

import qualified Data.StorableVector.Lazy as SV
import qualified Data.StorableVector.Lazy.Pointer as Pointer

import Data.Tuple.HT (mapFst, )
import Control.Monad (liftM, liftM2, )

import Data.Int (Int16)
import Foreign.Storable (Storable)

import Prelude hiding (zipWith, )


{-# INLINE zipWith #-}
zipWith :: (Storable a, Storable b, Storable c) =>
      (a -> b -> c)
   -> SV.Vector a
   -> SV.Vector b
   -> SV.Vector c
zipWith f =
   SV.crochetL (\y -> liftM (mapFst (flip f y)) . SV.viewL)


{-# INLINE zipWithPointer #-}
zipWithPointer :: (Storable a, Storable b, Storable c) =>
      (a -> b -> c)
   -> SV.Vector a
   -> SV.Vector b
   -> SV.Vector c
zipWithPointer f =
   SV.crochetL (\y -> liftM (mapFst (flip f y)) . Pointer.viewL)
    . Pointer.cons


{-# INLINE zipWithSize #-}
zipWithSize :: (Storable a, Storable b, Storable c) =>
      SV.ChunkSize
   -> (a -> b -> c)
   -> SV.Vector a
   -> SV.Vector b
   -> SV.Vector c
zipWithSize size f =
   curry (SV.unfoldr size (\(xt,yt) ->
      liftM2
         (\(x,xs) (y,ys) -> (f x y, (xs,ys)))
         (SV.viewL xt)
         (SV.viewL yt)))

{-# INLINE zipWithPointerSize #-}
zipWithPointerSize :: (Storable a, Storable b, Storable c) =>
      SV.ChunkSize
   -> (a -> b -> c)
   -> SV.Vector a
   -> SV.Vector b
   -> SV.Vector c
zipWithPointerSize size f a0 b0 =
   SV.unfoldr size (\(xt,yt) ->
      liftM2
         (\(x,xs) (y,ys) -> (f x y, (xs,ys)))
         (Pointer.viewL xt)
         (Pointer.viewL yt))
      (Pointer.cons a0, Pointer.cons b0)


main :: IO ()
main =
   print $
   SV.foldl' (+) 0 $
   SV.take 10000000 $
   (case (1::Int) of
      0 -> zipWith (+)
      1 -> zipWithPointer (+)
      2 -> zipWithSize SV.defaultChunkSize (+)
      3 -> zipWithPointerSize SV.defaultChunkSize (+)
      _ -> error "invalid choice")
         (SV.iterate SV.defaultChunkSize (subtract 1) 0)
         (SV.iterate SV.defaultChunkSize (1+) (1::Int16))
