{-# LANGUAGE TypeFamilies #-}
module LLVM.Extra.Multi.Iterator (
   takeWhile,
   countDown,
   take,
   Enum(..),
   ) where

import qualified LLVM.Extra.Multi.Value as MultiValue
import qualified LLVM.Extra.Iterator as Iter
import qualified LLVM.Extra.ScalarOrVector as SoV
import qualified LLVM.Extra.Tuple as Tuple
import qualified LLVM.Extra.MaybePrivate as Maybe
import qualified LLVM.Extra.Arithmetic as A
import qualified LLVM.Extra.Control as C

import qualified LLVM.Core as LLVM
import LLVM.Core (CodeGenFunction)

import Control.Applicative (liftA2)

import qualified Data.Enum.Storable as Enum

import qualified Prelude as P
import Prelude hiding (take, takeWhile, Enum, enumFrom, enumFromTo)



takeWhile ::
   (a -> CodeGenFunction r (MultiValue.T Bool)) ->
   Iter.T r a -> Iter.T r a
takeWhile :: forall a r. (a -> CodeGenFunction r (T Bool)) -> T r a -> T r a
takeWhile a -> CodeGenFunction r (T Bool)
p = (a -> CodeGenFunction r (Value Bool)) -> T r a -> T r a
forall a r. (a -> CodeGenFunction r (Value Bool)) -> T r a -> T r a
Iter.takeWhile ((T Bool -> Value Bool)
-> CodeGenFunction r (T Bool) -> CodeGenFunction r (Value Bool)
forall a b. (a -> b) -> CodeGenFunction r a -> CodeGenFunction r b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap T Bool -> Value Bool
unpackBool (CodeGenFunction r (T Bool) -> CodeGenFunction r (Value Bool))
-> (a -> CodeGenFunction r (T Bool))
-> a
-> CodeGenFunction r (Value Bool)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> CodeGenFunction r (T Bool)
p)

unpackBool :: MultiValue.T Bool -> LLVM.Value Bool
unpackBool :: T Bool -> Value Bool
unpackBool (MultiValue.Cons Repr Bool
b) = Value Bool
Repr Bool
b

countDown ::
   (MultiValue.Additive i, MultiValue.Comparison i,
    MultiValue.IntegerConstant i) =>
   MultiValue.T i -> Iter.T r (MultiValue.T i)
countDown :: forall i r.
(Additive i, Comparison i, IntegerConstant i) =>
T i -> T r (T i)
countDown T i
len =
   (T i -> CodeGenFunction r (T Bool)) -> T r (T i) -> T r (T i)
forall a r. (a -> CodeGenFunction r (T Bool)) -> T r a -> T r a
takeWhile (CmpPredicate -> T i -> T i -> CodeGenFunction r (T Bool)
forall r. CmpPredicate -> T i -> T i -> CodeGenFunction r (T Bool)
forall a r.
Comparison a =>
CmpPredicate -> T a -> T a -> CodeGenFunction r (T Bool)
MultiValue.cmp CmpPredicate
LLVM.CmpLT T i
forall a. C a => T a
MultiValue.zero) (T r (T i) -> T r (T i)) -> T r (T i) -> T r (T i)
forall a b. (a -> b) -> a -> b
$
   (T i -> CodeGenFunction r (T i)) -> T i -> T r (T i)
forall a r.
(Phi a, Undefined a) =>
(a -> CodeGenFunction r a) -> a -> T r a
Iter.iterate T i -> CodeGenFunction r (T i)
forall i r.
(Additive i, IntegerConstant i) =>
T i -> CodeGenFunction r (T i)
MultiValue.dec T i
len

take ::
   (MultiValue.Additive i, MultiValue.Comparison i,
    MultiValue.IntegerConstant i) =>
   MultiValue.T i -> Iter.T r a -> Iter.T r a
take :: forall i r a.
(Additive i, Comparison i, IntegerConstant i) =>
T i -> T r a -> T r a
take T i
len T r a
xs = (a -> T i -> a) -> T r a -> T r (T i) -> T r a
forall a b c. (a -> b -> c) -> T r a -> T r b -> T r c
forall (f :: * -> *) a b c.
Applicative f =>
(a -> b -> c) -> f a -> f b -> f c
liftA2 a -> T i -> a
forall a b. a -> b -> a
const T r a
xs (T i -> T r (T i)
forall i r.
(Additive i, Comparison i, IntegerConstant i) =>
T i -> T r (T i)
countDown T i
len)


class (MultiValue.C a) => Enum a where
   succ, pred :: MultiValue.T a -> LLVM.CodeGenFunction r (MultiValue.T a)
   enumFrom :: MultiValue.T a -> Iter.T r (MultiValue.T a)
   enumFromTo :: MultiValue.T a -> MultiValue.T a -> Iter.T r (MultiValue.T a)

instance
   (LLVM.IsInteger w, SoV.IntegerConstant w, Num w,
    LLVM.CmpRet w, LLVM.IsPrimitive w, P.Enum e) =>
      Enum (Enum.T w e) where
   succ :: forall r. T (T w e) -> CodeGenFunction r (T (T w e))
succ = T (T w e) -> CodeGenFunction r (T (T w e))
forall w e r.
(IsArithmetic w, IntegerConstant w) =>
T (T w e) -> CodeGenFunction r (T (T w e))
MultiValue.succ
   pred :: forall r. T (T w e) -> CodeGenFunction r (T (T w e))
pred = T (T w e) -> CodeGenFunction r (T (T w e))
forall w e r.
(IsArithmetic w, IntegerConstant w) =>
T (T w e) -> CodeGenFunction r (T (T w e))
MultiValue.pred
   enumFrom :: forall r. T (T w e) -> T r (T (T w e))
enumFrom = (T (T w e) -> CodeGenFunction r (T (T w e)))
-> T (T w e) -> T r (T (T w e))
forall a r.
(Phi a, Undefined a) =>
(a -> CodeGenFunction r a) -> a -> T r a
Iter.iterate T (T w e) -> CodeGenFunction r (T (T w e))
forall w e r.
(IsArithmetic w, IntegerConstant w) =>
T (T w e) -> CodeGenFunction r (T (T w e))
MultiValue.succ
   {- |
   More complicated than 'enumFromToSimple'
   but works also for e.g. [0 .. (0xFFFF::Word16)].
   -}
   enumFromTo :: forall r. T (T w e) -> T (T w e) -> T r (T (T w e))
enumFromTo T (T w e)
from T (T w e)
to =
      T r (T (T (T w e))) -> T r (T (T w e))
forall r a. T r (T a) -> T r a
Iter.takeWhileJust (T r (T (T (T w e))) -> T r (T (T w e)))
-> T r (T (T (T w e))) -> T r (T (T w e))
forall a b. (a -> b) -> a -> b
$
      (T (T (T w e)) -> CodeGenFunction r (T (T (T w e))))
-> T (T (T w e)) -> T r (T (T (T w e)))
forall a r.
(Phi a, Undefined a) =>
(a -> CodeGenFunction r a) -> a -> T r a
Iter.iterate (T (T w e)
-> (T (T w e) -> CodeGenFunction r (T (T (T w e))))
-> T (T (T w e))
-> CodeGenFunction r (T (T (T w e)))
forall b a r.
Phi b =>
b
-> (a -> CodeGenFunction r (T b)) -> T a -> CodeGenFunction r (T b)
Maybe.maybeArg T (T w e)
forall a. Undefined a => a
Tuple.undef (T (T w e) -> T (T w e) -> CodeGenFunction r (T (T (T w e)))
forall w e r.
(IsInteger w, IntegerConstant w, Num w, CmpRet w, IsPrimitive w,
 Enum e) =>
T (T w e) -> T (T w e) -> CodeGenFunction r (T (T (T w e)))
succMax T (T w e)
to)) (T (T w e) -> T (T (T w e))
forall a. a -> T a
Maybe.just T (T w e)
from)

succMax ::
   (LLVM.IsInteger w, SoV.IntegerConstant w, Num w,
    LLVM.CmpRet w, LLVM.IsPrimitive w, P.Enum e) =>
   MultiValue.T (Enum.T w e) ->
   MultiValue.T (Enum.T w e) ->
   LLVM.CodeGenFunction r (Maybe.T (MultiValue.T (Enum.T w e)))
succMax :: forall w e r.
(IsInteger w, IntegerConstant w, Num w, CmpRet w, IsPrimitive w,
 Enum e) =>
T (T w e) -> T (T w e) -> CodeGenFunction r (T (T (T w e)))
succMax T (T w e)
to T (T w e)
e = do
   MultiValue.Cons Repr Bool
less <- CmpPredicate
-> T (T w e) -> T (T w e) -> CodeGenFunction r (T Bool)
forall w a r.
(CmpRet w, IsPrimitive w) =>
CmpPredicate
-> T (T w a) -> T (T w a) -> CodeGenFunction r (T Bool)
MultiValue.cmpEnum CmpPredicate
A.CmpLT T (T w e)
e T (T w e)
to
   Value Bool
-> T (T (T w e))
-> CodeGenFunction r (T (T (T w e)))
-> CodeGenFunction r (T (T (T w e)))
forall a r.
Phi a =>
Value Bool -> a -> CodeGenFunction r a -> CodeGenFunction r a
C.ifThen Value Bool
Repr Bool
less (T (T w e) -> T (T (T w e))
forall a. a -> T a
Maybe.nothing T (T w e)
forall a. Undefined a => a
Tuple.undef) (CodeGenFunction r (T (T (T w e)))
 -> CodeGenFunction r (T (T (T w e))))
-> CodeGenFunction r (T (T (T w e)))
-> CodeGenFunction r (T (T (T w e)))
forall a b. (a -> b) -> a -> b
$
      (T (T w e) -> T (T (T w e)))
-> CodeGenFunction r (T (T w e))
-> CodeGenFunction r (T (T (T w e)))
forall a b. (a -> b) -> CodeGenFunction r a -> CodeGenFunction r b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap T (T w e) -> T (T (T w e))
forall a. a -> T a
Maybe.just (CodeGenFunction r (T (T w e))
 -> CodeGenFunction r (T (T (T w e))))
-> CodeGenFunction r (T (T w e))
-> CodeGenFunction r (T (T (T w e)))
forall a b. (a -> b) -> a -> b
$ T (T w e) -> CodeGenFunction r (T (T w e))
forall w e r.
(IsArithmetic w, IntegerConstant w) =>
T (T w e) -> CodeGenFunction r (T (T w e))
MultiValue.succ T (T w e)
e

{- |
Warning: For [0 .. (0xFFFF::Word16)]
it would compute an undefined @0xFFFF+1@.
In modulo arithmetic it would enter an infinite loop.
-}
_enumFromToSimple ::
   (LLVM.IsInteger w, SoV.IntegerConstant w, Num w,
    LLVM.CmpRet w, LLVM.IsPrimitive w, P.Enum e) =>
   MultiValue.T (Enum.T w e) ->
   MultiValue.T (Enum.T w e) ->
   Iter.T r (MultiValue.T (Enum.T w e))
_enumFromToSimple :: forall w e r.
(IsInteger w, IntegerConstant w, Num w, CmpRet w, IsPrimitive w,
 Enum e) =>
T (T w e) -> T (T w e) -> T r (T (T w e))
_enumFromToSimple T (T w e)
from T (T w e)
to =
   (T (T w e) -> CodeGenFunction r (T Bool))
-> T r (T (T w e)) -> T r (T (T w e))
forall a r. (a -> CodeGenFunction r (T Bool)) -> T r a -> T r a
takeWhile (CmpPredicate
-> T (T w e) -> T (T w e) -> CodeGenFunction r (T Bool)
forall w a r.
(CmpRet w, IsPrimitive w) =>
CmpPredicate
-> T (T w a) -> T (T w a) -> CodeGenFunction r (T Bool)
MultiValue.cmpEnum CmpPredicate
LLVM.CmpGE T (T w e)
to) (T r (T (T w e)) -> T r (T (T w e)))
-> T r (T (T w e)) -> T r (T (T w e))
forall a b. (a -> b) -> a -> b
$ T (T w e) -> T r (T (T w e))
forall r. T (T w e) -> T r (T (T w e))
forall a r. Enum a => T a -> T r (T a)
enumFrom T (T w e)
from