module Data.Int.Int24 (
Int24(..),
narrow24Int#,
) where
import Data.Word.Word24
import Data.Bits
import Foreign.Storable
import GHC.Base
import GHC.Enum
import GHC.Num
import GHC.Real
import GHC.Read
import GHC.Arr
import GHC.Word
import GHC.Int
import GHC.Show
import GHC.Ptr
import GHC.Err
#if __GLASGOW_HASKELL__ >= 702
#define TOINT integerToInt
#else
#define TOINT toInt#
#endif
data Int24 = I24# Int# deriving (Eq, Ord)
narrow24Int# :: Int# -> Int#
narrow24Int# x# = if primBool ((x'# `and#` mask#) `eqWord#` mask#)
then word2Int# ( x'# `or#` int2Word# m1# )
else word2Int# ( x'# `and#` (int2Word# m2#))
where
!x'# = int2Word# x#
!mask# = int2Word# 0x00800000#
!(I# m1#) = 8388608
!(I# m2#) = 16777215
instance Show Int24 where
showsPrec p x = showsPrec p (fromIntegral x :: Int)
instance Num Int24 where
(I24# x#) + (I24# y#) = I24# (narrow24Int# (x# +# y#))
(I24# x#) (I24# y#) = I24# (narrow24Int# (x# -# y#))
(I24# x#) * (I24# y#) = I24# (narrow24Int# (x# *# y#))
negate (I24# x#) = I24# (narrow24Int# (negateInt# x#))
abs x | x >= 0 = x
| otherwise = negate x
signum x | x > 0 = 1
signum 0 = 0
signum _ = 1
fromInteger i = I24# (narrow24Int# (TOINT i))
instance Real Int24 where
toRational x = toInteger x % 1
instance Enum Int24 where
succ x
| x /= maxBound = x + 1
| otherwise = succError "Int24"
pred x
| x /= minBound = x 1
| otherwise = predError "Int24"
toEnum i@(I# i#)
| i >= fromIntegral (minBound::Int24) && i <= fromIntegral (maxBound::Int24)
= I24# i#
| otherwise = toEnumError "Int24" i (minBound::Int24, maxBound::Int24)
fromEnum (I24# x#) = I# x#
enumFrom = boundedEnumFrom
enumFromThen = boundedEnumFromThen
instance Integral Int24 where
quot x@(I24# x#) y@(I24# y#)
| y == 0 = divZeroError
| x == minBound && y == (1) = overflowError
| otherwise = I24# (narrow24Int# (x# `quotInt#` y#))
rem x@(I24# x#) y@(I24# y#)
| y == 0 = divZeroError
| x == minBound && y == (1) = overflowError
| otherwise = I24# (narrow24Int# (x# `remInt#` y#))
div x@(I24# x#) y@(I24# y#)
| y == 0 = divZeroError
| x == minBound && y == (1) = overflowError
| otherwise = I24# (narrow24Int# (x# `divInt#` y#))
mod x@(I24# x#) y@(I24# y#)
| y == 0 = divZeroError
| x == minBound && y == (1) = overflowError
| otherwise = I24# (narrow24Int# (x# `modInt#` y#))
quotRem x@(I24# x#) y@(I24# y#)
| y == 0 = divZeroError
| x == minBound && y == (1) = overflowError
| otherwise = (I24# (narrow24Int# (x# `quotInt#` y#)),
I24# (narrow24Int# (x# `remInt#` y#)))
divMod x@(I24# x#) y@(I24# y#)
| y == 0 = divZeroError
| x == minBound && y == (1) = overflowError
| otherwise = (I24# (narrow24Int# (x# `divInt#` y#)),
I24# (narrow24Int# (x# `modInt#` y#)))
toInteger (I24# x#) = smallInteger x#
instance Bounded Int24 where
minBound = 0x800000
maxBound = 0x7FFFFF
instance Ix Int24 where
range (m,n) = [m..n]
unsafeIndex (m,_) i = fromIntegral i fromIntegral m
inRange (m,n) i = m <= i && i <= n
instance Read Int24 where
readsPrec p s = [(fromIntegral (x::Int), r) | (x, r) <- readsPrec p s]
instance Bits Int24 where
(I24# x#) .&. (I24# y#) = I24# (word2Int# (int2Word# x# `and#` int2Word# y#))
(I24# x#) .|. (I24# y#) = I24# (word2Int# (int2Word# x# `or#` int2Word# y#))
(I24# x#) `xor` (I24# y#) = I24# (word2Int# (int2Word# x# `xor#` int2Word# y#))
complement (I24# x#) = I24# (word2Int# (int2Word# x# `xor#` int2Word# (1#)))
(I24# x#) `shift` (I# i#)
| primBool (i# >=# 0# ) = I24# (narrow24Int# (x# `iShiftL#` i#))
| otherwise = I24# (x# `iShiftRA#` negateInt# i#)
(I24# x#) `rotate` i
| primBool (i'# ==# 0# ) = I24# x#
| otherwise
= I24# (narrow24Int# (word2Int# ((x'# `uncheckedShiftL#` i'#) `or#`
(x'# `uncheckedShiftRL#` (24# -# i'#)))))
where
!x'# = narrow24Word# (int2Word# x#)
!(I# i0#) = i `mod` 24
!i'# = word2Int# (narrow24Word# (int2Word# i0#))
bitSize _ = 24
isSigned _ = True
x `shiftR` i = x `shift` (i)
bit n = case bit n of
I32# x -> I24# (narrow24Int# x)
testBit x i = (x .&. bit i) /= 0
popCount (I24# x#) = popCount (W# (narrow24Word# (int2Word# x#)))
instance Storable Int24 where
sizeOf _ = 3
alignment _ = 3
peek p = fmap fromIntegral $ peek ((castPtr p) :: Ptr Word24)
poke p v = poke (castPtr p :: Ptr Word24) (fromIntegral v)
#if MIN_VERSION_base(4,7,0)
primBool :: Int# -> Bool
primBool x = tagToEnum# x
#else
primBool :: Bool -> Bool
primBool = id
#endif