module Optics.Extra.Internal.ByteString
( traversedStrictTree
, traversedStrictTree8
, traversedLazy
, traversedLazy8
) where
import Data.Bits
import Data.Char
import Data.Int
import Data.Word
import Foreign.ForeignPtr
import Foreign.Ptr
import Foreign.Storable
import GHC.Base (unsafeChr)
import GHC.ForeignPtr (mallocPlainForeignPtrBytes)
import GHC.IO (unsafeDupablePerformIO)
import qualified Data.ByteString as B
import qualified Data.ByteString.Char8 as B8
import qualified Data.ByteString.Lazy as BL
import qualified Data.ByteString.Lazy.Char8 as BL8
import qualified Data.ByteString.Internal as BI
import qualified Data.ByteString.Unsafe as BU
import Optics.Core
import Optics.Internal.Fold
import Optics.Internal.IxFold
import Optics.Internal.Optic
import Optics.Internal.Profunctor
traversedStrictTree :: IxTraversal' Int64 B.ByteString Word8
traversedStrictTree = Optic traversedStrictTree__
{-# INLINE traversedStrictTree #-}
traversedStrictTree8 :: IxTraversal' Int64 B8.ByteString Char
traversedStrictTree8 = Optic traversedStrictTree8__
{-# INLINE traversedStrictTree8 #-}
traversedLazy :: IxTraversal' Int64 BL.ByteString Word8
traversedLazy = Optic traversedLazy__
{-# INLINE traversedLazy #-}
traversedLazy8 :: IxTraversal' Int64 BL.ByteString Char
traversedLazy8 = Optic traversedLazy8__
{-# INLINE traversedLazy8 #-}
grain :: Int64
grain = 32
{-# INLINE grain #-}
traversedStrictTree__
:: Traversing p
=> Optic__ p j (Int64 -> j) B.ByteString B.ByteString Word8 Word8
traversedStrictTree__ = iwander $ \f bs ->
let len = B.length bs
go !i !j
| i + grain < j, k <- i + shiftR (j - i) 1 =
(\l r q -> l q >> r q) <$> go i k <*> go k j
| otherwise = run i j
run !(i::Int64) !(j::Int64)
| i == j = pure (\_ -> return ())
| otherwise =
let !i' = fromIntegral i
!x = BU.unsafeIndex bs i'
in (\y ys q -> pokeByteOff q i' y >> ys q)
<$> f i x
<*> run (i + 1) j
in unsafeCreate len <$> go 0 (fromIntegral len)
{-# INLINE [0] traversedStrictTree__ #-}
{-# RULES
"bytes -> map"
forall (o :: FunArrow j Word8 Word8). traversedStrictTree__ o
= roam B.map (reFunArrow o)
:: FunArrow (Int64 -> j) B.ByteString B.ByteString
"bytes -> imap"
forall (o :: IxFunArrow j Word8 Word8). traversedStrictTree__ o = iroam imapB o
:: IxFunArrow (Int64 -> j) B.ByteString B.ByteString
"bytes -> foldr"
forall (o :: Forget r j Word8 Word8). traversedStrictTree__ o
= foldring__ B.foldr (reForget o)
:: Forget r (Int64 -> j) B.ByteString B.ByteString
"bytes -> ifoldr"
forall (o :: IxForget r j Word8 Word8). traversedStrictTree__ o
= ifoldring__ ifoldrB o
:: IxForget r (Int64 -> j) B.ByteString B.ByteString
#-}
imapB :: (Int64 -> Word8 -> Word8) -> B.ByteString -> B.ByteString
imapB f = snd . B.mapAccumL (\i a -> i `seq` (i + 1, f i a)) 0
{-# INLINE imapB #-}
ifoldrB :: (Int64 -> Word8 -> a -> a) -> a -> B.ByteString -> a
ifoldrB f z xs = B.foldr (\x g i -> i `seq` f i x (g (i + 1))) (const z) xs 0
{-# INLINE ifoldrB #-}
traversedStrictTree8__
:: Traversing p
=> Optic__ p j (Int64 -> j) B8.ByteString B8.ByteString Char Char
traversedStrictTree8__ = iwander $ \f bs ->
let len = B.length bs
go !i !j
| i + grain < j, k <- i + shiftR (j - i) 1 =
(\l r q -> l q >> r q) <$> go i k <*> go k j
| otherwise = run i j
run !(i::Int64) !(j::Int64)
| i == j = pure (\_ -> return ())
| otherwise =
let !i' = fromIntegral i
!x = BU.unsafeIndex bs i'
in (\y ys q -> pokeByteOff q i' (c2w y) >> ys q)
<$> f i (w2c x)
<*> run (i + 1) j
in unsafeCreate len <$> go 0 (fromIntegral len)
{-# INLINE [0] traversedStrictTree8__ #-}
{-# RULES
"chars -> map"
forall (o :: FunArrow j Char Char). traversedStrictTree8__ o
= roam B8.map (reFunArrow o)
:: FunArrow (Int64 -> j) B8.ByteString B8.ByteString
"chars -> imap"
forall (o :: IxFunArrow j Char Char). traversedStrictTree8__ o = iroam imapB8 o
:: IxFunArrow (Int64 -> j) B8.ByteString B8.ByteString
"chars -> foldr"
forall (o :: Forget r j Char Char). traversedStrictTree8__ o
= foldring__ B8.foldr (reForget o)
:: Forget r (Int64 -> j) B8.ByteString B8.ByteString
"chars -> ifoldr"
forall (o :: IxForget r j Char Char). traversedStrictTree8__ o
= ifoldring__ ifoldrB8 o
:: IxForget r (Int64 -> j) B8.ByteString B8.ByteString
#-}
imapB8 :: (Int64 -> Char -> Char) -> B.ByteString -> B.ByteString
imapB8 f = snd . B8.mapAccumL (\i a -> i `seq` (i + 1, f i a)) 0
{-# INLINE imapB8 #-}
ifoldrB8 :: (Int64 -> Char -> a -> a) -> a -> B.ByteString -> a
ifoldrB8 f z xs = B8.foldr (\x g i -> i `seq` f i x (g (i + 1))) (const z) xs 0
{-# INLINE ifoldrB8 #-}
traversedLazy__
:: Traversing p
=> Optic__ p j (Int64 -> j) BL.ByteString BL.ByteString Word8 Word8
traversedLazy__ = iwander $ \f lbs ->
let go c fcs acc =
let !acc' = acc + fromIntegral (B.length c)
rest = reindexed (\x -> acc + x) traversedStrictTree
in BL.append . BL.fromStrict <$> itraverseOf rest f c <*> fcs acc'
in BL.foldrChunks go (\_ -> pure BL.empty) lbs 0
{-# INLINE [1] traversedLazy__ #-}
{-# RULES
"sets lazy bytestring"
forall (o :: FunArrow j Word8 Word8). traversedLazy__ o
= roam BL.map (reFunArrow o)
:: FunArrow (Int64 -> j) BL.ByteString BL.ByteString
"isets lazy bytestring"
forall (o :: IxFunArrow j Word8 Word8). traversedLazy__ o = iroam imapBL o
:: IxFunArrow (Int64 -> j) BL.ByteString BL.ByteString
"gets lazy bytestring"
forall (o :: Forget r j Word8 Word8). traversedLazy__ o
= foldring__ BL.foldr (reForget o)
:: Forget r (Int64 -> j) BL.ByteString BL.ByteString
"igets lazy bytestring"
forall (o :: IxForget r j Word8 Word8). traversedLazy__ o = ifoldring__ ifoldrBL o
:: IxForget r (Int64 -> j) BL.ByteString BL.ByteString
#-}
imapBL :: (Int64 -> Word8 -> Word8) -> BL.ByteString -> BL.ByteString
imapBL f = snd . BL.mapAccumL (\i a -> i `seq` (i + 1, f i a)) 0
{-# INLINE imapBL #-}
ifoldrBL :: (Int64 -> Word8 -> a -> a) -> a -> BL.ByteString -> a
ifoldrBL f z xs = BL.foldr (\x g i -> i `seq` f i x (g (i + 1))) (const z) xs 0
{-# INLINE ifoldrBL #-}
traversedLazy8__
:: Traversing p
=> Optic__ p j (Int64 -> j) BL.ByteString BL.ByteString Char Char
traversedLazy8__ = iwander $ \f lbs ->
let go c fcs acc =
let !acc' = acc + fromIntegral (B.length c)
rest = reindexed (\x -> acc + x) traversedStrictTree8
in BL.append . BL.fromStrict <$> itraverseOf rest f c <*> fcs acc'
in BL.foldrChunks go (\_ -> pure BL.empty) lbs 0
{-# INLINE [1] traversedLazy8__ #-}
{-# RULES
"sets lazy char bytestring"
forall (o :: FunArrow j Char Char). traversedLazy8__ o
= roam BL8.map (reFunArrow o)
:: FunArrow (Int64 -> j) BL8.ByteString BL8.ByteString
"isets lazy char bytestring"
forall (o :: IxFunArrow j Char Char). traversedLazy8__ o = iroam imapBL8 o
:: IxFunArrow (Int64 -> j) BL8.ByteString BL8.ByteString
"gets lazy char bytestring"
forall (o :: Forget r j Char Char). traversedLazy8__ o
= foldring__ BL8.foldr (reForget o)
:: Forget r (Int64 -> j) BL8.ByteString BL8.ByteString
"igets lazy char bytestring"
forall (o :: IxForget r j Char Char). traversedLazy8__ o = ifoldring__ ifoldrBL8 o
:: IxForget r (Int64 -> j) BL.ByteString BL.ByteString
#-}
imapBL8 :: (Int64 -> Char -> Char) -> BL8.ByteString -> BL8.ByteString
imapBL8 f = snd . BL8.mapAccumL (\i a -> i `seq` (i + 1, f i a)) 0
{-# INLINE imapBL8 #-}
ifoldrBL8 :: (Int64 -> Char -> a -> a) -> a -> BL8.ByteString -> a
ifoldrBL8 f z xs = BL8.foldr (\x g i -> i `seq` f i x (g (i + 1))) (const z) xs 0
{-# INLINE ifoldrBL8 #-}
w2c :: Word8 -> Char
w2c = unsafeChr . fromIntegral
{-# INLINE w2c #-}
c2w :: Char -> Word8
c2w = fromIntegral . ord
{-# INLINE c2w #-}
unsafeCreate :: Int -> (Ptr Word8 -> IO ()) -> B.ByteString
unsafeCreate l f = unsafeDupablePerformIO (create l f)
{-# INLINE unsafeCreate #-}
create :: Int -> (Ptr Word8 -> IO ()) -> IO B.ByteString
create l f = do
fp <- mallocPlainForeignPtrBytes l
withForeignPtr fp $ \p -> f p
return $! BI.PS fp 0 l
{-# INLINE create #-}