module LLVM.Extra.Array (
   size,
   assemble,
   extractAll,
   map,
   ) where
import qualified LLVM.Extra.Class as Class
import qualified LLVM.Core as LLVM
import LLVM.Core (Value, Array, CodeGenFunction, )
import qualified Type.Data.Num.Decimal as TypeNum
import Control.Monad.HT ((<=<), )
import Control.Monad (foldM, )
import qualified Data.List as List
import Data.Word (Word32, )
import Prelude hiding
          (Real, truncate, floor, round,
           map, zipWith, iterate, replicate, reverse, concat, sum, )
size ::
   (TypeNum.Natural n) =>
   Value (Array n a) -> Int
size =
   let sz :: (TypeNum.Natural n) => TypeNum.Singleton n -> Value (Array n a) -> Int
       sz n _ = TypeNum.integralFromSingleton n
   in  sz TypeNum.singleton
assemble ::
   (TypeNum.Natural n, LLVM.IsFirstClass a, LLVM.IsSized a) =>
   [Value a] -> CodeGenFunction r (Value (Array n a))
assemble =
   foldM (\v (k,x) -> LLVM.insertvalue v x (k::Word32)) Class.undefTuple .
   List.zip [0..]
extractAll ::
   (TypeNum.Natural n, LLVM.IsFirstClass a, LLVM.IsSized a) =>
   Value (Array n a) -> LLVM.CodeGenFunction r [Value a]
extractAll x =
   mapM
      (LLVM.extractvalue x)
      (take (size x) [(0::Word32)..])
map ::
   (TypeNum.Natural n,
    LLVM.IsFirstClass a, LLVM.IsSized a,
    LLVM.IsFirstClass b, LLVM.IsSized b) =>
   (Value a -> CodeGenFunction r (Value b)) ->
   (Value (Array n a) -> CodeGenFunction r (Value (Array n b)))
map f =
   assemble <=< mapM f <=< extractAll