module LLVM.Extra.Array (
   size,
   assemble,
   extractAll,
   map,
   ) where

import qualified LLVM.Extra.Tuple as Tuple

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, )


-- * target independent functions

size ::
   (TypeNum.Natural n) =>
   Value (Array n a) -> Int
size :: forall n a. Natural n => Value (Array n a) -> Int
size =
   let sz :: (TypeNum.Natural n) => TypeNum.Singleton n -> Value (Array n a) -> Int
       sz :: forall n a. Natural n => Singleton n -> Value (Array n a) -> Int
sz Singleton n
n Value (Array n a)
_ = Singleton n -> Int
forall n a. (Integer n, Num a) => Singleton n -> a
TypeNum.integralFromSingleton Singleton n
n
   in  Singleton n -> Value (Array n a) -> Int
forall n a. Natural n => Singleton n -> Value (Array n a) -> Int
sz Singleton n
forall x. Integer x => Singleton x
TypeNum.singleton

{- |
construct an array out of single elements

You must assert that the length of the list matches the array size.

This can be considered the inverse of 'extractAll'.
-}
assemble ::
   (TypeNum.Natural n, LLVM.IsSized a) =>
   [Value a] -> CodeGenFunction r (Value (Array n a))
assemble :: forall n a r.
(Natural n, IsSized a) =>
[Value a] -> CodeGenFunction r (Value (Array n a))
assemble =
   (Value (Array n a)
 -> (Word32, Value a) -> CodeGenFunction r (Value (Array n a)))
-> Value (Array n a)
-> [(Word32, Value a)]
-> CodeGenFunction r (Value (Array n a))
forall (t :: * -> *) (m :: * -> *) b a.
(Foldable t, Monad m) =>
(b -> a -> m b) -> b -> t a -> m b
foldM (\Value (Array n a)
v (Word32
k,Value a
x) -> Value (Array n a)
-> Value (ValueType (Array n a) Word32)
-> Word32
-> CodeGenFunction r (Value (Array n a))
forall r agg i.
GetValue agg i =>
Value agg
-> Value (ValueType agg i) -> i -> CodeGenFunction r (Value agg)
LLVM.insertvalue Value (Array n a)
v Value a
Value (ValueType (Array n a) Word32)
x (Word32
k::Word32)) Value (Array n a)
forall a. Undefined a => a
Tuple.undef ([(Word32, Value a)] -> CodeGenFunction r (Value (Array n a)))
-> ([Value a] -> [(Word32, Value a)])
-> [Value a]
-> CodeGenFunction r (Value (Array n a))
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
   [Word32] -> [Value a] -> [(Word32, Value a)]
forall a b. [a] -> [b] -> [(a, b)]
List.zip [Word32
0..]

{- |
provide the elements of an array as a list of individual virtual registers

This can be considered the inverse of 'assemble'.
-}
extractAll ::
   (TypeNum.Natural n, LLVM.IsSized a) =>
   Value (Array n a) -> LLVM.CodeGenFunction r [Value a]
extractAll :: forall n a r.
(Natural n, IsSized a) =>
Value (Array n a) -> CodeGenFunction r [Value a]
extractAll Value (Array n a)
x =
   (Word32 -> CodeGenFunction r (Value a))
-> [Word32] -> CodeGenFunction r [Value a]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> [a] -> m [b]
mapM
      (Value (Array n a)
-> Word32
-> CodeGenFunction r (Value (ValueType (Array n a) Word32))
forall r agg i.
GetValue agg i =>
Value agg -> i -> CodeGenFunction r (Value (ValueType agg i))
LLVM.extractvalue Value (Array n a)
x)
      (Int -> [Word32] -> [Word32]
forall a. Int -> [a] -> [a]
take (Value (Array n a) -> Int
forall n a. Natural n => Value (Array n a) -> Int
size Value (Array n a)
x) [(Word32
0::Word32)..])

{- |
The loop is unrolled,
since 'LLVM.insertvalue' and 'LLVM.extractvalue' expect constant indices.
-}
map ::
   (TypeNum.Natural n, LLVM.IsSized a, LLVM.IsSized b) =>
   (Value a -> CodeGenFunction r (Value b)) ->
   (Value (Array n a) -> CodeGenFunction r (Value (Array n b)))
map :: forall n a b r.
(Natural n, IsSized a, IsSized b) =>
(Value a -> CodeGenFunction r (Value b))
-> Value (Array n a) -> CodeGenFunction r (Value (Array n b))
map Value a -> CodeGenFunction r (Value b)
f =
   [Value b] -> CodeGenFunction r (Value (Array n b))
forall n a r.
(Natural n, IsSized a) =>
[Value a] -> CodeGenFunction r (Value (Array n a))
assemble ([Value b] -> CodeGenFunction r (Value (Array n b)))
-> (Value (Array n a) -> CodeGenFunction r [Value b])
-> Value (Array n a)
-> CodeGenFunction r (Value (Array n b))
forall (m :: * -> *) b c a.
Monad m =>
(b -> m c) -> (a -> m b) -> a -> m c
<=< (Value a -> CodeGenFunction r (Value b))
-> [Value a] -> CodeGenFunction r [Value b]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> [a] -> m [b]
mapM Value a -> CodeGenFunction r (Value b)
f ([Value a] -> CodeGenFunction r [Value b])
-> (Value (Array n a) -> CodeGenFunction r [Value a])
-> Value (Array n a)
-> CodeGenFunction r [Value b]
forall (m :: * -> *) b c a.
Monad m =>
(b -> m c) -> (a -> m b) -> a -> m c
<=< Value (Array n a) -> CodeGenFunction r [Value a]
forall n a r.
(Natural n, IsSized a) =>
Value (Array n a) -> CodeGenFunction r [Value a]
extractAll