{-# LANGUAGE TypeFamilies #-}
module Data.Array.Comfort.Boxed.Internal where

import qualified Data.Array.Comfort.Shape as Shape
import qualified Data.Primitive.Array as Prim

import qualified Control.Monad.ST.Strict as STStrict

import Prelude hiding (map, )


data Array sh a =
   Array {
      shape :: sh,
      buffer :: Prim.Array a
   }

-- add assertion, at least in an exposed version
reshape :: sh1 -> Array sh0 a -> Array sh1 a
reshape sh (Array _ arr) = Array sh arr

mapShape :: (sh0 -> sh1) -> Array sh0 a -> Array sh1 a
mapShape f (Array sh arr) = Array (f sh) arr


infixl 9 !

(!) :: (Shape.Indexed sh) => Array sh a -> Shape.Index sh -> a
(!) (Array sh arr) ix = Prim.indexArray arr $ Shape.offset sh ix

toList :: (Shape.C sh) => Array sh a -> [a]
toList (Array sh arr) =
   STStrict.runST (mapM (Prim.indexArrayM arr) $ take (Shape.size sh) [0..])

fromList :: (Shape.C sh) => sh -> [a] -> Array sh a
fromList sh xs = Array sh $ Prim.fromListN (Shape.size sh) xs

vectorFromList :: [a] -> Array (Shape.ZeroBased Int) a
vectorFromList xs =
   let arr = Prim.fromList xs
   in Array (Shape.ZeroBased $ Prim.sizeofArray arr) arr

map :: (Shape.C sh) => (a -> b) -> Array sh a -> Array sh b
map f (Array sh arr) = Array sh $ Prim.mapArray' f arr