{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE MagicHash #-}
{-# LANGUAGE UnboxedTuples #-}
module DataFrame.Internal.Parsing.Fast.Double (parseDoubleField#) where
import qualified Data.ByteString as BS
import qualified Data.ByteString.Unsafe as BSU
import qualified Data.Vector.Unboxed as VU
import Data.Word (Word64)
import GHC.Exts (Double (..), Double#, Int#)
import DataFrame.Internal.Parsing (readByteStringDouble)
import DataFrame.Internal.Parsing.Fast.Common
pow10Table :: VU.Vector Double
pow10Table :: Vector Double
pow10Table = Int -> (Int -> Double) -> Vector Double
forall a. Unbox a => Int -> (Int -> a) -> Vector a
VU.generate (Int
tableMax Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) (Double
10 Double -> Int -> Double
forall a b. (Num a, Integral b) => a -> b -> a
^)
{-# NOINLINE pow10Table #-}
recipPow10Table :: VU.Vector Double
recipPow10Table :: Vector Double
recipPow10Table = (Double -> Double) -> Vector Double -> Vector Double
forall a b. (Unbox a, Unbox b) => (a -> b) -> Vector a -> Vector b
VU.map Double -> Double
forall a. Fractional a => a -> a
recip Vector Double
pow10Table
{-# NOINLINE recipPow10Table #-}
tableMax :: Int
tableMax :: Int
tableMax = Int
1024
w2d :: Word64 -> Double
w2d :: Word64 -> Double
w2d Word64
w
| Word64
w Word64 -> Word64 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word64
9007199254740991 = Int -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word64
w :: Int)
| Bool
otherwise = Integer -> Double
forall a. Num a => Integer -> a
fromInteger (Word64 -> Integer
forall a. Integral a => a -> Integer
toInteger Word64
w)
{-# INLINE w2d #-}
referenceSlice :: BS.ByteString -> Int -> Int -> (# Int#, Double# #)
referenceSlice :: ByteString -> Int -> Int -> (# Int#, Double# #)
referenceSlice ByteString
bs Int
start Int
end =
case HasCallStack => ByteString -> Maybe Double
ByteString -> Maybe Double
readByteStringDouble (Int -> ByteString -> ByteString
BSU.unsafeTake (Int
end Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
start) (Int -> ByteString -> ByteString
BSU.unsafeDrop Int
start ByteString
bs)) of
Just (D# Double#
d) -> (# Int#
1#, Double#
d #)
Maybe Double
Nothing -> (# Int#
0#, Double#
0.0## #)
{-# NOINLINE referenceSlice #-}
parseDoubleField# :: BS.ByteString -> Int -> Int -> (# Int#, Double# #)
parseDoubleField# :: ByteString -> Int -> Int -> (# Int#, Double# #)
parseDoubleField# ByteString
bs Int
start Int
end0
| Int
i0 Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
end = (# Int#, Double# #)
none
| Bool
otherwise =
let !c0 :: Word8
c0 = ByteString -> Int -> Word8
BSU.unsafeIndex ByteString
bs Int
i0
!neg :: Bool
neg = Word8
c0 Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8
0x2D
!i1 :: Int
i1 = if Bool
neg Bool -> Bool -> Bool
|| Word8
c0 Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8
0x2B then Int
i0 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1 else Int
i0
in if Int
i1 Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
end Bool -> Bool -> Bool
|| Bool -> Bool
not (Word8 -> Bool
isDigitByte (ByteString -> Int -> Word8
BSU.unsafeIndex ByteString
bs Int
i1))
then (# Int#, Double# #)
none
else
let !iz :: Int
iz = ByteString -> Int -> Int -> Int
skipZeroes ByteString
bs Int
i1 Int
end
in ByteString
-> Int
-> Int
-> (Int -> Word64 -> (# Int#, Double# #))
-> (# Int#, Double# #)
forall r. ByteString -> Int -> Int -> (Int -> Word64 -> r) -> r
takeDigits64 ByteString
bs Int
iz Int
end ((Int -> Word64 -> (# Int#, Double# #)) -> (# Int#, Double# #))
-> (Int -> Word64 -> (# Int#, Double# #)) -> (# Int#, Double# #)
forall a b. (a -> b) -> a -> b
$ \Int
wEnd Word64
w ->
if Int
wEnd Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
iz Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
19
then ByteString -> Int -> Int -> (# Int#, Double# #)
referenceSlice ByteString
bs Int
start Int
end0
else Bool -> Word64 -> Int -> (# Int#, Double# #)
afterWhole Bool
neg Word64
w Int
wEnd
where
!i0 :: Int
i0 = ByteString -> Int -> Int -> Int
skipStrip ByteString
bs Int
start Int
end0
!end :: Int
end = ByteString -> Int -> Int -> Int
skipStripEnd ByteString
bs Int
i0 Int
end0
none :: (# Int#, Double# #)
none = (# Int#
0#, Double#
0.0## #)
afterWhole :: Bool -> Word64 -> Int -> (# Int#, Double# #)
afterWhole !Bool
neg !Word64
w !Int
i
| Int
i Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
end Bool -> Bool -> Bool
&& ByteString -> Int -> Word8
BSU.unsafeIndex ByteString
bs Int
i Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8
0x2E =
let !f0 :: Int
f0 = Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1
!fz :: Int
fz = ByteString -> Int -> Int -> Int
skipZeroes ByteString
bs Int
f0 Int
end
in ByteString
-> Int
-> Int
-> (Int -> Word64 -> (# Int#, Double# #))
-> (# Int#, Double# #)
forall r. ByteString -> Int -> Int -> (Int -> Word64 -> r) -> r
takeDigits64 ByteString
bs Int
fz Int
end ((Int -> Word64 -> (# Int#, Double# #)) -> (# Int#, Double# #))
-> (Int -> Word64 -> (# Int#, Double# #)) -> (# Int#, Double# #)
forall a b. (a -> b) -> a -> b
$ \Int
fEnd Word64
p ->
if Int
fEnd Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
f0
then (# Int#, Double# #)
none
else
if Int
fEnd Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
fz Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
19
then ByteString -> Int -> Int -> (# Int#, Double# #)
referenceSlice ByteString
bs Int
start Int
end0
else Bool -> Double -> Int -> (# Int#, Double# #)
afterExponent Bool
neg (Word64 -> Double
w2d Word64
w Double -> Double -> Double
forall a. Num a => a -> a -> a
+ (Word64 -> Double
w2d Word64
p Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ Int -> Double
pow10 (Int
fEnd Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
f0))) Int
fEnd
| Bool
otherwise = Bool -> Double -> Int -> (# Int#, Double# #)
afterExponent Bool
neg (Word64 -> Double
w2d Word64
w) Int
i
afterExponent :: Bool -> Double -> Int -> (# Int#, Double# #)
afterExponent !Bool
neg !Double
val !Int
i
| Int
i Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
end = Bool -> Double -> (# Int#, Double# #)
done Bool
neg Double
val
| ByteString -> Int -> Word8
BSU.unsafeIndex ByteString
bs Int
i Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8
0x65 Bool -> Bool -> Bool
|| ByteString -> Int -> Word8
BSU.unsafeIndex ByteString
bs Int
i Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8
0x45 =
let !i1 :: Int
i1 = Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1
!eneg :: Bool
eneg = Int
i1 Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
end Bool -> Bool -> Bool
&& ByteString -> Int -> Word8
BSU.unsafeIndex ByteString
bs Int
i1 Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8
0x2D
!i2 :: Int
i2 = if Int
i1 Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
end Bool -> Bool -> Bool
&& (Bool
eneg Bool -> Bool -> Bool
|| ByteString -> Int -> Word8
BSU.unsafeIndex ByteString
bs Int
i1 Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8
0x2B) then Int
i1 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1 else Int
i1
in if Int
i2 Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
end Bool -> Bool -> Bool
|| Bool -> Bool
not (Word8 -> Bool
isDigitByte (ByteString -> Int -> Word8
BSU.unsafeIndex ByteString
bs Int
i2))
then (# Int#, Double# #)
none
else
let !ez :: Int
ez = ByteString -> Int -> Int -> Int
skipZeroes ByteString
bs Int
i2 Int
end
in ByteString
-> Int
-> Int
-> (Int -> Word64 -> (# Int#, Double# #))
-> (# Int#, Double# #)
forall r. ByteString -> Int -> Int -> (Int -> Word64 -> r) -> r
takeDigits64 ByteString
bs Int
ez Int
end ((Int -> Word64 -> (# Int#, Double# #)) -> (# Int#, Double# #))
-> (Int -> Word64 -> (# Int#, Double# #)) -> (# Int#, Double# #)
forall a b. (a -> b) -> a -> b
$ \Int
eEnd Word64
e ->
if Int
eEnd Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
/= Int
end
then (# Int#, Double# #)
none
else
if Int
eEnd Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
ez Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
18
then ByteString -> Int -> Int -> (# Int#, Double# #)
referenceSlice ByteString
bs Int
start Int
end0
else Bool -> Double -> (# Int#, Double# #)
done Bool
neg (Double
val Double -> Double -> Double
forall a. Num a => a -> a -> a
* Bool -> Int -> Double
scale Bool
eneg (Word64 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word64
e))
| Bool
otherwise = (# Int#, Double# #)
none
scale :: Bool -> Int -> Double
scale !Bool
eneg !Int
ex
| Bool
eneg = Vector Double -> Int -> Double
forall a. Unbox a => Vector a -> Int -> a
VU.unsafeIndex Vector Double
recipPow10Table Int
k
| Bool
otherwise = Vector Double -> Int -> Double
forall a. Unbox a => Vector a -> Int -> a
VU.unsafeIndex Vector Double
pow10Table Int
k
where
!k :: Int
k = Int -> Int -> Int
forall a. Ord a => a -> a -> a
min Int
ex Int
tableMax
{-# INLINE scale #-}
pow10 :: Int -> Double
pow10 !Int
k = Vector Double -> Int -> Double
forall a. Unbox a => Vector a -> Int -> a
VU.unsafeIndex Vector Double
pow10Table (Int -> Int -> Int
forall a. Ord a => a -> a -> a
min Int
k Int
tableMax)
{-# INLINE pow10 #-}
done :: Bool -> Double -> (# Int#, Double# #)
done !Bool
neg !Double
v = case if Bool
neg then Double -> Double
forall a. Num a => a -> a
negate Double
v else Double
v of
D# Double#
d -> (# Int#
1#, Double#
d #)
{-# INLINE done #-}
{-# INLINE parseDoubleField# #-}