{-# LANGUAGE CPP #-}
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE MultiWayIf #-}
{-# LANGUAGE PatternSynonyms #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
#ifdef BYTESTRING_STRICT
module Data.ByteString.ReadInt
#else
module Data.ByteString.Lazy.ReadInt
#endif
( readInt
, readInt8
, readInt16
, readInt32
, readWord
, readWord8
, readWord16
, readWord32
, readInt64
, readWord64
) where
import qualified Data.ByteString.Internal as BI
#ifdef BYTESTRING_STRICT
import Data.ByteString
#else
import Data.ByteString.Lazy
import Data.ByteString.Lazy.Internal
#endif
import Data.Bits (FiniteBits, isSigned)
import Data.ByteString.Internal (pattern BS, plusForeignPtr)
import Data.Int
import Data.Word
import Foreign.ForeignPtr (ForeignPtr)
import Foreign.Ptr (minusPtr, plusPtr)
import Foreign.Storable (Storable(..))
readInt :: ByteString -> Maybe (Int, ByteString)
readInt :: ByteString -> Maybe (Int, ByteString)
readInt = forall a.
(Integral a, FiniteBits a, Bounded a) =>
ByteString -> Maybe (a, ByteString)
_read
readInt32 :: ByteString -> Maybe (Int32, ByteString)
readInt32 :: ByteString -> Maybe (Int32, ByteString)
readInt32 = forall a.
(Integral a, FiniteBits a, Bounded a) =>
ByteString -> Maybe (a, ByteString)
_read
readInt16 :: ByteString -> Maybe (Int16, ByteString)
readInt16 :: ByteString -> Maybe (Int16, ByteString)
readInt16 = forall a.
(Integral a, FiniteBits a, Bounded a) =>
ByteString -> Maybe (a, ByteString)
_read
readInt8 :: ByteString -> Maybe (Int8, ByteString)
readInt8 :: ByteString -> Maybe (Int8, ByteString)
readInt8 = forall a.
(Integral a, FiniteBits a, Bounded a) =>
ByteString -> Maybe (a, ByteString)
_read
readWord :: ByteString -> Maybe (Word, ByteString)
readWord :: ByteString -> Maybe (Word, ByteString)
readWord = forall a.
(Integral a, FiniteBits a, Bounded a) =>
ByteString -> Maybe (a, ByteString)
_read
readWord32 :: ByteString -> Maybe (Word32, ByteString)
readWord32 :: ByteString -> Maybe (Word32, ByteString)
readWord32 = forall a.
(Integral a, FiniteBits a, Bounded a) =>
ByteString -> Maybe (a, ByteString)
_read
readWord16 :: ByteString -> Maybe (Word16, ByteString)
readWord16 :: ByteString -> Maybe (Word16, ByteString)
readWord16 = forall a.
(Integral a, FiniteBits a, Bounded a) =>
ByteString -> Maybe (a, ByteString)
_read
readWord8 :: ByteString -> Maybe (Word8, ByteString)
readWord8 :: ByteString -> Maybe (Word8, ByteString)
readWord8 = forall a.
(Integral a, FiniteBits a, Bounded a) =>
ByteString -> Maybe (a, ByteString)
_read
readInt64 :: ByteString -> Maybe (Int64, ByteString)
readInt64 :: ByteString -> Maybe (Int64, ByteString)
readInt64 = forall a.
(Integral a, FiniteBits a, Bounded a) =>
ByteString -> Maybe (a, ByteString)
_read
readWord64 :: ByteString -> Maybe (Word64, ByteString)
readWord64 :: ByteString -> Maybe (Word64, ByteString)
readWord64 = forall a.
(Integral a, FiniteBits a, Bounded a) =>
ByteString -> Maybe (a, ByteString)
_read
_read :: forall a. (Integral a, FiniteBits a, Bounded a)
=> ByteString -> Maybe (a, ByteString)
{-# INLINE _read #-}
_read :: forall a.
(Integral a, FiniteBits a, Bounded a) =>
ByteString -> Maybe (a, ByteString)
_read
| forall a. Bits a => a -> Bool
isSigned @a a
0
= \ ByteString
bs -> ByteString -> Maybe (Word64, ByteString, Word64)
signed ByteString
bs forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \ (Word64
r, ByteString
s, Word64
d1) -> forall a.
(Integral a, Bounded a) =>
Word64 -> ByteString -> Word64 -> Maybe (a, ByteString)
_readDecimal Word64
r ByteString
s Word64
d1
| Bool
otherwise
= \ ByteString
bs -> Word64 -> ByteString -> Maybe (Word64, ByteString, Word64)
unsigned Word64
5 ByteString
bs forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \ (Word64
r, ByteString
s, Word64
d1) -> forall a.
(Integral a, Bounded a) =>
Word64 -> ByteString -> Word64 -> Maybe (a, ByteString)
_readDecimal Word64
r ByteString
s Word64
d1
where
signed :: ByteString -> Maybe (Word64, ByteString, Word64)
signed :: ByteString -> Maybe (Word64, ByteString, Word64)
signed ByteString
bs = do
(Word8
w, ByteString
s) <- ByteString -> Maybe (Word8, ByteString)
uncons ByteString
bs
let d1 :: Word64
d1 = Word8 -> Word64
fromDigit Word8
w
if | Word64
d1 forall a. Ord a => a -> a -> Bool
<= Word64
9 -> forall a. a -> Maybe a
Just (Word64
7, ByteString
s, Word64
d1)
| Word8
w forall a. Eq a => a -> a -> Bool
== Word8
0x2d -> Word64 -> ByteString -> Maybe (Word64, ByteString, Word64)
unsigned Word64
8 ByteString
s
| Word8
w forall a. Eq a => a -> a -> Bool
== Word8
0x2b -> Word64 -> ByteString -> Maybe (Word64, ByteString, Word64)
unsigned Word64
7 ByteString
s
| Bool
otherwise -> forall a. Maybe a
Nothing
unsigned :: Word64 -> ByteString -> Maybe (Word64, ByteString, Word64)
unsigned :: Word64 -> ByteString -> Maybe (Word64, ByteString, Word64)
unsigned Word64
r ByteString
bs = do
(Word8
w, ByteString
s) <- ByteString -> Maybe (Word8, ByteString)
uncons ByteString
bs
let d1 :: Word64
d1 = Word8 -> Word64
fromDigit Word8
w
if | Word64
d1 forall a. Ord a => a -> a -> Bool
<= Word64
9 -> forall a. a -> Maybe a
Just (Word64
r, ByteString
s, Word64
d1)
| Bool
otherwise -> forall a. Maybe a
Nothing
data Result = Overflow
| Result !Int
!Word64
_readDecimal :: forall a. (Integral a, Bounded a)
=> Word64
-> ByteString
-> Word64
-> Maybe (a, ByteString)
{-# INLINE _readDecimal #-}
_readDecimal :: forall a.
(Integral a, Bounded a) =>
Word64 -> ByteString -> Word64 -> Maybe (a, ByteString)
_readDecimal !Word64
r = ByteString -> Word64 -> Maybe (a, ByteString)
consume
where
consume :: ByteString -> Word64 -> Maybe (a, ByteString)
#ifdef BYTESTRING_STRICT
consume (BS fp len) a = case _digits q r fp len a of
Result used acc
| used == len
-> convert acc empty
| otherwise
-> convert acc $ BS (fp `plusForeignPtr` used) (len - used)
_ -> Nothing
#else
consume :: ByteString -> Word64 -> Maybe (a, ByteString)
consume ByteString
Empty Word64
acc = Word64 -> ByteString -> Maybe (a, ByteString)
convert Word64
acc ByteString
Empty
consume (Chunk (BS ForeignPtr Word8
fp Int
len) ByteString
cs) Word64
acc
= case Word64 -> Word64 -> ForeignPtr Word8 -> Int -> Word64 -> Result
_digits Word64
q Word64
r ForeignPtr Word8
fp Int
len Word64
acc of
Result Int
used Word64
acc'
| Int
used forall a. Eq a => a -> a -> Bool
== Int
len
-> ByteString -> Word64 -> Maybe (a, ByteString)
consume ByteString
cs Word64
acc'
| Bool
otherwise
-> Word64 -> ByteString -> Maybe (a, ByteString)
convert Word64
acc' forall a b. (a -> b) -> a -> b
$
ByteString -> ByteString -> ByteString
Chunk (ForeignPtr Word8 -> Int -> ByteString
BS (ForeignPtr Word8
fp forall a b. ForeignPtr a -> Int -> ForeignPtr b
`plusForeignPtr` Int
used) (Int
len forall a. Num a => a -> a -> a
- Int
used)) ByteString
cs
Result
_ -> forall a. Maybe a
Nothing
#endif
convert :: Word64 -> ByteString -> Maybe (a, ByteString)
convert :: Word64 -> ByteString -> Maybe (a, ByteString)
convert !Word64
acc ByteString
rest =
let !i :: a
i = case Word64
r of
Word64
8 -> forall a. Num a => a -> a
negate forall a b. (a -> b) -> a -> b
$ forall a b. (Integral a, Num b) => a -> b
fromIntegral @Word64 @a Word64
acc
Word64
_ -> forall a b. (Integral a, Num b) => a -> b
fromIntegral @Word64 @a Word64
acc
in forall a. a -> Maybe a
Just (a
i, ByteString
rest)
q :: Word64
q = forall a b. (Integral a, Num b) => a -> b
fromIntegral @a @Word64 forall a. Bounded a => a
maxBound forall a. Integral a => a -> a -> a
`div` Word64
10
_digits :: Word64
-> Word64
-> ForeignPtr Word8
-> Int
-> Word64
-> Result
{-# INLINE _digits #-}
_digits :: Word64 -> Word64 -> ForeignPtr Word8 -> Int -> Word64 -> Result
_digits !Word64
q !Word64
r ForeignPtr Word8
fp Int
len Word64
a = forall a. IO a -> a
BI.accursedUnutterablePerformIO forall a b. (a -> b) -> a -> b
$
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
BI.unsafeWithForeignPtr ForeignPtr Word8
fp forall a b. (a -> b) -> a -> b
$ \ Ptr Word8
ptr -> do
let end :: Ptr b
end = Ptr Word8
ptr forall a b. Ptr a -> Int -> Ptr b
`plusPtr` Int
len
forall {b}. Ptr b -> Ptr Word8 -> Ptr Word8 -> Word64 -> IO Result
go Ptr Word8
ptr forall {b}. Ptr b
end Ptr Word8
ptr Word64
a
where
go :: Ptr b -> Ptr Word8 -> Ptr Word8 -> Word64 -> IO Result
go !Ptr b
start !Ptr Word8
end = Ptr Word8 -> Word64 -> IO Result
loop
where
loop :: Ptr Word8 -> Word64 -> IO Result
loop !Ptr Word8
ptr !Word64
acc = IO Word64
getDigit forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \ !Word64
d ->
if | Word64
d forall a. Ord a => a -> a -> Bool
> Word64
9
-> forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ Int -> Word64 -> Result
Result (Ptr Word8
ptr forall a b. Ptr a -> Ptr b -> Int
`minusPtr` Ptr b
start) Word64
acc
| Word64
acc forall a. Ord a => a -> a -> Bool
< Word64
q Bool -> Bool -> Bool
|| Word64
acc forall a. Eq a => a -> a -> Bool
== Word64
q Bool -> Bool -> Bool
&& Word64
d forall a. Ord a => a -> a -> Bool
<= Word64
r
-> Ptr Word8 -> Word64 -> IO Result
loop (Ptr Word8
ptr forall a b. Ptr a -> Int -> Ptr b
`plusPtr` Int
1) (Word64
acc forall a. Num a => a -> a -> a
* Word64
10 forall a. Num a => a -> a -> a
+ Word64
d)
| Bool
otherwise
-> forall (m :: * -> *) a. Monad m => a -> m a
return Result
Overflow
where
getDigit :: IO Word64
getDigit :: IO Word64
getDigit
| Ptr Word8
ptr forall a. Eq a => a -> a -> Bool
/= Ptr Word8
end = Word8 -> Word64
fromDigit forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall a. Storable a => Ptr a -> IO a
peek Ptr Word8
ptr
| Bool
otherwise = forall (f :: * -> *) a. Applicative f => a -> f a
pure Word64
10
{-# NOINLINE getDigit #-}
fromDigit :: Word8 -> Word64
{-# INLINE fromDigit #-}
fromDigit :: Word8 -> Word64
fromDigit = \ !Word8
w -> forall a b. (Integral a, Num b) => a -> b
fromIntegral Word8
w forall a. Num a => a -> a -> a
- Word64
0x30