content: {-# LANGUAGE BangPatterns #-}
  {-# LANGUAGE MagicHash #-}
  {-# LANGUAGE UnboxedTuples #-}
  
  -- Tests for creating and initializing a @SmallArray#@ including the
  -- optimiziation where GHC inlines the code instead of calling the
  -- @newSmallArray#@ primop if the length is small enough and known at compile
  -- time.
  module Main where
  
  import GHC.Exts
  import GHC.ST
  
  import Control.Monad (forM_)
  
  
  main :: IO ()
  main = do
      let !a00 = newSmallArrayWith42 0
          !a01 = newSmallArrayWith42 1
          !a02 = newSmallArrayWith42 2
          !a03 = newSmallArrayWith42 3
          !a04 = newSmallArrayWith42 4
          !a05 = newSmallArrayWith42 5
          !a06 = newSmallArrayWith42 6
          !a07 = newSmallArrayWith42 7
          !a08 = newSmallArrayWith42 8
          !a09 = newSmallArrayWith42 9
          !a10 = newSmallArrayWith42 10
          !a11 = newSmallArrayWith42 11
          !a12 = newSmallArrayWith42 12
          !a13 = newSmallArrayWith42 13
          !a14 = newSmallArrayWith42 14
          !a15 = newSmallArrayWith42 15
          !a16 = newSmallArrayWith42 16
          !a17 = newSmallArrayWith42 17
          !a18 = newSmallArrayWith42 18
          !a19 = newSmallArrayWith42 19
          !a20 = newSmallArrayWith42 20
          !a21 = newSmallArrayWith42 21
          !a22 = newSmallArrayWith42 22
          !a23 = newSmallArrayWith42 23
          !a24 = newSmallArrayWith42 24
          !a25 = newSmallArrayWith42 25
          !a26 = newSmallArrayWith42 26
          !a27 = newSmallArrayWith42 27
          !a28 = newSmallArrayWith42 28
          !a29 = newSmallArrayWith42 29
          !a30 = newSmallArrayWith42 30
          !a31 = newSmallArrayWith42 31
          !a32 = newSmallArrayWith42 32
          !a33 = newSmallArrayWith42 33
          !a34 = newSmallArrayWith42 34
          !a35 = newSmallArrayWith42 35
          !a36 = newSmallArrayWith42 36
          !a37 = newSmallArrayWith42 37
          !a38 = newSmallArrayWith42 38
          !a39 = newSmallArrayWith42 39
          !all = [ a00, a01, a02, a03, a04, a05, a06, a07, a08, a09
                 , a10, a11, a12, a13, a14, a15, a16, a17, a18, a19
                 , a20, a21, a22, a23, a24, a25, a26, a27, a28, a29
                 , a30, a31, a32, a33, a34, a35, a36, a37, a38, a39
                 ]
      forM_ all (print . toListArray)
  
  
  data Array a = Array { unArray :: SmallArray# a }
  
  newSmallArrayWith42 :: Int -> Array Int
  newSmallArrayWith42 n = (runST (newArray n 42))
  -- inline to make sure the length is known at compile time
  {-# INLINE newSmallArrayWith42 #-}
  
  newArray :: Int -> a -> ST s (Array a)
  newArray (I# n#) a = ST $ \s1# -> case newSmallArray# n# a s1# of
      (# s2#, marr# #) -> case unsafeFreezeSmallArray# marr# s2# of
          (# s3#, arr# #) -> (# s3#, Array arr# #)
  -- inline to make sure the length is known at compile time
  {-# INLINE newArray #-}
  
  toListArray :: Array a -> [a]
  toListArray arr = go 0
    where
      go i | i >= lengthArray arr = []
           | otherwise = indexArray arr i : go (i+1)
  
  indexArray :: Array a -> Int -> a
  indexArray arr i@(I# i#)
    | i < 0 || i >= len =
        error $ "bounds error, offset " ++ show i ++ ", length " ++ show len
    | otherwise = case indexSmallArray# (unArray arr) i# of
        (# a #) -> a
    where len = lengthArray arr
  
  lengthArray :: Array a -> Int
  lengthArray arr = I# (sizeofSmallArray# (unArray arr))
  