{-# OPTIONS_GHC -Wall -fwarn-tabs #-}
{-# LANGUAGE BangPatterns, ScopedTypeVariables #-}
module Data.ByteString.Lex.Fractional
(
readSigned
, readDecimal
, readHexadecimal
, readOctal
, readExponential
, decimalPrecision
, readDecimalLimited
, readExponentialLimited
) where
import Data.ByteString (ByteString)
import qualified Data.ByteString as BS
import qualified Data.ByteString.Unsafe as BSU
import Data.Word (Word8)
import qualified Data.ByteString.Lex.Integral as I
import Data.ByteString.Lex.Integral (readSigned)
import Data.ByteString.Lex.Internal
justPair :: a -> b -> Maybe (a,b)
{-# INLINE justPair #-}
justPair :: forall a b. a -> b -> Maybe (a, b)
justPair !a
x !b
y = forall a. a -> Maybe a
Just (a
x,b
y)
pair :: a -> b -> (a,b)
{-# INLINE pair #-}
pair :: forall a b. a -> b -> (a, b)
pair !a
x !b
y = (a
x,b
y)
readDecimal :: (Fractional a) => ByteString -> Maybe (a, ByteString)
{-# SPECIALIZE readDecimal ::
ByteString -> Maybe (Float, ByteString),
ByteString -> Maybe (Double, ByteString),
ByteString -> Maybe (Rational, ByteString) #-}
readDecimal :: forall a. Fractional a => ByteString -> Maybe (a, ByteString)
readDecimal ByteString
xs =
case forall a. Integral a => ByteString -> Maybe (a, ByteString)
I.readDecimal ByteString
xs of
Maybe (Integer, ByteString)
Nothing -> forall a. Maybe a
Nothing
Just (Integer
whole, ByteString
ys) ->
case ByteString -> Maybe (Word8, ByteString)
BS.uncons ByteString
ys of
Maybe (Word8, ByteString)
Nothing -> forall a b. a -> b -> Maybe (a, b)
justPair (forall a. Num a => Integer -> a
fromInteger Integer
whole) ByteString
BS.empty
Just (Word8
y0,ByteString
ys0)
| Word8 -> Bool
isNotPeriod Word8
y0 -> forall a b. a -> b -> Maybe (a, b)
justPair (forall a. Num a => Integer -> a
fromInteger Integer
whole) ByteString
ys
| Bool
otherwise ->
case forall a. Integral a => ByteString -> Maybe (a, ByteString)
I.readDecimal ByteString
ys0 of
Maybe (Integer, ByteString)
Nothing -> forall a b. a -> b -> Maybe (a, b)
justPair (forall a. Num a => Integer -> a
fromInteger Integer
whole) ByteString
ys
Just (Integer
part, ByteString
zs) ->
let base :: a
base = a
10 forall a b. (Num a, Integral b) => a -> b -> a
^ (ByteString -> Int
BS.length ByteString
ys forall a. Num a => a -> a -> a
- Int
1 forall a. Num a => a -> a -> a
- ByteString -> Int
BS.length ByteString
zs)
frac :: a
frac = forall a. Num a => Integer -> a
fromInteger Integer
whole forall a. Num a => a -> a -> a
+ (forall a. Num a => Integer -> a
fromInteger Integer
part forall a. Fractional a => a -> a -> a
/ a
base)
in forall a b. a -> b -> Maybe (a, b)
justPair a
frac ByteString
zs
readHexadecimal :: (Fractional a) => ByteString -> Maybe (a, ByteString)
{-# SPECIALIZE readHexadecimal ::
ByteString -> Maybe (Float, ByteString),
ByteString -> Maybe (Double, ByteString),
ByteString -> Maybe (Rational, ByteString) #-}
readHexadecimal :: forall a. Fractional a => ByteString -> Maybe (a, ByteString)
readHexadecimal ByteString
xs =
case forall a. Integral a => ByteString -> Maybe (a, ByteString)
I.readHexadecimal ByteString
xs of
Maybe (Integer, ByteString)
Nothing -> forall a. Maybe a
Nothing
Just (Integer
n, ByteString
xs') -> forall a b. a -> b -> Maybe (a, b)
justPair (forall a. Num a => Integer -> a
fromInteger Integer
n) ByteString
xs'
readOctal :: (Fractional a) => ByteString -> Maybe (a, ByteString)
{-# SPECIALIZE readOctal ::
ByteString -> Maybe (Float, ByteString),
ByteString -> Maybe (Double, ByteString),
ByteString -> Maybe (Rational, ByteString) #-}
readOctal :: forall a. Fractional a => ByteString -> Maybe (a, ByteString)
readOctal ByteString
xs =
case forall a. Integral a => ByteString -> Maybe (a, ByteString)
I.readOctal ByteString
xs of
Maybe (Integer, ByteString)
Nothing -> forall a. Maybe a
Nothing
Just (Integer
n, ByteString
xs') -> forall a b. a -> b -> Maybe (a, b)
justPair (forall a. Num a => Integer -> a
fromInteger Integer
n) ByteString
xs'
readExponential :: (Fractional a) => ByteString -> Maybe (a, ByteString)
{-# SPECIALIZE readExponential ::
ByteString -> Maybe (Float, ByteString),
ByteString -> Maybe (Double, ByteString),
ByteString -> Maybe (Rational, ByteString) #-}
readExponential :: forall a. Fractional a => ByteString -> Maybe (a, ByteString)
readExponential ByteString
xs =
case forall a. Fractional a => ByteString -> Maybe (a, ByteString)
readDecimal ByteString
xs of
Maybe (a, ByteString)
Nothing -> forall a. Maybe a
Nothing
Just (a
frac, ByteString
ys) ->
case ByteString -> Maybe (Word8, ByteString)
BS.uncons ByteString
ys of
Maybe (Word8, ByteString)
Nothing -> forall a b. a -> b -> Maybe (a, b)
justPair a
frac ByteString
BS.empty
Just (Word8
y0,ByteString
ys0)
| Word8 -> Bool
isNotE Word8
y0 -> forall a b. a -> b -> Maybe (a, b)
justPair a
frac ByteString
ys
| Bool
otherwise ->
case forall a.
Num a =>
(ByteString -> Maybe (a, ByteString))
-> ByteString -> Maybe (a, ByteString)
readSigned forall a. Integral a => ByteString -> Maybe (a, ByteString)
I.readDecimal ByteString
ys0 of
Maybe (Int, ByteString)
Nothing -> forall a b. a -> b -> Maybe (a, b)
justPair a
frac ByteString
ys
Just (Int
ex,ByteString
zs) -> forall a b. a -> b -> Maybe (a, b)
justPair (a
frac forall a. Num a => a -> a -> a
* (a
10 forall a b. (Fractional a, Integral b) => a -> b -> a
^^ (Int
ex::Int))) ByteString
zs
data DecimalFraction a = DF !Integer {-# UNPACK #-}!Int
fractionDF :: Integer -> Int -> Integer -> DecimalFraction a
{-# INLINE fractionDF #-}
fractionDF :: forall a. Integer -> Int -> Integer -> DecimalFraction a
fractionDF Integer
whole Int
scale Integer
part =
forall a. Integer -> Int -> DecimalFraction a
DF (Integer
whole forall a. Num a => a -> a -> a
* (Integer
10 forall a b. (Num a, Integral b) => a -> b -> a
^ Int
scale) forall a. Num a => a -> a -> a
+ Integer
part) (forall a. Num a => a -> a
negate Int
scale)
fromDF :: Fractional a => DecimalFraction a -> a
{-# INLINE fromDF #-}
fromDF :: forall a. Fractional a => DecimalFraction a -> a
fromDF (DF Integer
frac Int
scale)
| Integer
frac forall a. Eq a => a -> a -> Bool
== Integer
0 = a
0
| Int
scale forall a. Eq a => a -> a -> Bool
== forall a. Bounded a => a
minBound = forall a. Num a => Integer -> a
fromInteger Integer
frac forall a. Num a => a -> a -> a
* (a
10 forall a b. (Fractional a, Integral b) => a -> b -> a
^^ forall a. Integral a => a -> Integer
toInteger Int
scale)
| Bool
otherwise = forall a. Num a => Integer -> a
fromInteger Integer
frac forall a. Num a => a -> a -> a
* (a
10 forall a b. (Fractional a, Integral b) => a -> b -> a
^^ Int
scale)
scaleDF :: DecimalFraction a -> Int -> DecimalFraction a
{-# INLINE scaleDF #-}
scaleDF :: forall a. DecimalFraction a -> Int -> DecimalFraction a
scaleDF (DF Integer
frac Int
scale) Int
scale' = forall a. Integer -> Int -> DecimalFraction a
DF Integer
frac (Int
scale forall a. Num a => a -> a -> a
+ Int
scale')
decimalPrecision :: forall proxy a. RealFloat a => proxy a -> Int
{-# INLINE decimalPrecision #-}
decimalPrecision :: forall (proxy :: * -> *) a. RealFloat a => proxy a -> Int
decimalPrecision =
let proxy :: a
proxy = forall a. HasCallStack => a
undefined :: a
n :: Int
n = forall a. Integral a => a -> Int
numDecimalDigits (forall a. RealFloat a => a -> Integer
floatRadix a
proxy forall a b. (Num a, Integral b) => a -> b -> a
^ forall a. RealFloat a => a -> Int
floatDigits a
proxy)
in Int
n seq :: forall a b. a -> b -> b
`seq` \proxy a
_ -> Int
n
lengthDropWhile :: (Word8 -> Bool) -> ByteString -> (Int, ByteString)
{-# INLINE lengthDropWhile #-}
lengthDropWhile :: (Word8 -> Bool) -> ByteString -> (Int, ByteString)
lengthDropWhile Word8 -> Bool
p ByteString
xs =
let ys :: ByteString
ys = (Word8 -> Bool) -> ByteString -> ByteString
BS.dropWhile Word8 -> Bool
p ByteString
xs
in (ByteString -> Int
BS.length ByteString
xs forall a. Num a => a -> a -> a
- ByteString -> Int
BS.length ByteString
ys, ByteString
ys)
readDecimalLimited :: (Fractional a) => Int -> ByteString -> Maybe (a, ByteString)
{-# INLINE readDecimalLimited #-}
readDecimalLimited :: forall a.
Fractional a =>
Int -> ByteString -> Maybe (a, ByteString)
readDecimalLimited Int
p ByteString
xs =
case forall a.
Fractional a =>
Int -> ByteString -> Maybe (DecimalFraction a, ByteString)
readDecimalLimited_ Int
p ByteString
xs of
Maybe (DecimalFraction a, ByteString)
Nothing -> forall a. Maybe a
Nothing
Just (DecimalFraction a
df,ByteString
ys) -> forall a b. a -> b -> Maybe (a, b)
justPair (forall a. Fractional a => DecimalFraction a -> a
fromDF DecimalFraction a
df) ByteString
ys
readDecimalLimited_ :: (Fractional a) => Int -> ByteString -> Maybe (DecimalFraction a, ByteString)
{-# SPECIALIZE readDecimalLimited_ ::
Int -> ByteString -> Maybe (DecimalFraction Float, ByteString),
Int -> ByteString -> Maybe (DecimalFraction Double, ByteString),
Int -> ByteString -> Maybe (DecimalFraction Rational, ByteString) #-}
readDecimalLimited_ :: forall a.
Fractional a =>
Int -> ByteString -> Maybe (DecimalFraction a, ByteString)
readDecimalLimited_ = forall {a}.
Int -> ByteString -> Maybe (DecimalFraction a, ByteString)
start
where
start :: Int -> ByteString -> Maybe (DecimalFraction a, ByteString)
start !Int
p !ByteString
xs =
case (Word8 -> Bool) -> ByteString -> (Int, ByteString)
lengthDropWhile Word8 -> Bool
isDecimalZero ByteString
xs of
(Int
0, ByteString
_) -> forall {a}.
Int -> ByteString -> Maybe (DecimalFraction a, ByteString)
readWholePart Int
p ByteString
xs
(Int
_, ByteString
ys) ->
case ByteString -> Maybe (Word8, ByteString)
BS.uncons ByteString
ys of
Maybe (Word8, ByteString)
Nothing -> forall a b. a -> b -> Maybe (a, b)
justPair (forall a. Integer -> Int -> DecimalFraction a
DF Integer
0 Int
0) ByteString
BS.empty
Just (Word8
y0,ByteString
ys0)
| Word8 -> Bool
isDecimal Word8
y0 -> forall {a}.
Int -> ByteString -> Maybe (DecimalFraction a, ByteString)
readWholePart Int
p ByteString
ys
| Word8 -> Bool
isNotPeriod Word8
y0 -> forall a b. a -> b -> Maybe (a, b)
justPair (forall a. Integer -> Int -> DecimalFraction a
DF Integer
0 Int
0) ByteString
ys
| Bool
otherwise ->
case (Word8 -> Bool) -> ByteString -> (Int, ByteString)
lengthDropWhile Word8 -> Bool
isDecimalZero ByteString
ys0 of
(Int
0, ByteString
_) -> forall {a}.
Int
-> Integer -> ByteString -> Maybe (DecimalFraction a, ByteString)
readFractionPart Int
p Integer
0 ByteString
ys
(Int
scale, ByteString
zs) -> forall {a}.
Int -> Int -> ByteString -> Maybe (DecimalFraction a, ByteString)
afterDroppingZeroes Int
p Int
scale ByteString
zs
afterDroppingZeroes :: Int -> Int -> ByteString -> Maybe (DecimalFraction a, ByteString)
afterDroppingZeroes !Int
p !Int
scale !ByteString
xs =
let ys :: ByteString
ys = Int -> ByteString -> ByteString
BS.take Int
p ByteString
xs in
case forall a. Integral a => ByteString -> Maybe (a, ByteString)
I.readDecimal ByteString
ys of
Maybe (Integer, ByteString)
Nothing -> forall a b. a -> b -> Maybe (a, b)
justPair (forall a. Integer -> Int -> DecimalFraction a
DF Integer
0 Int
0) ByteString
xs
Just (Integer
part, ByteString
ys') ->
let scale' :: Int
scale' = Int
scale forall a. Num a => a -> a -> a
+ ByteString -> Int
BS.length ByteString
xs forall a. Num a => a -> a -> a
- ByteString -> Int
BS.length ByteString
ys'
in forall a b. a -> b -> Maybe (a, b)
justPair (forall a. Integer -> Int -> DecimalFraction a
DF Integer
part (forall a. Num a => a -> a
negate Int
scale'))
((Word8 -> Bool) -> ByteString -> ByteString
BS.dropWhile Word8 -> Bool
isDecimal ByteString
ys')
readWholePart :: Int -> ByteString -> Maybe (DecimalFraction a, ByteString)
readWholePart !Int
p !ByteString
xs =
let ys :: ByteString
ys = Int -> ByteString -> ByteString
BS.take Int
p ByteString
xs in
case forall a. Integral a => ByteString -> Maybe (a, ByteString)
I.readDecimal ByteString
ys of
Maybe (Integer, ByteString)
Nothing -> forall a. Maybe a
Nothing
Just (Integer
whole, ByteString
ys')
| ByteString -> Bool
BS.null ByteString
ys' ->
case (Word8 -> Bool) -> ByteString -> (Int, ByteString)
lengthDropWhile Word8 -> Bool
isDecimal (Int -> ByteString -> ByteString
BS.drop Int
p ByteString
xs) of
(Int
scale, ByteString
zs) ->
forall a b. a -> b -> Maybe (a, b)
justPair (forall a. Integer -> Int -> DecimalFraction a
DF Integer
whole Int
scale) (ByteString -> ByteString
dropFractionPart ByteString
zs)
| Bool
otherwise ->
let len :: Int
len = ByteString -> Int
BS.length ByteString
ys forall a. Num a => a -> a -> a
- ByteString -> Int
BS.length ByteString
ys'
xs' :: ByteString
xs' = Int -> ByteString -> ByteString
BS.drop Int
len ByteString
xs
in
if Word8 -> Bool
isNotPeriod (ByteString -> Word8
BSU.unsafeHead ByteString
xs')
then forall a b. a -> b -> Maybe (a, b)
justPair (forall a. Integer -> Int -> DecimalFraction a
DF Integer
whole Int
0) ByteString
xs'
else forall {a}.
Int
-> Integer -> ByteString -> Maybe (DecimalFraction a, ByteString)
readFractionPart (Int
pforall a. Num a => a -> a -> a
-Int
len) Integer
whole ByteString
xs'
dropFractionPart :: ByteString -> ByteString
dropFractionPart !ByteString
xs =
case ByteString -> Maybe (Word8, ByteString)
BS.uncons ByteString
xs of
Maybe (Word8, ByteString)
Nothing -> ByteString
BS.empty
Just (Word8
x0,ByteString
xs0)
| Word8 -> Bool
isNotPeriod Word8
x0 -> ByteString
xs
| Bool
otherwise ->
case ByteString -> Maybe (Word8, ByteString)
BS.uncons ByteString
xs0 of
Maybe (Word8, ByteString)
Nothing -> Word8 -> ByteString
BS.singleton Word8
0x2E
Just (Word8
x1,ByteString
xs1)
| Word8 -> Bool
isDecimal Word8
x1 -> (Word8 -> Bool) -> ByteString -> ByteString
BS.dropWhile Word8 -> Bool
isDecimal ByteString
xs1
| Bool
otherwise -> ByteString
xs
readFractionPart :: Int
-> Integer -> ByteString -> Maybe (DecimalFraction a, ByteString)
readFractionPart !Int
p !Integer
whole !ByteString
xs =
let ys :: ByteString
ys = Int -> ByteString -> ByteString
BS.take Int
p (ByteString -> ByteString
BSU.unsafeTail ByteString
xs) in
case forall a. Integral a => ByteString -> Maybe (a, ByteString)
I.readDecimal ByteString
ys of
Maybe (Integer, ByteString)
Nothing -> forall a b. a -> b -> Maybe (a, b)
justPair (forall a. Integer -> Int -> DecimalFraction a
DF Integer
whole Int
0) ByteString
xs
Just (Integer
part, ByteString
ys') ->
let scale :: Int
scale = ByteString -> Int
BS.length ByteString
ys forall a. Num a => a -> a -> a
- ByteString -> Int
BS.length ByteString
ys'
in forall a b. a -> b -> Maybe (a, b)
justPair (forall a. Integer -> Int -> Integer -> DecimalFraction a
fractionDF Integer
whole Int
scale Integer
part)
((Word8 -> Bool) -> ByteString -> ByteString
BS.dropWhile Word8 -> Bool
isDecimal (Int -> ByteString -> ByteString
BS.drop (Int
1forall a. Num a => a -> a -> a
+Int
scale) ByteString
xs))
readExponentialLimited :: (Fractional a) => Int -> ByteString -> Maybe (a, ByteString)
{-# SPECIALIZE readExponentialLimited ::
Int -> ByteString -> Maybe (Float, ByteString),
Int -> ByteString -> Maybe (Double, ByteString),
Int -> ByteString -> Maybe (Rational, ByteString) #-}
readExponentialLimited :: forall a.
Fractional a =>
Int -> ByteString -> Maybe (a, ByteString)
readExponentialLimited = forall a.
Fractional a =>
Int -> ByteString -> Maybe (a, ByteString)
start
where
start :: Int -> ByteString -> Maybe (a, ByteString)
start !Int
p !ByteString
xs =
case forall a.
Fractional a =>
Int -> ByteString -> Maybe (DecimalFraction a, ByteString)
readDecimalLimited_ Int
p ByteString
xs of
Maybe (DecimalFraction a, ByteString)
Nothing -> forall a. Maybe a
Nothing
Just (DecimalFraction a
df,ByteString
xs') -> forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$! forall {a}.
Fractional a =>
DecimalFraction a -> ByteString -> (a, ByteString)
readExponentPart DecimalFraction a
df ByteString
xs'
readExponentPart :: DecimalFraction a -> ByteString -> (a, ByteString)
readExponentPart !DecimalFraction a
df !ByteString
xs
| ByteString -> Bool
BS.null ByteString
xs = forall a b. a -> b -> (a, b)
pair (forall a. Fractional a => DecimalFraction a -> a
fromDF DecimalFraction a
df) ByteString
BS.empty
| Word8 -> Bool
isNotE (ByteString -> Word8
BSU.unsafeHead ByteString
xs) = forall a b. a -> b -> (a, b)
pair (forall a. Fractional a => DecimalFraction a -> a
fromDF DecimalFraction a
df) ByteString
xs
| Bool
otherwise =
case forall a.
Num a =>
(ByteString -> Maybe (a, ByteString))
-> ByteString -> Maybe (a, ByteString)
readSigned forall a. Integral a => ByteString -> Maybe (a, ByteString)
I.readDecimal (ByteString -> ByteString
BSU.unsafeTail ByteString
xs) of
Maybe (Int, ByteString)
Nothing -> forall a b. a -> b -> (a, b)
pair (forall a. Fractional a => DecimalFraction a -> a
fromDF DecimalFraction a
df) ByteString
xs
Just (Int
scale, ByteString
xs') -> forall a b. a -> b -> (a, b)
pair (forall a. Fractional a => DecimalFraction a -> a
fromDF forall a b. (a -> b) -> a -> b
$ forall a. DecimalFraction a -> Int -> DecimalFraction a
scaleDF DecimalFraction a
df Int
scale) ByteString
xs'