packages feed

llvm-tf-21.0: private/LLVM/Core/Data.hs

{-# LANGUAGE EmptyDataDecls #-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE ScopedTypeVariables #-}
module LLVM.Core.Data (
    Ptr(..), uncheckedFromPtr, uncheckedToPtr,
    IntN(..), WordN(..), FP128(..),
    Array(..), Vector(..), Label, Struct(..), PackedStruct(..),
    FixedList,
    ) where

import qualified LLVM.Core.UnaryVector as UnaryVector
import LLVM.Core.UnaryVector (FixedList)

import qualified Type.Data.Num.Decimal.Proof as DecProof
import qualified Type.Data.Num.Decimal.Number as Dec
import Type.Base.Proxy (Proxy(Proxy))

import qualified Foreign

import qualified Data.Foldable as Fold
import qualified Data.Bits as Bits

import Data.Typeable (Typeable)

import qualified Test.QuickCheck as QC


{- |
We export the constructor such that you can use 'Ptr' in foreign imports.
However, we recommend that you call 'uncheckedFromPtr' instead.
-}
newtype Ptr a = Ptr (Foreign.Ptr a)
    deriving (Show, Eq, Ord, Typeable)

uncheckedFromPtr :: Foreign.Ptr a -> Ptr a
uncheckedFromPtr = Ptr

uncheckedToPtr :: Ptr a -> Foreign.Ptr a
uncheckedToPtr (Ptr ptr) = ptr

instance Foreign.Storable (Ptr a) where
    sizeOf = Foreign.sizeOf . uncheckedToPtr
    alignment = Foreign.alignment . uncheckedToPtr
    poke p = Foreign.pokeByteOff p 0 . uncheckedToPtr
    peek p = fmap uncheckedFromPtr $ Foreign.peekByteOff p 0


-- TODO:
-- Make instances IntN, WordN to actually do the right thing.
-- Make FP128 do the right thing
-- Make Array functions.

-- |Variable sized signed integer.
-- The /n/ parameter should belong to @PosI@.
newtype IntN n = IntN Integer
    deriving (Show, Eq, Ord, Typeable)

instance (Dec.Positive n) => QC.Arbitrary (IntN n) where
    arbitrary = arbitraryInt IntN (\(IntN a) -> a)

instance (Dec.Positive n) => Bounded (IntN n) where
    minBound =
        withBitSize $
        IntN . negate . Bits.shiftL 1 . subtract 1 . Dec.integralFromProxy
    maxBound =
        withBitSize $
        IntN . subtract 1 . Bits.shiftL 1 . subtract 1 . Dec.integralFromProxy

-- |Variable sized unsigned integer.
-- The /n/ parameter should belong to @PosI@.
newtype WordN n = WordN Integer
    deriving (Show, Eq, Ord, Typeable)

instance (Dec.Positive n) => QC.Arbitrary (WordN n) where
    arbitrary = arbitraryInt WordN (\(WordN a) -> a)

instance (Dec.Positive n) => Bounded (WordN n) where
    minBound = WordN 0
    maxBound =
        withBitSize $ WordN . subtract 1 . Bits.shiftL 1 . Dec.integralFromProxy

arbitraryInt :: (Bounded a) => (Integer -> a) -> (a -> Integer) -> QC.Gen a
arbitraryInt wrap unwrap =
    case (minBound, maxBound) of
        (a,b) -> do
            x <- QC.choose (unwrap a, unwrap b)
            return $ wrap x `asTypeOf` a `asTypeOf` b

withBitSize :: (Proxy n -> f n) -> f n
withBitSize f = f Proxy

-- |128 bit floating point.
newtype FP128 = FP128 Rational
    deriving (Show, Typeable)


-- |Fixed sized arrays, the array size is encoded in the /n/ parameter.
newtype Array n a = Array [a]
    deriving (Eq, Show, Typeable)

instance (Dec.Integer n) => Fold.Foldable (Array n) where
    foldMap f (Array xs) = Fold.foldMap f xs

instance (Dec.Integer n, QC.Arbitrary a) => QC.Arbitrary (Array n a) where
    arbitrary = withArraySize $ fmap Array . QC.vector . Dec.integralFromProxy

withArraySize :: (Proxy n -> gen (Array n a)) -> gen (Array n a)
withArraySize f = f Proxy

-- |Fixed sized vector, the array size is encoded in the /n/ parameter.
newtype Vector n a = Vector (FixedList (Dec.ToUnary n) a)

instance (Dec.Natural n, Show a) => Show (Vector n a) where
    showsPrec p (Vector xs) =
        case DecProof.unaryNat :: DecProof.UnaryNat n of
            DecProof.UnaryNat ->
                showParen (p>10) $
                    showString "Vector " .
                    showList (Fold.toList
                        (UnaryVector.fromFixedList xs
                            :: UnaryVector.T (Dec.ToUnary n) a))

-- |Label type, produced by a basic block.
data Label
    deriving (Typeable)

-- |Struct types; a list (nested tuple) of component types.
newtype Struct a = Struct a
    deriving (Eq, Show, Typeable)
newtype PackedStruct a = PackedStruct a
    deriving (Eq, Show, Typeable)

instance (QC.Arbitrary a) => QC.Arbitrary (Struct a) where
    arbitrary = fmap Struct QC.arbitrary