{-# language KindSignatures #-}
{-# language BangPatterns #-}
{-# language RoleAnnotations #-}
{-# language MagicHash #-}
{-# language UnboxedTuples #-}
{-# language RankNTypes #-}
{-# language DeriveTraversable #-}
{-# language Unsafe #-}
module Data.CompactSequence.Internal.Array where
import Data.CompactSequence.Internal.Size
import Data.Primitive.SmallArray
import Control.Monad.ST.Strict
import GHC.Exts (SmallArray#)
newtype Array n a = Array (SmallArray a)
  deriving (Functor, Foldable, Traversable)
type role Array nominal representational
singleton :: a -> Array Sz1 a
singleton x = Array (pure x)
unsafeSmallArrayToArray :: SmallArray a -> Array n a
unsafeSmallArrayToArray = Array
arrayToSmallArray :: Array n a -> SmallArray a
arrayToSmallArray (Array sa) = sa
getSingleton# :: Array Sz1 a -> (# a #)
getSingleton# (Array sa) = indexSmallArray## sa 0
getSingletonA :: Applicative f => Array Sz1 a -> f a
getSingletonA (Array sa)
  | (# a #) <- indexSmallArray## sa 0
  = pure a
splitArray :: Size n -> Array (Twice n) a -> (Array n a, Array n a)
splitArray (Size len) (Array sa)
  | (# sa1, sa2 #) <- splitSmallArray# len sa
  = (Array (SmallArray sa1), Array (SmallArray sa2))
{-# INLINE splitArray #-}
splitSmallArray# :: Int -> SmallArray a -> (# SmallArray# a, SmallArray# a #)
splitSmallArray# len sa1 = (# sa2, sa3 #)
  where
    !(SmallArray sa2) = cloneSmallArray sa1 0 len
    !(SmallArray sa3) = cloneSmallArray sa1 len len
{-# NOINLINE splitSmallArray# #-}
append :: Size n -> Array n a -> Array n a -> Array (Twice n) a
append (Size n) (Array xs) (Array ys) = Array $
  appendSmallArrays n xs ys
appendSmallArrays :: Int -> SmallArray a -> SmallArray a -> SmallArray a
appendSmallArrays n xs ys =
    createSmallArray (2*n)
      (error "Data.CompactSequence.Internal.Array.append: Internal error")
      $ \sma -> copySmallArray sma 0 xs 0 n
        *> copySmallArray sma n ys 0 n
{-# NOINLINE appendSmallArrays #-}
createSmallArray
  :: Int
  -> a
  -> (forall s. SmallMutableArray s a -> ST s ())
  -> SmallArray a
createSmallArray n x f = runSmallArray $ do
  mary <- newSmallArray n x
  f mary
  pure mary
arraySplitListN :: Size n -> [a] -> (Array n a, [a])
arraySplitListN (Size n) xs
  | (sa, xs') <- smallArraySplitListN n xs
  = (Array sa, xs')
smallArraySplitListN :: Int -> [a] -> (SmallArray a, [a])
smallArraySplitListN n l = runST $ do
  sma <- newSmallArray n (error "smallArraySplitListN: uninitialized")
  let go !ix [] = if ix == n
        then do
          sa <- unsafeFreezeSmallArray sma
          pure (sa, [])
        else error "smallArraySplitListN: list length less than specified size"
      go !ix xss@(x : xs) = if ix < n
        then do
          writeSmallArray sma ix x
          go (ix+1) xs
        else do
          sa <- unsafeFreezeSmallArray sma
          pure (sa, xss)
  go 0 l
fromList :: Size n -> [a] -> Array n a
fromList (Size n) xs = Array (smallArrayFromListN n xs)