content: -------------------------------------------------------------------------------
  -- Benchmark helpers
  -------------------------------------------------------------------------------
  
  {-# INLINE benchIO #-}
  benchIO :: NFData b => String -> (Int -> IO a) -> (a -> b) -> Benchmark
  benchIO name src f = bench name $ nfIO $
      (randomRIO (1,1) >>= src) <&> f
  
  {-# INLINE benchPureSink #-}
  benchPureSink :: NFData b => Int -> String -> (Stream Int -> b) -> Benchmark
  benchPureSink value name = benchIO name (sourceIntFromTo value)
  
  {-# INLINE benchIO' #-}
  benchIO' :: NFData b => String -> (Int -> IO a) -> (a -> IO b) -> Benchmark
  benchIO' name src f = bench name $ nfIO $
      randomRIO (1,1) >>= src >>= f
  
  {-# INLINE benchIOSink #-}
  benchIOSink :: NFData b => Int -> String -> (Stream Int -> IO b) -> Benchmark
  benchIOSink value name = benchIO' name (sourceIntFromTo value)
  
  -------------------------------------------------------------------------------
  -- Bench Ops
  -------------------------------------------------------------------------------
  
  {-# INLINE sourceUnfoldr #-}
  sourceUnfoldr :: MonadIO m => Int -> Int -> m (Stream Int)
  sourceUnfoldr value n = S.fold (A.createOf value) $ S.unfoldr step n
      where
      step cnt =
          if cnt > n + value
          then Nothing
          else Just (cnt, cnt + 1)
  
  {-# INLINE sourceIntFromTo #-}
  sourceIntFromTo :: MonadIO m => Int -> Int -> m (Stream Int)
  sourceIntFromTo value n = S.fold (A.createOf value) $ S.enumerateFromTo n (n + value)
  
  {-# INLINE sourceFromList #-}
  sourceFromList :: MonadIO m => Int -> Int -> m (Stream Int)
  sourceFromList value n = S.fold (A.createOf value) $ S.fromList [n..n+value]
  
  -------------------------------------------------------------------------------
  -- Transformation
  -------------------------------------------------------------------------------
  
  {-# INLINE composeN #-}
  composeN :: P.Monad m
      => Int -> (Stream Int -> m (Stream Int)) -> Stream Int -> m (Stream Int)
  composeN n f x =
      case n of
          1 -> f x
          2 -> f x P.>>= f
          3 -> f x P.>>= f P.>>= f
          4 -> f x P.>>= f P.>>= f P.>>= f
          _ -> undefined
  
  {-# INLINE scanl' #-}
  {-# INLINE scanl1' #-}
  {-# INLINE map #-}
  
  scanl' , scanl1', map
      :: MonadIO m => Int -> Int -> Stream Int -> m (Stream Int)
  
  
  {-# INLINE onArray #-}
  onArray
      :: MonadIO m => Int -> (Stream.Stream m Int -> Stream.Stream m Int)
      -> Stream Int
      -> m (Stream Int)
  onArray value f arr = S.fold (A.createOf value) $ f $ S.unfold A.reader arr
  
  scanl'  value n = composeN n $ onArray value $ S.scanl (Scanl.mkScanl (+) 0)
  scanl1' value n = composeN n $ onArray value $ Stream.scanl1' (+)
  map     value n = composeN n $ onArray value $ fmap (+1)
  -- map           n = composeN n $ A.map (+1)
  
  {-# INLINE eqInstance #-}
  eqInstance :: Stream Int -> Bool
  eqInstance src = src == src
  
  {-# INLINE eqInstanceNotEq #-}
  eqInstanceNotEq :: Stream Int -> Bool
  eqInstanceNotEq src = src P./= src
  
  {-# INLINE ordInstance #-}
  ordInstance :: Stream Int -> Bool
  ordInstance src = src P.< src
  
  {-# INLINE ordInstanceMin #-}
  ordInstanceMin :: Stream Int -> Stream Int
  ordInstanceMin src = P.min src src
  
  {-# INLINE showInstance #-}
  showInstance :: Stream Int -> P.String
  showInstance = P.show
  
  {-# INLINE pureFoldl' #-}
  pureFoldl' :: MonadIO m => Stream Int -> m Int
  pureFoldl' = S.fold (Fold.foldl' (+) 0) . S.unfold A.reader
  
  -------------------------------------------------------------------------------
  -- Elimination
  -------------------------------------------------------------------------------
  
  {-# INLINE unfoldReadDrain #-}
  unfoldReadDrain :: MonadIO m => Stream Int -> m ()
  unfoldReadDrain = S.fold Fold.drain . S.unfold A.reader
  
  {-# INLINE toStreamRevDrain #-}
  toStreamRevDrain :: MonadIO m => Stream Int -> m ()
  toStreamRevDrain = S.fold Fold.drain . A.readRev
  
  -------------------------------------------------------------------------------
  -- Bench groups
  -------------------------------------------------------------------------------
  
  common_o_1_space_generation :: Int -> [Benchmark]
  common_o_1_space_generation value =
      [ bgroup
          "generation"
          [ benchIOSrc "writeN . intFromTo" (sourceIntFromTo value)
          , benchIOSrc
                "fromList . intFromTo"
                (sourceIntFromToFromList value)
          , benchIOSrc "writeN . unfoldr" (sourceUnfoldr value)
          , benchIOSrc "writeN . fromList" (sourceFromList value)
          , benchPureSink value "show" showInstance
          ]
      ]
  
  common_o_1_space_elimination :: Int -> [Benchmark]
  common_o_1_space_elimination value =
      [ bgroup "elimination"
          [ benchPureSink value "id" id
          , benchPureSink value "==" eqInstance
          , benchPureSink value "/=" eqInstanceNotEq
          , benchPureSink value "<" ordInstance
          , benchPureSink value "min" ordInstanceMin
          , benchIOSink value "foldl'" pureFoldl'
          , benchIOSink value "read" unfoldReadDrain
          , benchIOSink value "toStreamRev" toStreamRevDrain
          ]
        ]
  
  common_o_n_heap_serial :: Int -> [Benchmark]
  common_o_n_heap_serial value =
      [ bgroup "elimination"
          [
          -- Converting the stream to an array
              benchFold "writeN" (S.fold (A.createOf value))
                  (P.sourceUnfoldrM value)
           ]
      ]
  
  common_o_1_space_transformation :: Int -> [Benchmark]
  common_o_1_space_transformation value =
     [ bgroup "transformation"
          [ benchIOSink value "scanl'" (scanl' value 1)
          , benchIOSink value "scanl1'" (scanl1' value 1)
          , benchIOSink value "map" (map value 1)
          ]
     ]
  
  common_o_1_space_transformationX4 :: Int -> [Benchmark]
  common_o_1_space_transformationX4 value =
      [ bgroup "transformationX4"
          [ benchIOSink value "scanl'" (scanl' value 4)
          , benchIOSink value "scanl1'" (scanl1' value 4)
          , benchIOSink value "map" (map value 4)
          ]
        ]
  
  commonBenchmarks :: Int -> [Benchmark]
  commonBenchmarks size =
          [ bgroup (o_1_space_prefix moduleName) $ concat
              [ common_o_1_space_generation size
              , common_o_1_space_elimination size
              , common_o_1_space_transformation size
              , common_o_1_space_transformationX4 size
              ]
          , bgroup (o_n_space_prefix moduleName) $
               common_o_n_heap_serial size
          ]
  