%
% (c) The University of Glasgow, 2000-2006
%
\section{Fast integers, etc... booleans moved to FastBool for using panic}

\begin{code}

--Even if the optimizer could handle boxed arithmetic equally well,
--this helps automatically check the sources to make sure that
--it's only used in an appropriate pattern of efficiency.
--(it also makes `let`s and `case`s stricter...)

-- | Fast integers, characters and pointer types for use in many parts of GHC
module FastTypes (
    -- * FastInt
    FastInt,
    
    -- ** Getting in and out of FastInt
    _ILIT, iBox, iUnbox,
    
    -- ** Arithmetic on FastInt
    (+#), (-#), (*#), quotFastInt, negateFastInt,
    --quotRemFastInt is difficult because unboxed values can't
    --be tupled, but unboxed tuples aren't portable.  Just use
    -- nuisance boxed quotRem and rely on optimization.
    (==#), (/=#), (<#), (<=#), (>=#), (>#),
    minFastInt, maxFastInt,
    --prefer to distinguish operations, not types, between
    --signed and unsigned.
    --left-shift is the same for 'signed' and 'unsigned' numbers
    shiftLFastInt,
    --right-shift isn't the same for negative numbers (ones with
    --the highest-order bit '1').  If you don't care because the
    --number you're shifting is always nonnegative, use the '_' version
    --which should just be the fastest one.
    shiftR_FastInt,
    --"L' = logical or unsigned shift; 'A' = arithmetic or signed shift
    shiftRLFastInt, shiftRAFastInt,
    bitAndFastInt, bitOrFastInt,
    --add more operations to this file as you need them

    -- * FastChar
    FastChar,

    -- ** Getting in and out of FastChar
    _CLIT, cBox, cUnbox,

    -- ** Operations on FastChar
    fastOrd, fastChr, eqFastChar,
    --note, fastChr is "unsafe"Chr: it doesn't check for
    --character values above the range of Unicode

    -- * FastPtr
    FastPtr, 
    
    -- ** Getting in and out of FastPtr
    pBox, pUnbox,
    
    -- ** Casting FastPtrs
    castFastPtr
  ) where

#include "HsVersions.h"

#if defined(__GLASGOW_HASKELL__)

-- Import the beggars
import GHC.Exts

type FastInt = Int#

--in case it's a macro, don't lexically feed an argument!
--e.g. #define _ILIT(x) (x#) , #define _ILIT(x) (x :: FastInt)
_ILIT = \(I# x) -> x
--perhaps for accomodating caseless-leading-underscore treatment,
--something like _iLIT or iLIT would be better?

iBox x = I# x
iUnbox (I# x) = x
quotFastInt   = quotInt#
negateFastInt = negateInt#

--I think uncheckedIShiftL# and uncheckedIShiftRL# are the same
--as uncheckedShiftL# and uncheckedShiftRL# ...
--should they be used? How new are they?
--They existed as far back as GHC 6.0 at least...
shiftLFastInt x y = uncheckedIShiftL# x y
shiftR_FastInt x y = uncheckedIShiftRL# x y
shiftRLFastInt x y = uncheckedIShiftRL# x y
shiftRAFastInt x y = uncheckedIShiftRA# x y
--{-# INLINE shiftLNonnegativeFastInt #-}
--{-# INLINE shiftRNonnegativeFastInt #-}
--shiftLNonnegativeFastInt n p = word2Int#((int2Word# n) `uncheckedShiftL#` p)
--shiftRNonnegativeFastInt n p = word2Int#((int2Word# n) `uncheckedShiftRL#` p)
bitAndFastInt x y = word2Int# (and# (int2Word# x) (int2Word# y))
bitOrFastInt x y = word2Int# (or# (int2Word# x) (int2Word# y))

type FastChar = Char#
_CLIT = \(C# c) -> c
cBox c = C# c
cUnbox (C# c) = c
fastOrd c = ord# c
fastChr x = chr# x
eqFastChar a b = eqChar# a b

--note that the type-parameter doesn't provide any safety
--when it's a synonym, but as long as we keep it compiling
--with and without __GLASGOW_HASKELL__ defined, it's fine.
type FastPtr a = Addr#
pBox p = Ptr p
pUnbox (Ptr p) = p
castFastPtr p = p

#else /* ! __GLASGOW_HASKELL__ */

import Data.Char (ord, chr)

import Data.Bits
import Data.Word (Word) --is it a good idea to assume this exists too?
--does anyone need shiftRLFastInt? (apparently yes.)

import Foreign.Ptr

type FastInt = Int
_ILIT x = x
iBox x = x
iUnbox x = x
(+#) = (+)
(-#) = (-)
(*#) = (*)
quotFastInt   = quot
--quotRemFastInt = quotRem
negateFastInt = negate
(==#) = (==)
(/=#) = (/=)
(<#)  = (<)
(<=#) = (<=)
(>=#) = (>=)
(>#)  = (>)
shiftLFastInt = shiftL
shiftR_FastInt = shiftR
shiftRAFastInt = shiftR
shiftRLFastInt n p = fromIntegral (shiftR (fromIntegral n :: Word) p)
--shiftLFastInt n p = n * (2 ^ p)
--assuming quot-Int is faster and the
--same for nonnegative arguments than div-Int
--shiftR_FastInt n p = n `quot` (2 ^ p)
--shiftRAFastInt n p = n `div` (2 ^ p)
--I couldn't figure out how to implement without Word nor Bits
--shiftRLFastInt n p = fromIntegral ((fromIntegral n :: Word) `quot` (2 ^ (fromIntegral p :: Word)))

bitAndFastInt = (.&.)
bitOrFastInt = (.|.)

type FastBool = Bool
fastBool x = x
isFastTrue x = x
-- make sure these are as strict as the unboxed version,
-- so that the performance characteristics match
fastOr False False = False
fastOr _ _ = True
fastAnd True True = True
fastAnd _ _ = False

type FastChar = Char
_CLIT c = c
cBox c = c
cUnbox c = c
fastOrd = ord
fastChr = chr  --or unsafeChr if there was a standard location for it
eqFastChar = (==)

type FastPtr a = Ptr a
pBox p = p
pUnbox p = p
castFastPtr = castPtr

--These are among the type-signatures necessary for !ghc to compile
-- but break ghc (can't give a signature for an import...)
--Note that the comparisons actually do return Bools not FastBools.
(+#), (-#), (*#) :: FastInt -> FastInt -> FastInt
(==#), (/=#), (<#), (<=#), (>=#), (>#) :: FastInt -> FastInt -> Bool

#endif /* ! __GLASGOW_HASKELL__ */

minFastInt, maxFastInt :: FastInt -> FastInt -> FastInt
minFastInt x y = if x <# y then x else y
maxFastInt x y = if x <# y then y else x

-- type-signatures will improve the non-ghc-specific versions
-- and keep things accurate (and ABLE to compile!)
_ILIT :: Int -> FastInt
iBox :: FastInt -> Int
iUnbox :: Int -> FastInt

quotFastInt :: FastInt -> FastInt -> FastInt
negateFastInt :: FastInt -> FastInt
shiftLFastInt, shiftR_FastInt, shiftRAFastInt, shiftRLFastInt
   :: FastInt -> FastInt -> FastInt
bitAndFastInt, bitOrFastInt :: FastInt -> FastInt -> FastInt

_CLIT :: Char -> FastChar
cBox :: FastChar -> Char
cUnbox :: Char -> FastChar
fastOrd :: FastChar -> FastInt
fastChr :: FastInt -> FastChar
eqFastChar :: FastChar -> FastChar -> Bool

pBox :: FastPtr a -> Ptr a
pUnbox :: Ptr a -> FastPtr a
castFastPtr :: FastPtr a -> FastPtr b

\end{code}