content: {-# OPTIONS_GHC -Wno-orphans #-}
  
  {-# LANGUAGE CPP #-}
  
  #include "Streamly/Benchmark/Data/Array/CommonImports.hs"
  
  import Control.DeepSeq (deepseq)
  #if __GLASGOW_HASKELL__ >= 810
  import Data.Kind (Type)
  #endif
  
  import qualified Streamly.Internal.Data.Array as IA
  import qualified GHC.Exts as GHC
  
  -- import qualified Streamly.Data.Array as A
  import qualified Streamly.Internal.Data.Array as A
  
  #if __GLASGOW_HASKELL__ >= 810
  type Stream :: Type -> Type
  #endif
  type Stream = A.Array
  
  #include "Streamly/Benchmark/Data/Array/Common.hs"
  
  instance NFData (A.Array a) where
      {-# INLINE rnf #-}
      rnf _ = ()
  
  -------------------------------------------------------------------------------
  -- Benchmark helpers
  -------------------------------------------------------------------------------
  
  -- Drain a source that generates a pure array
  {-# INLINE benchPureSrc #-}
  benchPureSrc :: String -> (Int -> Stream a) -> Benchmark
  benchPureSrc name src = benchPure name src id
  
  -- Drain a source that generates an array in the IO monad
  {-# INLINE benchIOSrc #-}
  benchIOSrc :: String -> (Int -> IO (Stream a)) -> Benchmark
  benchIOSrc name src = benchIO name src id
  
  -------------------------------------------------------------------------------
  -- Bench Ops
  -------------------------------------------------------------------------------
  
  {-# INLINE sourceIntFromToFromList #-}
  sourceIntFromToFromList :: MonadIO m => Int -> Int -> m (Stream Int)
  sourceIntFromToFromList value n = P.return $ A.fromListN value [n..n + value]
  
  {-# INLINE readInstance #-}
  readInstance :: P.String -> Stream Int
  readInstance str =
      let r = P.reads str
      in case r of
          [(x,"")] -> x
          _ -> P.error "readInstance: no parse"
  
  #ifdef DEVBUILD
  {-
  {-# INLINE foldableFoldl' #-}
  foldableFoldl' :: Stream Int -> Int
  foldableFoldl' = F.foldl' (+) 0
  
  {-# INLINE foldableSum #-}
  foldableSum :: Stream Int -> Int
  foldableSum = P.sum
  -}
  #endif
  
  {-# INLINE sourceIsList #-}
  sourceIsList :: Int -> Int -> Stream Int
  sourceIsList value n = GHC.fromList [n..n+value]
  
  {-# INLINE sourceIsString #-}
  sourceIsString :: Int -> Int -> Stream P.Char
  sourceIsString value n = GHC.fromString (P.replicate (n + value) 'a')
  
  {-# INLINE sourceIntFromToFromStream #-}
  sourceIntFromToFromStream :: MonadIO m => Int -> Int -> m (Stream Int)
  sourceIntFromToFromStream value n = S.fold A.create $ S.enumerateFromTo n (n + value)
  
  -------------------------------------------------------------------------------
  -- Bench groups
  -------------------------------------------------------------------------------
  
  o_1_space_generation :: Int -> [Benchmark]
  o_1_space_generation value =
      [ bgroup
          "generation"
          [ benchIOSrc "write . intFromTo" (sourceIntFromToFromStream value)
          , let testStr = "fromList " ++ mkListString value
             in testStr `deepseq` bench "read" (nf readInstance testStr)
          , benchPureSrc "writeN . IsList.fromList" (sourceIsList value)
          , benchPureSrc
                "writeN . IsString.fromString"
                (sourceIsString value)
  
          ]
      ]
  
  o_1_space_elimination :: Int -> [Benchmark]
  o_1_space_elimination value =
      [ bgroup "elimination"
          [ benchPureSink value "length . IsList.toList" (length . GHC.toList)
          , benchFold "createOfLast.1"
              (S.fold (IA.createOfLast 1)) (P.sourceUnfoldrM value)
          , benchFold "createOfLast.10"
              (S.fold (IA.createOfLast 10)) (P.sourceUnfoldrM value)
  #ifdef DEVBUILD
  {-
            benchPureSink value "foldable/foldl'" foldableFoldl'
          , benchPureSink value "foldable/sum" foldableSum
  -}
  #endif
          ]
        ]
  
  o_n_heap_serial :: Int -> [Benchmark]
  o_n_heap_serial value =
      [ bgroup "elimination"
          [
          -- Converting the stream to an array
              benchFold "createOfLast.Max" (S.fold (IA.createOfLast (value + 1)))
                  (P.sourceUnfoldrM value)
           ]
      ]
  
  moduleName :: String
  moduleName = "Data.Array"
  
  defStreamSize :: Int
  defStreamSize = defaultStreamSize
  
  main :: IO ()
  main = runWithCLIOpts defStreamSize allBenchmarks
  
      where
  
      allBenchmarks size =
          [ bgroup (o_1_space_prefix moduleName) $
               o_1_space_generation size ++ o_1_space_elimination size
          , bgroup (o_n_space_prefix moduleName) $
               o_n_heap_serial size
          ] ++ commonBenchmarks size
  