{-# LANGUAGE CPP                   #-}
{-# LANGUAGE MagicHash             #-}
module Basement.Numerical.Conversion
    ( intToInt64
    , int64ToInt
    , intToWord
    , wordToWord64
    , word64ToWord
    , Word32x2(..)
    , word64ToWord32s
    , wordToChar
    , wordToInt
    , word64ToWord#
    , charToInt
    , int64ToWord64
    , word64ToInt64
    ) where

#include "MachDeps.h"

import GHC.Types
import GHC.Prim hiding (word64ToWord#)
import qualified GHC.Prim
import GHC.Int
import GHC.Word
import Basement.Compat.Primitive

#if WORD_SIZE_IN_BITS < 64
import GHC.IntWord64
#endif

intToInt64 :: Int -> Int64
#if WORD_SIZE_IN_BITS == 64
#if __GLASGOW_HASKELL__ >= 904
intToInt64 (I# i) = I64# (intToInt64# i)
#else
intToInt64 :: Int -> Int64
intToInt64 (I# Int#
i) = Int# -> Int64
I64# Int#
i
#endif
#else
intToInt64 (I# i) = I64# (intToInt64# i)
#endif

int64ToInt :: Int64 -> Int
#if WORD_SIZE_IN_BITS == 64
#if __GLASGOW_HASKELL__ >= 904
int64ToInt (I64# i) = I# (int64ToInt# i)
#else
int64ToInt :: Int64 -> Int
int64ToInt (I64# Int#
i) = Int# -> Int
I# Int#
i
#endif
#else
int64ToInt (I64# i) = I# (int64ToInt# i)
#endif

wordToWord64 :: Word -> Word64
#if WORD_SIZE_IN_BITS == 64
#if __GLASGOW_HASKELL__ >= 904
wordToWord64 (W# i) = W64# (wordToWord64# i)
#else
wordToWord64 :: Word -> Word64
wordToWord64 (W# Word#
i) = Word# -> Word64
W64# Word#
i
#endif
#else
wordToWord64 (W# i) = W64# (wordToWord64# i)
#endif

word64ToWord :: Word64 -> Word
#if WORD_SIZE_IN_BITS == 64
#if __GLASGOW_HASKELL__ >= 904
word64ToWord (W64# i) = W# (GHC.Prim.word64ToWord# i)
#else
word64ToWord :: Word64 -> Word
word64ToWord (W64# Word#
i) = Word# -> Word
W# Word#
i
#endif
#else
word64ToWord (W64# i) = W# (word64ToWord# i)
#endif

word64ToInt64 :: Word64 -> Int64
#if WORD_SIZE_IN_BITS == 64
#if __GLASGOW_HASKELL__ >= 904
word64ToInt64 (W64# i) = I64# (word64ToInt64# i)
#else
word64ToInt64 :: Word64 -> Int64
word64ToInt64 (W64# Word#
i) = Int# -> Int64
I64# (Word# -> Int#
word2Int# Word#
i)
#endif
#else
word64ToInt64 (W64# i) = I64# (word64ToInt64# i)
#endif

int64ToWord64 :: Int64 -> Word64
#if WORD_SIZE_IN_BITS == 64
#if __GLASGOW_HASKELL__ >= 904
int64ToWord64 (I64# i) = W64# (int64ToWord64# i)
#else
int64ToWord64 :: Int64 -> Word64
int64ToWord64 (I64# Int#
i) = Word# -> Word64
W64# (Int# -> Word#
int2Word# Int#
i)
#endif
#else
int64ToWord64 (I64# i) = W64# (int64ToWord64# i)
#endif

#if WORD_SIZE_IN_BITS == 64
word64ToWord# :: Word# -> Word#
word64ToWord# :: Word# -> Word#
word64ToWord# Word#
i = Word#
i
{-# INLINE word64ToWord# #-}
#endif

-- | 2 Word32s
data Word32x2 = Word32x2 {-# UNPACK #-} !Word32
                         {-# UNPACK #-} !Word32

#if WORD_SIZE_IN_BITS == 64
word64ToWord32s :: Word64 -> Word32x2
#if __GLASGOW_HASKELL__ >= 904
word64ToWord32s (W64# w64) = Word32x2 (W32# (wordToWord32# (uncheckedShiftRL# (GHC.Prim.word64ToWord# w64 ) 32#))) (W32# (wordToWord32# (GHC.Prim.word64ToWord# w64)))
#else
word64ToWord32s :: Word64 -> Word32x2
word64ToWord32s (W64# Word#
w64) = Word32 -> Word32 -> Word32x2
Word32x2 (Word32# -> Word32
W32# (Word# -> Word32#
wordToWord32# (Word# -> Int# -> Word#
uncheckedShiftRL# Word#
w64 Int#
32#))) (Word32# -> Word32
W32# (Word# -> Word32#
wordToWord32# Word#
w64))
#endif
#else
word64ToWord32s :: Word64 -> Word32x2
word64ToWord32s (W64# w64) = Word32x2 (W32# (word64ToWord# (uncheckedShiftRL64# w64 32#))) (W32# (word64ToWord# w64))
#endif

wordToChar :: Word -> Char
wordToChar :: Word -> Char
wordToChar (W# Word#
word) = Char# -> Char
C# (Int# -> Char#
chr# (Word# -> Int#
word2Int# Word#
word))

wordToInt :: Word -> Int
wordToInt :: Word -> Int
wordToInt (W# Word#
word) = Int# -> Int
I# (Word# -> Int#
word2Int# Word#
word)

intToWord :: Int -> Word
intToWord :: Int -> Word
intToWord (I# Int#
i) = Word# -> Word
W# (Int# -> Word#
int2Word# Int#
i)

charToInt :: Char -> Int
charToInt :: Char -> Int
charToInt (C# Char#
x) = Int# -> Int
I# (Char# -> Int#
ord# Char#
x)