{-# LANGUAGE CPP #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}
#if __GLASGOW_HASKELL__ < 707
#error This code requires GHC 7.7+
#endif
#include "MachDeps.h"
#include "HsBaseConfig.h"
module Data.IntCast
(
intCast
, intCastIso
, intCastEq
, intCastMaybe
, IntBaseType
, IntBaseTypeK(..)
, IsIntSubType
, IsIntBaseSubType
, IsIntTypeIso
, IsIntBaseTypeIso
, IsIntTypeEq
, IsIntBaseTypeEq
) where
import Data.Bits
import Data.Int
import Data.Word
import Foreign.C.Types
import GHC.TypeLits
#if __GLASGOW_HASKELL__ < 900
import Numeric.Natural (Natural)
#endif
data IntBaseTypeK
= FixedIntTag Nat
| FixedWordTag Nat
| BigIntTag
| BigWordTag
type family IntBaseType a :: IntBaseTypeK
type instance IntBaseType Integer = 'BigIntTag
type instance IntBaseType Natural = 'BigWordTag
type instance IntBaseType Int8 = 'FixedIntTag 8
type instance IntBaseType Int16 = 'FixedIntTag 16
type instance IntBaseType Int32 = 'FixedIntTag 32
type instance IntBaseType Int64 = 'FixedIntTag 64
type instance IntBaseType Word8 = 'FixedWordTag 8
type instance IntBaseType Word16 = 'FixedWordTag 16
type instance IntBaseType Word32 = 'FixedWordTag 32
type instance IntBaseType Word64 = 'FixedWordTag 64
#if defined(WORD_SIZE_IN_BITS)
type instance IntBaseType Int = 'FixedIntTag WORD_SIZE_IN_BITS
type instance IntBaseType Word = 'FixedWordTag WORD_SIZE_IN_BITS
#else
#error Cannot determine bit-size of 'Int'/'Word' type
#endif
type instance IntBaseType CChar = IntBaseType HTYPE_CHAR
type instance IntBaseType CInt = IntBaseType HTYPE_INT
type instance IntBaseType CIntMax = IntBaseType HTYPE_INTMAX_T
type instance IntBaseType CIntPtr = IntBaseType HTYPE_INTPTR_T
type instance IntBaseType CLLong = IntBaseType HTYPE_LONG_LONG
type instance IntBaseType CLong = IntBaseType HTYPE_LONG
type instance IntBaseType CPtrdiff = IntBaseType HTYPE_PTRDIFF_T
type instance IntBaseType CSChar = IntBaseType HTYPE_SIGNED_CHAR
type instance IntBaseType CShort = IntBaseType HTYPE_SHORT
type instance IntBaseType CSigAtomic = IntBaseType HTYPE_SIG_ATOMIC_T
type instance IntBaseType CSize = IntBaseType HTYPE_SIZE_T
type instance IntBaseType CUChar = IntBaseType HTYPE_UNSIGNED_CHAR
type instance IntBaseType CUInt = IntBaseType HTYPE_UNSIGNED_INT
type instance IntBaseType CUIntMax = IntBaseType HTYPE_UINTMAX_T
type instance IntBaseType CUIntPtr = IntBaseType HTYPE_UINTPTR_T
type instance IntBaseType CULLong = IntBaseType HTYPE_UNSIGNED_LONG_LONG
type instance IntBaseType CULong = IntBaseType HTYPE_UNSIGNED_LONG
type instance IntBaseType CUShort = IntBaseType HTYPE_UNSIGNED_SHORT
type family IsIntBaseSubType a b :: Bool where
IsIntBaseSubType a a = 'True
IsIntBaseSubType a 'BigIntTag = 'True
IsIntBaseSubType ('FixedWordTag a) 'BigWordTag = 'True
IsIntBaseSubType ('FixedIntTag a) ('FixedIntTag b) = a <=? b
IsIntBaseSubType ('FixedWordTag a) ('FixedWordTag b) = a <=? b
IsIntBaseSubType ('FixedWordTag a) ('FixedIntTag b) = a+1 <=? b
IsIntBaseSubType a b = 'False
type IsIntSubType a b = IsIntBaseSubType (IntBaseType a) (IntBaseType b)
type family IsIntBaseTypeIso a b :: Bool where
IsIntBaseTypeIso a a = 'True
IsIntBaseTypeIso ('FixedIntTag n) ('FixedWordTag n) = 'True
IsIntBaseTypeIso ('FixedWordTag n) ('FixedIntTag n) = 'True
IsIntBaseTypeIso a b = 'False
type IsIntTypeIso a b = IsIntBaseTypeIso (IntBaseType a) (IntBaseType b)
type family IsIntBaseTypeEq (a :: IntBaseTypeK) (b :: IntBaseTypeK) :: Bool where
IsIntBaseTypeEq a a = 'True
IsIntBaseTypeEq a b = 'False
type IsIntTypeEq a b = IsIntBaseTypeEq (IntBaseType a) (IntBaseType b)
intCast :: (Integral a, Integral b, IsIntSubType a b ~ 'True) => a -> b
intCast :: a -> b
intCast = a -> b
forall a b. (Integral a, Num b) => a -> b
fromIntegral
{-# INLINE intCast #-}
intCastIso :: (Integral a, Integral b, IsIntTypeIso a b ~ 'True) => a -> b
intCastIso :: a -> b
intCastIso = a -> b
forall a b. (Integral a, Num b) => a -> b
fromIntegral
{-# INLINE intCastIso #-}
intCastEq :: (Integral a, Integral b, IsIntTypeEq a b ~ 'True) => a -> b
intCastEq :: a -> b
intCastEq = a -> b
forall a b. (Integral a, Num b) => a -> b
fromIntegral
{-# INLINE intCastEq #-}
isBitSubType :: (Bits a, Bits b) => a -> b -> Bool
isBitSubType :: a -> b -> Bool
isBitSubType a
_x b
_y
| Maybe Int
xWidth Maybe Int -> Maybe Int -> Bool
forall a. Eq a => a -> a -> Bool
== Maybe Int
yWidth, Bool
xSigned Bool -> Bool -> Bool
forall a. Eq a => a -> a -> Bool
== Bool
ySigned = Bool
True
| Bool
ySigned, Maybe Int
forall a. Maybe a
Nothing Maybe Int -> Maybe Int -> Bool
forall a. Eq a => a -> a -> Bool
== Maybe Int
yWidth = Bool
True
| Bool -> Bool
not Bool
xSigned, Bool -> Bool
not Bool
ySigned, Maybe Int
forall a. Maybe a
Nothing Maybe Int -> Maybe Int -> Bool
forall a. Eq a => a -> a -> Bool
== Maybe Int
yWidth = Bool
True
| Bool
xSigned Bool -> Bool -> Bool
forall a. Eq a => a -> a -> Bool
== Bool
ySigned, Just Int
xW <- Maybe Int
xWidth, Just Int
yW <- Maybe Int
yWidth = Int
xW Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
yW
| Bool -> Bool
not Bool
xSigned, Bool
ySigned, Just Int
xW <- Maybe Int
xWidth, Just Int
yW <- Maybe Int
yWidth = Int
xW Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
yW
| Bool
otherwise = Bool
False
where
xWidth :: Maybe Int
xWidth = a -> Maybe Int
forall a. Bits a => a -> Maybe Int
bitSizeMaybe a
_x
xSigned :: Bool
xSigned = a -> Bool
forall a. Bits a => a -> Bool
isSigned a
_x
yWidth :: Maybe Int
yWidth = b -> Maybe Int
forall a. Bits a => a -> Maybe Int
bitSizeMaybe b
_y
ySigned :: Bool
ySigned = b -> Bool
forall a. Bits a => a -> Bool
isSigned b
_y
{-# INLINE isBitSubType #-}
intCastMaybe :: (Integral a, Integral b, Bits a, Bits b) => a -> Maybe b
intCastMaybe :: a -> Maybe b
intCastMaybe a
x
| Bool -> (a -> Bool) -> Maybe a -> Bool
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Bool
True (a -> a -> Bool
forall a. Ord a => a -> a -> Bool
<= a
x) Maybe a
yMinBound
, Bool -> (a -> Bool) -> Maybe a -> Bool
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Bool
True (a
x a -> a -> Bool
forall a. Ord a => a -> a -> Bool
<=) Maybe a
yMaxBound = b -> Maybe b
forall a. a -> Maybe a
Just b
y
| Bool
otherwise = Maybe b
forall a. Maybe a
Nothing
where
y :: b
y = a -> b
forall a b. (Integral a, Num b) => a -> b
fromIntegral a
x
xWidth :: Maybe Int
xWidth = a -> Maybe Int
forall a. Bits a => a -> Maybe Int
bitSizeMaybe a
x
yWidth :: Maybe Int
yWidth = b -> Maybe Int
forall a. Bits a => a -> Maybe Int
bitSizeMaybe b
y
yMinBound :: Maybe a
yMinBound | a -> b -> Bool
forall a b. (Bits a, Bits b) => a -> b -> Bool
isBitSubType a
x b
y = Maybe a
forall a. Maybe a
Nothing
| a -> Bool
forall a. Bits a => a -> Bool
isSigned a
x, Bool -> Bool
not (b -> Bool
forall a. Bits a => a -> Bool
isSigned b
y) = a -> Maybe a
forall a. a -> Maybe a
Just a
0
| a -> Bool
forall a. Bits a => a -> Bool
isSigned a
x, b -> Bool
forall a. Bits a => a -> Bool
isSigned b
y, Just Int
yW <- Maybe Int
yWidth
= a -> Maybe a
forall a. a -> Maybe a
Just (a -> a
forall a. Num a => a -> a
negate (a -> a) -> a -> a
forall a b. (a -> b) -> a -> b
$ Int -> a
forall a. Bits a => Int -> a
bit (Int
yWInt -> Int -> Int
forall a. Num a => a -> a -> a
-Int
1))
| Bool
otherwise = Maybe a
forall a. Maybe a
Nothing
yMaxBound :: Maybe a
yMaxBound | a -> b -> Bool
forall a b. (Bits a, Bits b) => a -> b -> Bool
isBitSubType a
x b
y = Maybe a
forall a. Maybe a
Nothing
| a -> Bool
forall a. Bits a => a -> Bool
isSigned a
x, Bool -> Bool
not (b -> Bool
forall a. Bits a => a -> Bool
isSigned b
y), Just Int
xW <- Maybe Int
xWidth, Just Int
yW <- Maybe Int
yWidth
, Int
xW Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
yWInt -> Int -> Int
forall a. Num a => a -> a -> a
+Int
1 = Maybe a
forall a. Maybe a
Nothing
| Just Int
yW <- Maybe Int
yWidth = if b -> Bool
forall a. Bits a => a -> Bool
isSigned b
y then a -> Maybe a
forall a. a -> Maybe a
Just (Int -> a
forall a. Bits a => Int -> a
bit (Int
yWInt -> Int -> Int
forall a. Num a => a -> a -> a
-Int
1)a -> a -> a
forall a. Num a => a -> a -> a
-a
1) else a -> Maybe a
forall a. a -> Maybe a
Just (Int -> a
forall a. Bits a => Int -> a
bit Int
yWa -> a -> a
forall a. Num a => a -> a -> a
-a
1)
| Bool
otherwise = Maybe a
forall a. Maybe a
Nothing
{-# INLINEABLE intCastMaybe #-}