
> module Main where

> import Data.IORef
> import Control.Concurrent
> --import Control.Concurrent.STM
> import System.Environment
> import Data.Time


> import MVarList


printing 

> printList :: Show a => ListHandle a -> IO ()
> printList (ListHandle {headList = ptrPtr}) =
>  do startptr <- (
>          do ptr <- readIORef ptrPtr
>             Head {next = startptr} <- readMVar ptr
>             return startptr)
>     printListHelp startptr


> printListHelp :: Show a => MVar (List a) -> IO ()
> printListHelp curNodePtr =
>   do { curNode <- readMVar curNodePtr
>      ; case curNode of
>          Null -> putStr "Nil"
>          Node {val = curval, next = curnext} ->
>             do { putStr (show curval  ++ " -> ")
>                ;  printListHelp curnext }
>          DelNode {val = curval, next = curnext} ->
>             do { putStr (show curval  ++ "DEAD -> ")
>                ;  printListHelp curnext }
>      } 

> cntList :: Show a => ListHandle a -> IO Int
> cntList (ListHandle {headList = ptrPtr}) =
>  do startptr <- (
>          do ptr <- readIORef ptrPtr
>             Head {next = startptr} <- readMVar ptr
>             return startptr)
>     cntListHelp startptr 0


> cntListHelp :: Show a => MVar (List a) -> Int -> IO Int
> cntListHelp curNodePtr i =
>   do { curNode <- readMVar curNodePtr
>      ; case curNode of
>          Null -> return i
>          Node {val = curval, next = curnext} -> 
>                cntListHelp curnext (i+1)
>          DelNode {val = curval, next = curnext} ->
>                cntListHelp curnext (i+1)
>      } 


create List

> createList :: Int -> IO (ListHandle Int)
> createList n =
>   do nl <- newList
>      mapM (addToTail nl) [1..n]
>      return nl


> data Op a = Find a | Insert a | Delete a deriving Show
        

> createTasks :: [a] -> [Op a]
> createTasks xs = task 1 xs
>   where
>     insCnt = 5   -- every 5th op is insert
>     delCnt = 9   -- ever 9th op is delete
>     task _ [] = []
>     task cnt (x:xs) 
>       | (cnt `mod` insCnt) == 0 = (Insert x) : task (cnt+1) xs
>       | (cnt `mod` delCnt) == 0 = (Delete x) : task (cnt+1) xs
>       | otherwise             = (Find x) : task (cnt+1) xs



mainly finds, some deletes which will be inserted again

> specificTask1 :: [a] -> [Op a]
> specificTask1 xs = task 1 xs []
>   where
>     delCnt = 5   -- every 6th op is delete
>     insCnt = 50   -- after 5 deletes we'll insert them again
>     task _ [] _ = []
>     task cnt (x:xs) deletes 
>       | length deletes == insCnt =  map Insert deletes ++ task (cnt+1) (x:xs) []
>       | (cnt `mod` delCnt) == 0 = (Delete x) : task (cnt+1) xs (x:deletes)
>       | otherwise             = (Find x) : task (cnt+1) xs deletes

> executeTasks :: Eq a => ListHandle a -> [Op a] -> IO ()
> executeTasks lh ops =
>  do mapM (\ task -> 
>           case task of
>              Find x -> do { find lh x; return () }
>              Insert x -> do { addToTail lh x; return () }
>              Delete x -> do { delete lh x; return () })
>          ops
>     return ()

  put number into threads buckets

> distribution :: [Int] -> Int -> [[Int]]
> distribution no threads =
>   let init = map (\ _ -> []) [1..threads]
>       go :: [Int] -> Int -> [[Int]] -> [[Int]]
>       go [] _ acc = acc
>       go (x:xs) cnt acc = 
>          let idx = cnt `mod` threads
>              acc' = take idx acc ++ [x : (acc !! idx)] ++ drop (idx+1) acc
>          in go xs (cnt+1) acc'
>  
>   in go no 1 init           

> insert :: Eq a => ListHandle a -> a -> IO ()
> insert = addToTail


runnable version

> main = mainPar

parallel version

> mainPar :: IO ()
> mainPar =
>  do let len = 3000
>     let threads = 4
>     nl <- createList len
>     let numbers = [1..len] ++ (reverse [1..len]) ++ [1..len] ++ (reverse [1..len])
>                   ++ [1..len] ++ (reverse [1..len]) ++ [1..len] ++ (reverse [1..len])
>     let [d1,d2,d3,d4] = distribution numbers threads
>     let t1 = d1++d2++d3++d4
>     let t2 = d2++d3++d4++d1
>     let t3 = d3++d4++d1++d2
>     let t4 = d4++d1++d2++d3
>     wait <- atomically (newTVar 0)
>     putStrLn "Start"
>     start <- getCurrentTime
>     mapM (\ t -> forkIO (do executeTasks nl (specificTask1 t)
>                             atomically(do counter <- readTVar wait
>                                           writeTVar wait (counter+1))))
>          [t1,t2,t3,t4]
>     atomically ( do counter <- readTVar wait
>                     if counter < 4 then retry 
>                      else return () )
>     fin <- getCurrentTime
>     putStrLn "Done"
>     putStrLn $ "Time: " ++ show (diffUTCTime fin start)


> mainPar2 :: IO ()
> mainPar2 =
>   do nl <- createList 5
>      let len = 5 + 200
>      cnt <- atomically (newTVar 0)
>      printList nl
>      mapM (\ e -> forkIO ( do insert nl e
>                               atomically(do i <- readTVar cnt
>                                             writeTVar cnt (i+1))))
>           [6..len]

>      atomically ( do i <- readTVar cnt
>                      if i <= len-6 then retry 
>                       else return () )

>      printList nl
>      n <- cntList nl
>      putStrLn $ "Overall: " ++ show n


sequential version 
  
> mainSeq :: IO ()
> mainSeq = 
>  do let len = 3000
>     let threads = 4
>     nl <- createList len
>     let numbers = [1..len] ++ (reverse [1..len]) ++ [1..len] ++ (reverse [1..len])
>                   ++ [1..len] ++ (reverse [1..len]) ++ [1..len] ++ (reverse [1..len])
>     let [d1,d2,d3,d4] = distribution numbers threads
>     let t1 = d1++d2++d3++d4
>     let t2 = d2++d3++d4++d1
>     let t3 = d3++d4++d1++d2
>     let t4 = d4++d1++d2++d3
>     putStrLn "Start"
>     start <- getCurrentTime
>     mapM (\ t -> executeTasks nl (specificTask1 t)) [t1,t2,t3,t4]
>     fin <- getCurrentTime
>     putStrLn "Done"
>     putStrLn $ "Time: " ++ show (diffUTCTime fin start)


just testing

> mainTest2 :: IO ()
> mainTest2 =
>  do let len = 10
>     nl <- createList len
>     printList nl
>     addToTail nl 1
>     printList nl   

> mainTest :: IO ()
> mainTest =
>  do let len = 10
>     nl <- createList len
>     printList nl   

      r <- delete nl 3
      putStrLn ("Result : " ++ show r)
      find nl 10

>     insert nl 11

>     delete nl 3
>     find nl 11


>     mapM (\x -> forkIO (insert nl x)) [12..50]

>     threadDelay 1000000

> {-
>     putStrLn "Start"
>     executeTasks nl $ createTasks [1..len]
>     find nl (len+1) -- we try to find a non-existent element
>                     -- this way, in the LazyList case, we will physically delete all (logically deleted) elements 
> -}
>     putStrLn "End"
>     printList nl
