{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE TypeApplications #-}
module Data.ByteString.Base64.Internal.Tail
( loopTail
, loopTailNoPad
) where
import Data.Bits
import Data.ByteString.Internal
import Data.ByteString.Base64.Internal.Utils
import Foreign.ForeignPtr
import Foreign.Ptr
import Foreign.Storable
import GHC.Exts
import GHC.Word
loopTail
:: ForeignPtr Word8
-> Ptr Word8
-> Ptr Word8
-> Ptr Word8
-> Ptr Word8
-> Ptr Word8
-> IO ByteString
loopTail :: ForeignPtr Word8
-> Ptr Word8
-> Ptr Word8
-> Ptr Word8
-> Ptr Word8
-> Ptr Word8
-> IO ByteString
loopTail !ForeignPtr Word8
dfp !Ptr Word8
dptr (Ptr !Addr#
alpha) !Ptr Word8
end !Ptr Word8
sptr_ !Ptr Word8
dptr_ = Ptr Word8 -> Ptr Word8 -> IO ByteString
go Ptr Word8
sptr_ Ptr Word8
dptr_
where
go :: Ptr Word8 -> Ptr Word8 -> IO ByteString
go Ptr Word8
src Ptr Word8
dst
| Ptr Word8
src Ptr Word8 -> Ptr Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Ptr Word8
end =
ByteString -> IO ByteString
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (ByteString -> IO ByteString) -> ByteString -> IO ByteString
forall a b. (a -> b) -> a -> b
$ ForeignPtr Word8 -> Int -> Int -> ByteString
PS ForeignPtr Word8
dfp Int
0 (Ptr Word8
dst Ptr Word8 -> Ptr Word8 -> Int
forall a b. Ptr a -> Ptr b -> Int
`minusPtr` Ptr Word8
dptr)
| Bool
otherwise = do
!x <- forall a. Storable a => Ptr a -> IO a
peek @Word8 Ptr Word8
src
let !a = Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
unsafeShiftR Word8
x Int
2
!carry0 = Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
unsafeShiftL (Word8
x Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0x03) Int
4
poke @Word8 dst $ aix a alpha
if src `plusPtr` 1 == end then do
poke @Word8 (dst `plusPtr` 1) $ aix carry0 alpha
poke @Word8 (dst `plusPtr` 2) 0x3d
poke @Word8 (dst `plusPtr` 3) 0x3d
else do
!y <- peek @Word8 $ src `plusPtr` 1
let !b = Word8
carry0 Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
unsafeShiftR (Word8
y Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0xf0) Int
4
!carry1 = Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
unsafeShiftL (Word8
y Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0x0f) Int
2
poke @Word8 (dst `plusPtr` 1) $ aix b alpha
poke @Word8 (dst `plusPtr` 2) $ aix carry1 alpha
poke @Word8 (dst `plusPtr` 3) 0x3d
pure $ PS dfp 0 (4 + minusPtr dst dptr)
{-# inline loopTail #-}
loopTailNoPad
:: ForeignPtr Word8
-> Ptr Word8
-> Ptr Word8
-> Ptr Word8
-> Ptr Word8
-> Ptr Word8
-> IO ByteString
loopTailNoPad :: ForeignPtr Word8
-> Ptr Word8
-> Ptr Word8
-> Ptr Word8
-> Ptr Word8
-> Ptr Word8
-> IO ByteString
loopTailNoPad !ForeignPtr Word8
dfp (Ptr !Addr#
alpha) !Ptr Word8
dptr !Ptr Word8
end !Ptr Word8
src !Ptr Word8
dst
| Ptr Word8
src Ptr Word8 -> Ptr Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Ptr Word8
end = ByteString -> IO ByteString
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (ForeignPtr Word8 -> Int -> Int -> ByteString
PS ForeignPtr Word8
dfp Int
0 (Ptr Word8 -> Ptr Word8 -> Int
forall a b. Ptr a -> Ptr b -> Int
minusPtr Ptr Word8
dst Ptr Word8
dptr))
| Ptr Word8 -> Int -> Ptr Word8
forall a b. Ptr a -> Int -> Ptr b
plusPtr Ptr Word8
src Int
1 Ptr Word8 -> Ptr Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Ptr Word8
end = do
!x <- forall a. Storable a => Ptr a -> IO a
peek @Word8 Ptr Word8
src
let !a = Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
unsafeShiftR (Word8
x Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0xfc) Int
2
!b = Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
unsafeShiftL (Word8
x Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0x03) Int
4
poke @Word8 dst (aix a alpha)
poke @Word8 (plusPtr dst 1) (aix b alpha)
return (PS dfp 0 (2 + minusPtr dst dptr))
| Bool
otherwise = do
!x <- forall a. Storable a => Ptr a -> IO a
peek @Word8 Ptr Word8
src
!y <- peek @Word8 (plusPtr src 1)
let !a = Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
unsafeShiftR (Word8
x Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0xfc) Int
2
!b = Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
unsafeShiftL (Word8
x Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0x03) Int
4
let !c = Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
unsafeShiftR (Word8
y Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0xf0) Int
4 Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. Word8
b
!d = Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
unsafeShiftL (Word8
y Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0x0f) Int
2
poke @Word8 dst (aix a alpha)
poke @Word8 (plusPtr dst 1) (aix c alpha)
poke @Word8 (plusPtr dst 2) (aix d alpha)
return (PS dfp 0 (3 + minusPtr dst dptr))
{-# inline loopTailNoPad #-}