{-# LANGUAGE CPP #-}
module Data.Binary.Parser.Numeric where
import Control.Applicative
import Control.Monad
import Data.Binary.Get.Internal
import qualified Data.Binary.Parser.Word8 as W
import qualified Data.ByteString as B
import qualified Data.ByteString.Lex.Integral as LexInt
import Data.Int
import Data.Scientific (Scientific (..))
import qualified Data.Scientific as Sci
import Data.Word
#define MINUS 45
#define PLUS 43
#define LITTLE_E 101
#define BIG_E 69
#define DOT 46
hexadecimal :: (Integral a) => Get a
hexadecimal :: forall a. Integral a => Get a
hexadecimal = do
ByteString
bs <- (Word8 -> Bool) -> Get ByteString
W.takeWhile1 Word8 -> Bool
W.isHexDigit
case ByteString -> Maybe (a, ByteString)
forall a. Integral a => ByteString -> Maybe (a, ByteString)
LexInt.readHexadecimal ByteString
bs of
Just (a
x, ByteString
_) -> a -> Get a
forall a. a -> Get a
forall (m :: * -> *) a. Monad m => a -> m a
return a
x
Maybe (a, ByteString)
Nothing -> String -> Get a
forall a. String -> Get a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"hexadecimal: impossible"
{-# SPECIALISE hexadecimal :: Get Int #-}
{-# SPECIALISE hexadecimal :: Get Int8 #-}
{-# SPECIALISE hexadecimal :: Get Int16 #-}
{-# SPECIALISE hexadecimal :: Get Int32 #-}
{-# SPECIALISE hexadecimal :: Get Int64 #-}
{-# SPECIALISE hexadecimal :: Get Integer #-}
{-# SPECIALISE hexadecimal :: Get Word #-}
{-# SPECIALISE hexadecimal :: Get Word8 #-}
{-# SPECIALISE hexadecimal :: Get Word16 #-}
{-# SPECIALISE hexadecimal :: Get Word32 #-}
{-# SPECIALISE hexadecimal :: Get Word64 #-}
decimal :: Integral a => Get a
decimal :: forall a. Integral a => Get a
decimal = do
ByteString
bs <- (Word8 -> Bool) -> Get ByteString
W.takeWhile1 Word8 -> Bool
W.isDigit
a -> Get a
forall a. a -> Get a
forall (m :: * -> *) a. Monad m => a -> m a
return (a -> Get a) -> a -> Get a
forall a b. (a -> b) -> a -> b
$! ByteString -> a
forall a. Integral a => ByteString -> a
LexInt.readDecimal_ ByteString
bs
{-# SPECIALISE decimal :: Get Int #-}
{-# SPECIALISE decimal :: Get Int8 #-}
{-# SPECIALISE decimal :: Get Int16 #-}
{-# SPECIALISE decimal :: Get Int32 #-}
{-# SPECIALISE decimal :: Get Int64 #-}
{-# SPECIALISE decimal :: Get Integer #-}
{-# SPECIALISE decimal :: Get Word #-}
{-# SPECIALISE decimal :: Get Word8 #-}
{-# SPECIALISE decimal :: Get Word16 #-}
{-# SPECIALISE decimal :: Get Word32 #-}
{-# SPECIALISE decimal :: Get Word64 #-}
signed :: Num a => Get a -> Get a
signed :: forall a. Num a => Get a -> Get a
signed Get a
p = do
Word8
w <- Get Word8
W.peek
if Word8
w Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== MINUS
then Int -> Get ()
W.skipN Int
1 Get () -> Get a -> Get a
forall a b. Get a -> Get b -> Get b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> a -> a
forall a. Num a => a -> a
negate (a -> a) -> Get a -> Get a
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Get a
p
else if Word8
w Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== PLUS then W.skipN 1 >> p else p
{-# SPECIALISE signed :: Get Int -> Get Int #-}
{-# SPECIALISE signed :: Get Int8 -> Get Int8 #-}
{-# SPECIALISE signed :: Get Int16 -> Get Int16 #-}
{-# SPECIALISE signed :: Get Int32 -> Get Int32 #-}
{-# SPECIALISE signed :: Get Int64 -> Get Int64 #-}
{-# SPECIALISE signed :: Get Integer -> Get Integer #-}
rational :: Fractional a => Get a
rational :: forall a. Fractional a => Get a
rational = (Scientific -> a) -> Get a
forall a. (Scientific -> a) -> Get a
scientifically Scientific -> a
forall a b. (Real a, Fractional b) => a -> b
realToFrac
{-# SPECIALIZE rational :: Get Double #-}
{-# SPECIALIZE rational :: Get Float #-}
{-# SPECIALIZE rational :: Get Rational #-}
{-# SPECIALIZE rational :: Get Scientific #-}
double :: Get Double
double :: Get Double
double = (Scientific -> Double) -> Get Double
forall a. (Scientific -> a) -> Get a
scientifically Scientific -> Double
forall a. RealFloat a => Scientific -> a
Sci.toRealFloat
scientific :: Get Scientific
scientific :: Get Scientific
scientific = (Scientific -> Scientific) -> Get Scientific
forall a. (Scientific -> a) -> Get a
scientifically Scientific -> Scientific
forall a. a -> a
id
scientifically :: (Scientific -> a) -> Get a
scientifically :: forall a. (Scientific -> a) -> Get a
scientifically Scientific -> a
h = do
Word8
sign <- Get Word8
W.peek
Bool -> Get () -> Get ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Word8
sign Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== PLUS || sign == MINUS) (W.skipN 1)
Integer
intPart <- Get Integer
forall a. Integral a => Get a
decimal
Scientific
sci <- (do ByteString
fracDigits <- Word8 -> Get ()
W.word8 DOT >> W.takeWhile1 W.isDigit
let e' :: Int
e' = ByteString -> Int
B.length ByteString
fracDigits
intPart' :: Integer
intPart' = Integer
intPart Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
* (Integer
10 Integer -> Int -> Integer
forall a b. (Num a, Integral b) => a -> b -> a
^ Int
e')
fracPart :: Integer
fracPart = ByteString -> Integer
forall a. Integral a => ByteString -> a
LexInt.readDecimal_ ByteString
fracDigits
Integer -> Int -> Get Scientific
parseE (Integer
intPart' Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
+ Integer
fracPart) Int
e'
) Get Scientific -> Get Scientific -> Get Scientific
forall a. Get a -> Get a -> Get a
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> (Integer -> Int -> Get Scientific
parseE Integer
intPart Int
0)
if Word8
sign Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
/= MINUS then return $! h sci else return $! h (negate sci)
where
parseE :: Integer -> Int -> Get Scientific
parseE Integer
c Int
e =
(do Word8
_ <- (Word8 -> Bool) -> Get Word8
W.satisfy (\Word8
w -> Word8
w Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== LITTLE_E || w == BIG_E)
(Integer -> Int -> Scientific
Sci.scientific Integer
c (Int -> Scientific) -> (Int -> Int) -> Int -> Scientific
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Int -> Int -> Int
forall a. Num a => a -> a -> a
subtract Int
e) (Int -> Scientific) -> Get Int -> Get Scientific
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Get Int -> Get Int
forall a. Num a => Get a -> Get a
signed Get Int
forall a. Integral a => Get a
decimal)) Get Scientific -> Get Scientific -> Get Scientific
forall a. Get a -> Get a -> Get a
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> Scientific -> Get Scientific
forall a. a -> Get a
forall (m :: * -> *) a. Monad m => a -> m a
return (Integer -> Int -> Scientific
Sci.scientific Integer
c (Int -> Int
forall a. Num a => a -> a
negate Int
e))
{-# INLINE parseE #-}
{-# INLINE scientifically #-}