{-# LANGUAGE Trustworthy #-}
{-# LANGUAGE CPP, MagicHash, UnboxedTuples, NoImplicitPrelude #-}
{-# OPTIONS_GHC -O2 #-}
{-# OPTIONS_HADDOCK not-home #-}

-----------------------------------------------------------------------------
-- |
-- Module      :  GHC.Float.ConversionUtils
-- Copyright   :  (c) Daniel Fischer 2010
-- License     :  see libraries/base/LICENSE
--
-- Maintainer  :  cvs-ghc@haskell.org
-- Stability   :  internal
-- Portability :  non-portable (GHC Extensions)
--
-- Utilities for conversion between Double/Float and Rational
--
-----------------------------------------------------------------------------

#include "MachDeps.h"

module GHC.Float.ConversionUtils ( elimZerosInteger, elimZerosInt# ) where

import GHC.Base
import GHC.Integer
#if WORD_SIZE_IN_BITS < 64
import GHC.IntWord64
#endif

default ()

#if WORD_SIZE_IN_BITS < 64

#define TO64    integerToInt64

toByte64# :: Int64# -> Int#
toByte64# i = word2Int# (and# 255## (int2Word# (int64ToInt# i)))

-- Double mantissae have 53 bits, too much for Int#
elim64# :: Int64# -> Int# -> (# Integer, Int# #)
elim64# n e =
    case zeroCount (toByte64# n) of
      t | isTrue# (e <=# t) -> (# int64ToInteger (uncheckedIShiftRA64# n e), 0# #)
        | isTrue# (t <# 8#) -> (# int64ToInteger (uncheckedIShiftRA64# n t), e -# t #)
        | otherwise         -> elim64# (uncheckedIShiftRA64# n 8#) (e -# 8#)

#else

#define TO64    integerToInt

-- Double mantissae fit it Int#
elim64# :: Int# -> Int# -> (# Integer, Int# #)
elim64# :: Int# -> Int# -> (# Integer, Int# #)
elim64# = Int# -> Int# -> (# Integer, Int# #)
elimZerosInt#

#endif

{-# INLINE elimZerosInteger #-}
elimZerosInteger :: Integer -> Int# -> (# Integer, Int# #)
elimZerosInteger :: Integer -> Int# -> (# Integer, Int# #)
elimZerosInteger m :: Integer
m e :: Int#
e = Int# -> Int# -> (# Integer, Int# #)
elim64# (TO64 m) e

elimZerosInt# :: Int# -> Int# -> (# Integer, Int# #)
elimZerosInt# :: Int# -> Int# -> (# Integer, Int# #)
elimZerosInt# n :: Int#
n e :: Int#
e =
    case Int# -> Int#
zeroCount (Int# -> Int#
toByte# Int#
n) of
      t :: Int#
t | Int# -> Bool
isTrue# (Int#
e Int# -> Int# -> Int#
<=# Int#
t) -> (# Int# -> Integer
smallInteger (Int# -> Int# -> Int#
uncheckedIShiftRA# Int#
n Int#
e), 0# #)
        | Int# -> Bool
isTrue# (Int#
t Int# -> Int# -> Int#
<# 8#) -> (# Int# -> Integer
smallInteger (Int# -> Int# -> Int#
uncheckedIShiftRA# Int#
n Int#
t), Int#
e Int# -> Int# -> Int#
-# Int#
t #)
        | Bool
otherwise         -> Int# -> Int# -> (# Integer, Int# #)
elimZerosInt# (Int# -> Int# -> Int#
uncheckedIShiftRA# Int#
n 8#) (Int#
e Int# -> Int# -> Int#
-# 8#)

{-# INLINE zeroCount #-}
zeroCount :: Int# -> Int#
zeroCount :: Int# -> Int#
zeroCount i :: Int#
i =
    case BA
zeroCountArr of
      BA ba :: ByteArray#
ba -> ByteArray# -> Int# -> Int#
indexInt8Array# ByteArray#
ba Int#
i

toByte# :: Int# -> Int#
toByte# :: Int# -> Int#
toByte# i :: Int#
i = Word# -> Int#
word2Int# (Word# -> Word# -> Word#
and# 255## (Int# -> Word#
int2Word# Int#
i))


data BA = BA ByteArray#

-- Number of trailing zero bits in a byte
zeroCountArr :: BA
zeroCountArr :: BA
zeroCountArr =
    let mkArr :: State# d -> ByteArray#
mkArr s :: State# d
s =
          case Int# -> State# d -> (# State# d, MutableByteArray# d #)
forall d. Int# -> State# d -> (# State# d, MutableByteArray# d #)
newByteArray# 256# State# d
s of
            (# s1 :: State# d
s1, mba :: MutableByteArray# d
mba #) ->
              case MutableByteArray# d -> Int# -> Int# -> State# d -> State# d
forall d.
MutableByteArray# d -> Int# -> Int# -> State# d -> State# d
writeInt8Array# MutableByteArray# d
mba 0# 8# State# d
s1 of
                s2 :: State# d
s2 ->
                  let fillA :: Int# -> Int# -> Int# -> State# d -> State# d
fillA step :: Int#
step val :: Int#
val idx :: Int#
idx st :: State# d
st
                        | Int# -> Bool
isTrue# (Int#
idx Int# -> Int# -> Int#
<# 256#) =
                                        case MutableByteArray# d -> Int# -> Int# -> State# d -> State# d
forall d.
MutableByteArray# d -> Int# -> Int# -> State# d -> State# d
writeInt8Array# MutableByteArray# d
mba Int#
idx Int#
val State# d
st of
                                          nx :: State# d
nx -> Int# -> Int# -> Int# -> State# d -> State# d
fillA Int#
step Int#
val (Int#
idx Int# -> Int# -> Int#
+# Int#
step) State# d
nx
                        | Int# -> Bool
isTrue# (Int#
step Int# -> Int# -> Int#
<# 256#) =
                                        Int# -> Int# -> Int# -> State# d -> State# d
fillA (2# Int# -> Int# -> Int#
*# Int#
step) (Int#
val Int# -> Int# -> Int#
+# 1#) Int#
step  State# d
st
                        | Bool
otherwise   = State# d
st
                  in case Int# -> Int# -> Int# -> State# d -> State# d
fillA 2# 0# 1# State# d
s2 of
                       s3 :: State# d
s3 -> case MutableByteArray# d -> State# d -> (# State# d, ByteArray# #)
forall d.
MutableByteArray# d -> State# d -> (# State# d, ByteArray# #)
unsafeFreezeByteArray# MutableByteArray# d
mba State# d
s3 of
                                (# _, ba :: ByteArray#
ba #) -> ByteArray#
ba
    in case State# RealWorld -> ByteArray#
forall d. State# d -> ByteArray#
mkArr State# RealWorld
realWorld# of
        b :: ByteArray#
b -> ByteArray# -> BA
BA ByteArray#
b