-- |
-- Module      : Streamly.Internal.Data.MutArray
-- Copyright   : (c) 2020 Composewell Technologies
-- License     : BSD-3-Clause
-- Maintainer  : streamly@composewell.com
-- Stability   : experimental
-- Portability : GHC

-- XXX To detect array overflow issues we can have a debug mode in RTS where we
-- allocate one additional page beyond a large allocation and unmap that page
-- so that we get segfault if it is accessed. Also any unpinned large
-- allocations can be kept unmapped for a while after being freed in case those
-- are being used by someone, also we can aggressively move such pages to
-- detect problems more quickly.
--
module Streamly.Internal.Data.MutArray
    (
    -- * MutArray.Type module
      module Streamly.Internal.Data.MutArray.Type
    -- * MutArray module
    , indexerFromLen
    , splitterFromLen
    -- , splitFromLen
    -- , slicesOf
    , compactMax
    , compactMax'
    , compactSepByByte_
    , compactEndByByte_
    , compactEndByLn_
    , createOfLast

    -- XXX Do not expose these yet, we should perhaps expose only the Get/Put
    -- monads instead? Decide after implementing the monads.

    -- * Serialization
    , serialize
    , deserialize
    , serializePtrN
    , deserializePtrN

    -- * Deprecated
    , slicerFromLen
    , sliceIndexerFromLen
    , genSlicesFromLen
    , getSlicesFromLen
    , compactLE
    , pinnedCompactLE
    , compactOnByte
    , compactOnByteSuffix
    , IORef
    , newIORef
    , writeIORef
    , modifyIORef'
    , readIORef
    , pollIntIORef
    )
where

#include "assert.hs"
#include "deprecation.h"
#include "inline.hs"
#include "ArrayMacros.h"

import Control.Monad.IO.Class (MonadIO(..))
import Data.Word (Word8)
import Foreign.Ptr (Ptr)
import Streamly.Internal.Data.MutByteArray.Type (PinnedState(..))
import Streamly.Internal.Data.Serialize.Type (Serialize)
import Streamly.Internal.Data.Stream.Type (Stream)
import Streamly.Internal.Data.Unbox (Unbox)
import Streamly.Internal.Data.Unfold.Type (Unfold(..))
import Streamly.Internal.Data.Fold.Type (Fold)

import qualified Streamly.Internal.Data.IORef as IORef
import qualified Streamly.Internal.Data.RingArray as RingArray
import qualified Streamly.Internal.Data.Serialize.Type as Serialize
import qualified Streamly.Internal.Data.Stream.Nesting as Stream
import qualified Streamly.Internal.Data.Stream.Type as Stream
import qualified Streamly.Internal.Data.Fold.Type as Fold
-- import qualified Streamly.Internal.Data.Stream.Transform as Stream
import qualified Streamly.Internal.Data.Unfold as Unfold

import Prelude hiding (foldr, length, read, splitAt)
import Streamly.Internal.Data.MutArray.Type

-- | Generate a stream of array slice descriptors ((index, len)) of specified
-- length from an array, starting from the supplied array index. The last slice
-- may be shorter than the requested length depending on the array length.
--
-- /Pre-release/
{-# INLINE indexerFromLen #-}
indexerFromLen, sliceIndexerFromLen :: forall m a. (Monad m, Unbox a)
    => Int -- ^ from index
    -> Int -- ^ length of the slice
    -> Unfold m (MutArray a) (Int, Int)
indexerFromLen :: forall (m :: * -> *) a.
(Monad m, Unbox a) =>
Int -> Int -> Unfold m (MutArray a) (Int, Int)
indexerFromLen Int
from Int
len =
    let fromThenTo :: c -> (Int, Int, c)
fromThenTo c
n = (Int
from, Int
from Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
len, c
n c -> c -> c
forall a. Num a => a -> a -> a
- c
1)
        mkSlice :: Int -> Int -> m (Int, Int)
mkSlice Int
n Int
i = (Int, Int) -> m (Int, Int)
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (Int
i, Int -> Int -> Int
forall a. Ord a => a -> a -> a
min Int
len (Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
i))
     in (MutArray a -> Int)
-> Unfold m Int (Int, Int) -> Unfold m (MutArray a) (Int, Int)
forall a c (m :: * -> *) b.
(a -> c) -> Unfold m c b -> Unfold m a b
Unfold.lmap MutArray a -> Int
forall a. Unbox a => MutArray a -> Int
length
        (Unfold m Int (Int, Int) -> Unfold m (MutArray a) (Int, Int))
-> Unfold m Int (Int, Int) -> Unfold m (MutArray a) (Int, Int)
forall a b. (a -> b) -> a -> b
$ (Int -> Int -> m (Int, Int))
-> Unfold m Int Int -> Unfold m Int (Int, Int)
forall (m :: * -> *) a b c.
Monad m =>
(a -> b -> m c) -> Unfold m a b -> Unfold m a c
Unfold.mapM2 Int -> Int -> m (Int, Int)
forall {m :: * -> *}. Monad m => Int -> Int -> m (Int, Int)
mkSlice
        (Unfold m Int Int -> Unfold m Int (Int, Int))
-> Unfold m Int Int -> Unfold m Int (Int, Int)
forall a b. (a -> b) -> a -> b
$ (Int -> (Int, Int, Int))
-> Unfold m (Int, Int, Int) Int -> Unfold m Int Int
forall a c (m :: * -> *) b.
(a -> c) -> Unfold m c b -> Unfold m a b
Unfold.lmap Int -> (Int, Int, Int)
forall {c}. Num c => c -> (Int, Int, c)
fromThenTo Unfold m (Int, Int, Int) Int
forall a (m :: * -> *).
(Enumerable a, Monad m) =>
Unfold m (a, a, a) a
forall (m :: * -> *). Monad m => Unfold m (Int, Int, Int) Int
Unfold.enumerateFromThenTo
RENAME(sliceIndexerFromLen,indexerFromLen)

{-# DEPRECATED genSlicesFromLen "Please use indexerFromLen instead." #-}
genSlicesFromLen :: forall m a. (Monad m, Unbox a)
    => Int -- ^ from index
    -> Int -- ^ length of the slice
    -> Unfold m (MutArray a) (Int, Int)
genSlicesFromLen :: forall (m :: * -> *) a.
(Monad m, Unbox a) =>
Int -> Int -> Unfold m (MutArray a) (Int, Int)
genSlicesFromLen = Int -> Int -> Unfold m (MutArray a) (Int, Int)
forall (m :: * -> *) a.
(Monad m, Unbox a) =>
Int -> Int -> Unfold m (MutArray a) (Int, Int)
indexerFromLen

-- | Generate a stream of slices of specified length from an array, starting
-- from the supplied array index. The last slice may be shorter than the
-- requested length depending on the array length.
--
-- /Pre-release/
{-# INLINE splitterFromLen #-}
splitterFromLen, slicerFromLen :: forall m a. (Monad m, Unbox a)
    => Int -- ^ from index
    -> Int -- ^ length of the slice
    -> Unfold m (MutArray a) (MutArray a)
splitterFromLen :: forall (m :: * -> *) a.
(Monad m, Unbox a) =>
Int -> Int -> Unfold m (MutArray a) (MutArray a)
splitterFromLen Int
from Int
len =
    let mkSlice :: MutArray a -> (Int, Int) -> m (MutArray a)
mkSlice MutArray a
arr (Int
i, Int
n) = MutArray a -> m (MutArray a)
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (MutArray a -> m (MutArray a)) -> MutArray a -> m (MutArray a)
forall a b. (a -> b) -> a -> b
$ Int -> Int -> MutArray a -> MutArray a
forall a. Unbox a => Int -> Int -> MutArray a -> MutArray a
unsafeSliceOffLen Int
i Int
n MutArray a
arr
     in (MutArray a -> (Int, Int) -> m (MutArray a))
-> Unfold m (MutArray a) (Int, Int)
-> Unfold m (MutArray a) (MutArray a)
forall (m :: * -> *) a b c.
Monad m =>
(a -> b -> m c) -> Unfold m a b -> Unfold m a c
Unfold.mapM2 MutArray a -> (Int, Int) -> m (MutArray a)
forall {m :: * -> *} {a}.
(Monad m, Unbox a) =>
MutArray a -> (Int, Int) -> m (MutArray a)
mkSlice (Int -> Int -> Unfold m (MutArray a) (Int, Int)
forall (m :: * -> *) a.
(Monad m, Unbox a) =>
Int -> Int -> Unfold m (MutArray a) (Int, Int)
indexerFromLen Int
from Int
len)
RENAME(slicerFromLen,splitterFromLen)

{-# DEPRECATED getSlicesFromLen "Please use splitterFromLen instead." #-}
getSlicesFromLen :: forall m a. (Monad m, Unbox a)
    => Int -- ^ from index
    -> Int -- ^ length of the slice
    -> Unfold m (MutArray a) (MutArray a)
getSlicesFromLen :: forall (m :: * -> *) a.
(Monad m, Unbox a) =>
Int -> Int -> Unfold m (MutArray a) (MutArray a)
getSlicesFromLen = Int -> Int -> Unfold m (MutArray a) (MutArray a)
forall (m :: * -> *) a.
(Monad m, Unbox a) =>
Int -> Int -> Unfold m (MutArray a) (MutArray a)
splitterFromLen

--------------------------------------------------------------------------------
-- Serialization/Deserialization using Serialize
--------------------------------------------------------------------------------

{-# INLINE unsafeSerialize #-}
unsafeSerialize :: (MonadIO m, Serialize a) =>
    MutArray Word8 -> a -> m (MutArray Word8)
unsafeSerialize :: forall (m :: * -> *) a.
(MonadIO m, Serialize a) =>
MutArray Word8 -> a -> m (MutArray Word8)
unsafeSerialize (MutArray MutByteArray
mbarr Int
start Int
end Int
bound) a
a = do
#ifdef DEBUG
    let len = Serialize.addSizeTo 0 a
    assertM(bound - end >= len)
#endif
    Int
off <- IO Int -> m Int
forall a. IO a -> m a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO Int -> m Int) -> IO Int -> m Int
forall a b. (a -> b) -> a -> b
$ Int -> MutByteArray -> a -> IO Int
forall a. Serialize a => Int -> MutByteArray -> a -> IO Int
Serialize.serializeAt Int
end MutByteArray
mbarr a
a
    MutArray Word8 -> m (MutArray Word8)
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (MutArray Word8 -> m (MutArray Word8))
-> MutArray Word8 -> m (MutArray Word8)
forall a b. (a -> b) -> a -> b
$ MutByteArray -> Int -> Int -> Int -> MutArray Word8
forall a. MutByteArray -> Int -> Int -> Int -> MutArray a
MutArray MutByteArray
mbarr Int
start Int
off Int
bound

{-# NOINLINE serializeRealloc #-}
serializeRealloc :: forall m a. (MonadIO m, Serialize a) =>
       (Int -> Int)
    -> MutArray Word8
    -> a
    -> m (MutArray Word8)
serializeRealloc :: forall (m :: * -> *) a.
(MonadIO m, Serialize a) =>
(Int -> Int) -> MutArray Word8 -> a -> m (MutArray Word8)
serializeRealloc Int -> Int
sizer MutArray Word8
arr a
x = do
    let len :: Int
len = Int -> a -> Int
forall a. Serialize a => Int -> a -> Int
Serialize.addSizeTo Int
0 a
x
    MutArray Word8
arr1 <- IO (MutArray Word8) -> m (MutArray Word8)
forall a. IO a -> m a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO (MutArray Word8) -> m (MutArray Word8))
-> IO (MutArray Word8) -> m (MutArray Word8)
forall a b. (a -> b) -> a -> b
$ String
-> (Int -> Int) -> Int -> MutArray Word8 -> IO (MutArray Word8)
forall (m :: * -> *) a.
(MonadIO m, Unbox a) =>
String -> (Int -> Int) -> Int -> MutArray a -> m (MutArray a)
reallocBytesWith String
"serializeRealloc" Int -> Int
sizer Int
len MutArray Word8
arr
    MutArray Word8 -> a -> m (MutArray Word8)
forall (m :: * -> *) a.
(MonadIO m, Serialize a) =>
MutArray Word8 -> a -> m (MutArray Word8)
unsafeSerialize MutArray Word8
arr1 a
x

{-# INLINE serializeWith #-}
serializeWith :: forall m a. (MonadIO m, Serialize a) =>
       (Int -> Int)
    -> MutArray Word8
    -> a
    -> m (MutArray Word8)
serializeWith :: forall (m :: * -> *) a.
(MonadIO m, Serialize a) =>
(Int -> Int) -> MutArray Word8 -> a -> m (MutArray Word8)
serializeWith Int -> Int
sizer arr :: MutArray Word8
arr@(MutArray MutByteArray
mbarr Int
start Int
end Int
bound) a
x = do
    let len :: Int
len = Int -> a -> Int
forall a. Serialize a => Int -> a -> Int
Serialize.addSizeTo Int
0 a
x
    if (Int
bound Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
end) Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
len
    then do
        Int
off <- IO Int -> m Int
forall a. IO a -> m a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO Int -> m Int) -> IO Int -> m Int
forall a b. (a -> b) -> a -> b
$ Int -> MutByteArray -> a -> IO Int
forall a. Serialize a => Int -> MutByteArray -> a -> IO Int
Serialize.serializeAt Int
end MutByteArray
mbarr a
x
        assertM(Int
len Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
off)
        MutArray Word8 -> m (MutArray Word8)
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (MutArray Word8 -> m (MutArray Word8))
-> MutArray Word8 -> m (MutArray Word8)
forall a b. (a -> b) -> a -> b
$ MutByteArray -> Int -> Int -> Int -> MutArray Word8
forall a. MutByteArray -> Int -> Int -> Int -> MutArray a
MutArray MutByteArray
mbarr Int
start Int
off Int
bound
    -- XXX this will inhibit unboxing?
    else (Int -> Int) -> MutArray Word8 -> a -> m (MutArray Word8)
forall (m :: * -> *) a.
(MonadIO m, Serialize a) =>
(Int -> Int) -> MutArray Word8 -> a -> m (MutArray Word8)
serializeRealloc Int -> Int
sizer MutArray Word8
arr a
x

-- | Serializes a (Ptr, len) pair in the same way as an array. The serialized
-- value can be de-serialized as an array or consumed as a pointer using
-- deserializePtrN.
--
-- The Ptr must be pinned or the existence of the Ptr must be ensured by the
-- user of this API.
--
-- /Unimplemented/
{-# INLINE serializePtrN #-}
serializePtrN :: -- (MonadIO m) =>
    MutArray Word8 -> Ptr a -> Int -> m (MutArray Word8)
-- assert/error out if Ptr is not pinned. unsafe prefix?
-- First serialize the length and then splice the ptr
serializePtrN :: forall a (m :: * -> *).
MutArray Word8 -> Ptr a -> Int -> m (MutArray Word8)
serializePtrN MutArray Word8
_arr Ptr a
_ptr Int
_len = m (MutArray Word8)
forall a. (?callStack::CallStack) => a
undefined

-- | Consume a serialized array or (Ptr, length) from the MutArray using an IO
-- action that consumes the pointer directly.
--
-- WARNING! The array must be a pinned array.
--
-- /Unimplemented/
{-# INLINE deserializePtrN #-}
deserializePtrN :: -- (MonadIO m) =>
    MutArray Word8 -> (Ptr a -> Int -> m b) -> m (a, MutArray Word8)
-- assert/error out if the array is not pinned. unsafe prefix?
deserializePtrN :: forall a (m :: * -> *) b.
MutArray Word8 -> (Ptr a -> Int -> m b) -> m (a, MutArray Word8)
deserializePtrN MutArray Word8
_arr Ptr a -> Int -> m b
_action = m (a, MutArray Word8)
forall a. (?callStack::CallStack) => a
undefined

-- | Serialize the supplied Haskell value at the end of the mutable array,
-- growing the array size. If there is no reserve capacity left in the array
-- the array is reallocated to double the current size.
--
-- Like 'snoc' except that the value is serialized to the byte array.
--
-- Note: If you are serializing a large number of small fields, and the types
-- are statically known, then it may be more efficient to declare a record of
-- those fields and derive an 'Serialize' instance of the entire record.
--
-- /Unstable API/
{-# INLINE serialize #-}
serialize :: forall m a. (MonadIO m, Serialize a) =>
    MutArray Word8 -> a -> m (MutArray Word8)
serialize :: forall (m :: * -> *) a.
(MonadIO m, Serialize a) =>
MutArray Word8 -> a -> m (MutArray Word8)
serialize = (Int -> Int) -> MutArray Word8 -> a -> m (MutArray Word8)
forall (m :: * -> *) a.
(MonadIO m, Serialize a) =>
(Int -> Int) -> MutArray Word8 -> a -> m (MutArray Word8)
serializeWith Int -> Int
f

    where

    f :: Int -> Int
f Int
oldSize =
        if Int -> Bool
isPower2 Int
oldSize
        then Int
oldSize Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
2
        else Int -> Int
roundUpToPower2 Int
oldSize Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
2

-- | Deserialize a Haskell value from the beginning of a mutable array. The
-- deserialized value is removed from the array and the remaining array is
-- returned.
--
-- Like 'uncons' except that the value is deserialized from the byte array.
--
-- Note: If you are deserializing a large number of small fields, and the types
-- are statically known, then it may be more efficient to declare a record of
-- those fields and derive 'Serialize' instance of the entire record.
--
-- /Unstable API/
{-# INLINE deserialize #-}
deserialize :: (MonadIO m, Serialize a) =>
    MutArray Word8 -> m (a, MutArray Word8)
deserialize :: forall (m :: * -> *) a.
(MonadIO m, Serialize a) =>
MutArray Word8 -> m (a, MutArray Word8)
deserialize arr :: MutArray Word8
arr@(MutArray {Int
MutByteArray
arrContents :: MutByteArray
arrStart :: Int
arrEnd :: Int
arrBound :: Int
arrContents :: forall a. MutArray a -> MutByteArray
arrStart :: forall a. MutArray a -> Int
arrEnd :: forall a. MutArray a -> Int
arrBound :: forall a. MutArray a -> Int
..}) = do
    let lenArr :: Int
lenArr = MutArray Word8 -> Int
forall a. MutArray a -> Int
byteLength MutArray Word8
arr
    (Int
off, a
val) <-
        IO (Int, a) -> m (Int, a)
forall a. IO a -> m a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO (Int, a) -> m (Int, a)) -> IO (Int, a) -> m (Int, a)
forall a b. (a -> b) -> a -> b
$ Int -> MutByteArray -> Int -> IO (Int, a)
forall a. Serialize a => Int -> MutByteArray -> Int -> IO (Int, a)
Serialize.deserializeAt Int
arrStart MutByteArray
arrContents (Int
arrStart Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
lenArr)
    assertM(Int
off Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
arrStart Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
lenArr)
    (a, MutArray Word8) -> m (a, MutArray Word8)
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (a
val, MutByteArray -> Int -> Int -> Int -> MutArray Word8
forall a. MutByteArray -> Int -> Int -> Int -> MutArray a
MutArray MutByteArray
arrContents Int
off Int
arrEnd Int
arrBound)

-------------------------------------------------------------------------------
-- Compacting Streams of Arrays
-------------------------------------------------------------------------------

-- | @compactLE maxElems@ coalesces adjacent arrays in the input stream
-- only if the combined size would be less than or equal to @maxElems@
-- elements. Note that it won't split an array if the original array is already
-- larger than maxElems.
--
-- @maxElems@ must be greater than 0.
--
-- Generates unpinned arrays irrespective of the pinning status of input
-- arrays.
{-# INLINE compactMax #-}
compactMax, compactLE :: (MonadIO m, Unbox a) =>
    Int -> Stream m (MutArray a) -> Stream m (MutArray a)
-- XXX compactLE can be moved to MutArray/Type if we are not using the parser
-- to implement it.
compactMax :: forall (m :: * -> *) a.
(MonadIO m, Unbox a) =>
Int -> Stream m (MutArray a) -> Stream m (MutArray a)
compactMax = PinnedState
-> Int -> Stream m (MutArray a) -> Stream m (MutArray a)
forall (m :: * -> *) a.
(MonadIO m, Unbox a) =>
PinnedState
-> Int -> Stream m (MutArray a) -> Stream m (MutArray a)
compactLeAs PinnedState
Unpinned
-- The parser version turns out to be a little bit slower.
-- compactLE n = Stream.catRights . Stream.parseManyD (pCompactLE n)

RENAME(compactLE,compactMax)

-- | Like 'compactBySizeLE' but generates pinned arrays.
{-# INLINE_NORMAL compactMax' #-}
compactMax', pinnedCompactLE :: forall m a. (MonadIO m, Unbox a)
    => Int -> Stream m (MutArray a) -> Stream m (MutArray a)
compactMax' :: forall (m :: * -> *) a.
(MonadIO m, Unbox a) =>
Int -> Stream m (MutArray a) -> Stream m (MutArray a)
compactMax' = PinnedState
-> Int -> Stream m (MutArray a) -> Stream m (MutArray a)
forall (m :: * -> *) a.
(MonadIO m, Unbox a) =>
PinnedState
-> Int -> Stream m (MutArray a) -> Stream m (MutArray a)
compactLeAs PinnedState
Pinned
-- compactMax' n = Stream.catRights . Stream.parseManyD (pPinnedCompactLE n)

{-# DEPRECATED pinnedCompactLE "Please use compactMax' instead." #-}
{-# INLINE pinnedCompactLE #-}
pinnedCompactLE :: forall (m :: * -> *) a.
(MonadIO m, Unbox a) =>
Int -> Stream m (MutArray a) -> Stream m (MutArray a)
pinnedCompactLE = Int -> Stream m (MutArray a) -> Stream m (MutArray a)
forall (m :: * -> *) a.
(MonadIO m, Unbox a) =>
Int -> Stream m (MutArray a) -> Stream m (MutArray a)
compactMax'

data SplitState s arr
    = Initial s
    | Buffering s arr
    | Splitting s arr
    | Yielding arr (SplitState s arr)
    | Finishing

-- | Split a stream of arrays on a given separator byte, dropping the separator
-- and coalescing all the arrays between two separators into a single array.
--
{-# INLINE_NORMAL _compactSepByByteCustom #-}
_compactSepByByteCustom
    :: MonadIO m
    => Word8
    -> Stream m (MutArray Word8)
    -> Stream m (MutArray Word8)
_compactSepByByteCustom :: forall (m :: * -> *).
MonadIO m =>
Word8 -> Stream m (MutArray Word8) -> Stream m (MutArray Word8)
_compactSepByByteCustom Word8
byte (Stream.Stream State StreamK m (MutArray Word8)
-> s -> m (Step s (MutArray Word8))
step s
state) =
    (State StreamK m (MutArray Word8)
 -> SplitState s (MutArray Word8)
 -> m (Step (SplitState s (MutArray Word8)) (MutArray Word8)))
-> SplitState s (MutArray Word8) -> Stream m (MutArray Word8)
forall (m :: * -> *) a s.
(State StreamK m a -> s -> m (Step s a)) -> s -> Stream m a
Stream.Stream State StreamK m (MutArray Word8)
-> SplitState s (MutArray Word8)
-> m (Step (SplitState s (MutArray Word8)) (MutArray Word8))
step' (s -> SplitState s (MutArray Word8)
forall s arr. s -> SplitState s arr
Initial s
state)

    where

    {-# INLINE_LATE step' #-}
    step' :: State StreamK m (MutArray Word8)
-> SplitState s (MutArray Word8)
-> m (Step (SplitState s (MutArray Word8)) (MutArray Word8))
step' State StreamK m (MutArray Word8)
gst (Initial s
st) = do
        Step s (MutArray Word8)
r <- State StreamK m (MutArray Word8)
-> s -> m (Step s (MutArray Word8))
step State StreamK m (MutArray Word8)
gst s
st
        case Step s (MutArray Word8)
r of
            Stream.Yield MutArray Word8
arr s
s -> do
                (MutArray Word8
arr1, Maybe (MutArray Word8)
marr2) <- Word8
-> MutArray Word8 -> m (MutArray Word8, Maybe (MutArray Word8))
forall (m :: * -> *).
MonadIO m =>
Word8
-> MutArray Word8 -> m (MutArray Word8, Maybe (MutArray Word8))
breakEndByWord8_ Word8
byte MutArray Word8
arr
                Step (SplitState s (MutArray Word8)) (MutArray Word8)
-> m (Step (SplitState s (MutArray Word8)) (MutArray Word8))
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (Step (SplitState s (MutArray Word8)) (MutArray Word8)
 -> m (Step (SplitState s (MutArray Word8)) (MutArray Word8)))
-> Step (SplitState s (MutArray Word8)) (MutArray Word8)
-> m (Step (SplitState s (MutArray Word8)) (MutArray Word8))
forall a b. (a -> b) -> a -> b
$ case Maybe (MutArray Word8)
marr2 of
                    Maybe (MutArray Word8)
Nothing   -> SplitState s (MutArray Word8)
-> Step (SplitState s (MutArray Word8)) (MutArray Word8)
forall s a. s -> Step s a
Stream.Skip (s -> MutArray Word8 -> SplitState s (MutArray Word8)
forall s arr. s -> arr -> SplitState s arr
Buffering s
s MutArray Word8
arr1)
                    Just MutArray Word8
arr2 -> SplitState s (MutArray Word8)
-> Step (SplitState s (MutArray Word8)) (MutArray Word8)
forall s a. s -> Step s a
Stream.Skip (MutArray Word8
-> SplitState s (MutArray Word8) -> SplitState s (MutArray Word8)
forall s arr. arr -> SplitState s arr -> SplitState s arr
Yielding MutArray Word8
arr1 (s -> MutArray Word8 -> SplitState s (MutArray Word8)
forall s arr. s -> arr -> SplitState s arr
Splitting s
s MutArray Word8
arr2))
            Stream.Skip s
s -> Step (SplitState s (MutArray Word8)) (MutArray Word8)
-> m (Step (SplitState s (MutArray Word8)) (MutArray Word8))
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (Step (SplitState s (MutArray Word8)) (MutArray Word8)
 -> m (Step (SplitState s (MutArray Word8)) (MutArray Word8)))
-> Step (SplitState s (MutArray Word8)) (MutArray Word8)
-> m (Step (SplitState s (MutArray Word8)) (MutArray Word8))
forall a b. (a -> b) -> a -> b
$ SplitState s (MutArray Word8)
-> Step (SplitState s (MutArray Word8)) (MutArray Word8)
forall s a. s -> Step s a
Stream.Skip (s -> SplitState s (MutArray Word8)
forall s arr. s -> SplitState s arr
Initial s
s)
            Step s (MutArray Word8)
Stream.Stop -> Step (SplitState s (MutArray Word8)) (MutArray Word8)
-> m (Step (SplitState s (MutArray Word8)) (MutArray Word8))
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return Step (SplitState s (MutArray Word8)) (MutArray Word8)
forall s a. Step s a
Stream.Stop

    step' State StreamK m (MutArray Word8)
gst (Buffering s
st MutArray Word8
buf) = do
        Step s (MutArray Word8)
r <- State StreamK m (MutArray Word8)
-> s -> m (Step s (MutArray Word8))
step State StreamK m (MutArray Word8)
gst s
st
        case Step s (MutArray Word8)
r of
            Stream.Yield MutArray Word8
arr s
s -> do
                (MutArray Word8
arr1, Maybe (MutArray Word8)
marr2) <- Word8
-> MutArray Word8 -> m (MutArray Word8, Maybe (MutArray Word8))
forall (m :: * -> *).
MonadIO m =>
Word8
-> MutArray Word8 -> m (MutArray Word8, Maybe (MutArray Word8))
breakEndByWord8_ Word8
byte MutArray Word8
arr
                -- XXX Use spliceExp instead and then rightSize?
                MutArray Word8
buf1 <- MutArray Word8 -> MutArray Word8 -> m (MutArray Word8)
forall (m :: * -> *) a.
(MonadIO m, Unbox a) =>
MutArray a -> MutArray a -> m (MutArray a)
splice MutArray Word8
buf MutArray Word8
arr1
                Step (SplitState s (MutArray Word8)) (MutArray Word8)
-> m (Step (SplitState s (MutArray Word8)) (MutArray Word8))
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (Step (SplitState s (MutArray Word8)) (MutArray Word8)
 -> m (Step (SplitState s (MutArray Word8)) (MutArray Word8)))
-> Step (SplitState s (MutArray Word8)) (MutArray Word8)
-> m (Step (SplitState s (MutArray Word8)) (MutArray Word8))
forall a b. (a -> b) -> a -> b
$ case Maybe (MutArray Word8)
marr2 of
                    Maybe (MutArray Word8)
Nothing -> SplitState s (MutArray Word8)
-> Step (SplitState s (MutArray Word8)) (MutArray Word8)
forall s a. s -> Step s a
Stream.Skip (s -> MutArray Word8 -> SplitState s (MutArray Word8)
forall s arr. s -> arr -> SplitState s arr
Buffering s
s MutArray Word8
buf1)
                    Just MutArray Word8
x -> SplitState s (MutArray Word8)
-> Step (SplitState s (MutArray Word8)) (MutArray Word8)
forall s a. s -> Step s a
Stream.Skip (MutArray Word8
-> SplitState s (MutArray Word8) -> SplitState s (MutArray Word8)
forall s arr. arr -> SplitState s arr -> SplitState s arr
Yielding MutArray Word8
buf1 (s -> MutArray Word8 -> SplitState s (MutArray Word8)
forall s arr. s -> arr -> SplitState s arr
Splitting s
s MutArray Word8
x))
            Stream.Skip s
s -> Step (SplitState s (MutArray Word8)) (MutArray Word8)
-> m (Step (SplitState s (MutArray Word8)) (MutArray Word8))
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (Step (SplitState s (MutArray Word8)) (MutArray Word8)
 -> m (Step (SplitState s (MutArray Word8)) (MutArray Word8)))
-> Step (SplitState s (MutArray Word8)) (MutArray Word8)
-> m (Step (SplitState s (MutArray Word8)) (MutArray Word8))
forall a b. (a -> b) -> a -> b
$ SplitState s (MutArray Word8)
-> Step (SplitState s (MutArray Word8)) (MutArray Word8)
forall s a. s -> Step s a
Stream.Skip (s -> MutArray Word8 -> SplitState s (MutArray Word8)
forall s arr. s -> arr -> SplitState s arr
Buffering s
s MutArray Word8
buf)
            Step s (MutArray Word8)
Stream.Stop -> Step (SplitState s (MutArray Word8)) (MutArray Word8)
-> m (Step (SplitState s (MutArray Word8)) (MutArray Word8))
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (Step (SplitState s (MutArray Word8)) (MutArray Word8)
 -> m (Step (SplitState s (MutArray Word8)) (MutArray Word8)))
-> Step (SplitState s (MutArray Word8)) (MutArray Word8)
-> m (Step (SplitState s (MutArray Word8)) (MutArray Word8))
forall a b. (a -> b) -> a -> b
$
                if MutArray Word8 -> Int
forall a. MutArray a -> Int
byteLength MutArray Word8
buf Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0
                then Step (SplitState s (MutArray Word8)) (MutArray Word8)
forall s a. Step s a
Stream.Stop
                else SplitState s (MutArray Word8)
-> Step (SplitState s (MutArray Word8)) (MutArray Word8)
forall s a. s -> Step s a
Stream.Skip (MutArray Word8
-> SplitState s (MutArray Word8) -> SplitState s (MutArray Word8)
forall s arr. arr -> SplitState s arr -> SplitState s arr
Yielding MutArray Word8
buf SplitState s (MutArray Word8)
forall s arr. SplitState s arr
Finishing)

    step' State StreamK m (MutArray Word8)
_ (Splitting s
st MutArray Word8
buf) = do
        (MutArray Word8
arr1, Maybe (MutArray Word8)
marr2) <- Word8
-> MutArray Word8 -> m (MutArray Word8, Maybe (MutArray Word8))
forall (m :: * -> *).
MonadIO m =>
Word8
-> MutArray Word8 -> m (MutArray Word8, Maybe (MutArray Word8))
breakEndByWord8_ Word8
byte MutArray Word8
buf
        Step (SplitState s (MutArray Word8)) (MutArray Word8)
-> m (Step (SplitState s (MutArray Word8)) (MutArray Word8))
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (Step (SplitState s (MutArray Word8)) (MutArray Word8)
 -> m (Step (SplitState s (MutArray Word8)) (MutArray Word8)))
-> Step (SplitState s (MutArray Word8)) (MutArray Word8)
-> m (Step (SplitState s (MutArray Word8)) (MutArray Word8))
forall a b. (a -> b) -> a -> b
$ case Maybe (MutArray Word8)
marr2 of
                Maybe (MutArray Word8)
Nothing -> SplitState s (MutArray Word8)
-> Step (SplitState s (MutArray Word8)) (MutArray Word8)
forall s a. s -> Step s a
Stream.Skip (SplitState s (MutArray Word8)
 -> Step (SplitState s (MutArray Word8)) (MutArray Word8))
-> SplitState s (MutArray Word8)
-> Step (SplitState s (MutArray Word8)) (MutArray Word8)
forall a b. (a -> b) -> a -> b
$ s -> MutArray Word8 -> SplitState s (MutArray Word8)
forall s arr. s -> arr -> SplitState s arr
Buffering s
st MutArray Word8
arr1
                Just MutArray Word8
arr2 -> SplitState s (MutArray Word8)
-> Step (SplitState s (MutArray Word8)) (MutArray Word8)
forall s a. s -> Step s a
Stream.Skip (SplitState s (MutArray Word8)
 -> Step (SplitState s (MutArray Word8)) (MutArray Word8))
-> SplitState s (MutArray Word8)
-> Step (SplitState s (MutArray Word8)) (MutArray Word8)
forall a b. (a -> b) -> a -> b
$ MutArray Word8
-> SplitState s (MutArray Word8) -> SplitState s (MutArray Word8)
forall s arr. arr -> SplitState s arr -> SplitState s arr
Yielding MutArray Word8
arr1 (s -> MutArray Word8 -> SplitState s (MutArray Word8)
forall s arr. s -> arr -> SplitState s arr
Splitting s
st MutArray Word8
arr2)

    step' State StreamK m (MutArray Word8)
_ (Yielding MutArray Word8
arr SplitState s (MutArray Word8)
next) = Step (SplitState s (MutArray Word8)) (MutArray Word8)
-> m (Step (SplitState s (MutArray Word8)) (MutArray Word8))
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (Step (SplitState s (MutArray Word8)) (MutArray Word8)
 -> m (Step (SplitState s (MutArray Word8)) (MutArray Word8)))
-> Step (SplitState s (MutArray Word8)) (MutArray Word8)
-> m (Step (SplitState s (MutArray Word8)) (MutArray Word8))
forall a b. (a -> b) -> a -> b
$ MutArray Word8
-> SplitState s (MutArray Word8)
-> Step (SplitState s (MutArray Word8)) (MutArray Word8)
forall s a. a -> s -> Step s a
Stream.Yield MutArray Word8
arr SplitState s (MutArray Word8)
next
    step' State StreamK m (MutArray Word8)
_ SplitState s (MutArray Word8)
Finishing = Step (SplitState s (MutArray Word8)) (MutArray Word8)
-> m (Step (SplitState s (MutArray Word8)) (MutArray Word8))
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return Step (SplitState s (MutArray Word8)) (MutArray Word8)
forall s a. Step s a
Stream.Stop

-- XXX implement predicate based version of this compactSepBy_, compactEndBy_
-- XXX the versions that use equality can be named compactSepByElem_ etc. The
-- byte/word etc versions of that can be specialized using rewrite rules.

-- | Split a stream of arrays on a given separator byte, dropping the separator
-- and coalescing all the arrays between two separators into a single array.
--
{-# INLINE compactSepByByte_ #-}
compactSepByByte_, compactOnByte
    :: (MonadIO m)
    => Word8
    -> Stream m (MutArray Word8)
    -> Stream m (MutArray Word8)
-- XXX compare perf of custom vs idiomatic version
-- compactOnByte = _compactOnByteCustom
-- XXX use spliceExp and rightSize?
compactSepByByte_ :: forall (m :: * -> *).
MonadIO m =>
Word8 -> Stream m (MutArray Word8) -> Stream m (MutArray Word8)
compactSepByByte_ Word8
byte = (MutArray Word8 -> m (MutArray Word8, Maybe (MutArray Word8)))
-> (MutArray Word8 -> MutArray Word8 -> m (MutArray Word8))
-> Stream m (MutArray Word8)
-> Stream m (MutArray Word8)
forall (m :: * -> *) (f :: * -> *) a.
Monad m =>
(f a -> m (f a, Maybe (f a)))
-> (f a -> f a -> m (f a)) -> Stream m (f a) -> Stream m (f a)
Stream.splitInnerBy (Word8
-> MutArray Word8 -> m (MutArray Word8, Maybe (MutArray Word8))
forall (m :: * -> *).
MonadIO m =>
Word8
-> MutArray Word8 -> m (MutArray Word8, Maybe (MutArray Word8))
breakEndByWord8_ Word8
byte) MutArray Word8 -> MutArray Word8 -> m (MutArray Word8)
forall (m :: * -> *) a.
(MonadIO m, Unbox a) =>
MutArray a -> MutArray a -> m (MutArray a)
splice

RENAME(compactOnByte,compactSepByByte_)

-- | Split a stream of arrays on a given separator byte, dropping the separator
-- and coalescing all the arrays between two separators into a single array.
--
{-# INLINE compactEndByByte_ #-}
compactEndByByte_, compactOnByteSuffix
    :: (MonadIO m)
    => Word8
    -> Stream m (MutArray Word8)
    -> Stream m (MutArray Word8)
compactEndByByte_ :: forall (m :: * -> *).
MonadIO m =>
Word8 -> Stream m (MutArray Word8) -> Stream m (MutArray Word8)
compactEndByByte_ Word8
byte =
        -- XXX use spliceExp and rightSize?
        (MutArray Word8 -> Bool)
-> (MutArray Word8 -> m (MutArray Word8, Maybe (MutArray Word8)))
-> (MutArray Word8 -> MutArray Word8 -> m (MutArray Word8))
-> Stream m (MutArray Word8)
-> Stream m (MutArray Word8)
forall (m :: * -> *) (f :: * -> *) a.
Monad m =>
(f a -> Bool)
-> (f a -> m (f a, Maybe (f a)))
-> (f a -> f a -> m (f a))
-> Stream m (f a)
-> Stream m (f a)
Stream.splitInnerBySuffix
            (\MutArray Word8
arr -> MutArray Word8 -> Int
forall a. MutArray a -> Int
byteLength MutArray Word8
arr Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0) (Word8
-> MutArray Word8 -> m (MutArray Word8, Maybe (MutArray Word8))
forall (m :: * -> *).
MonadIO m =>
Word8
-> MutArray Word8 -> m (MutArray Word8, Maybe (MutArray Word8))
breakEndByWord8_ Word8
byte) MutArray Word8 -> MutArray Word8 -> m (MutArray Word8)
forall (m :: * -> *) a.
(MonadIO m, Unbox a) =>
MutArray a -> MutArray a -> m (MutArray a)
splice

RENAME(compactOnByteSuffix,compactEndByByte_)

-- XXX On windows we should compact on "\r\n". We can just compact on '\n' and
-- drop the last byte in each array if it is '\r'.

-- | Compact byte arrays on newline character, dropping the newline char.
{-# INLINE compactEndByLn_ #-}
compactEndByLn_ :: MonadIO m
    => Stream m (MutArray Word8)
    -> Stream m (MutArray Word8)
compactEndByLn_ :: forall (m :: * -> *).
MonadIO m =>
Stream m (MutArray Word8) -> Stream m (MutArray Word8)
compactEndByLn_ = Word8 -> Stream m (MutArray Word8) -> Stream m (MutArray Word8)
forall (m :: * -> *).
MonadIO m =>
Word8 -> Stream m (MutArray Word8) -> Stream m (MutArray Word8)
compactEndByByte_ Word8
10

-- | @createOfLast n@ folds a maximum of @n@ elements from the end of the input
-- stream to an 'MutArray'.
--
{-# INLINE createOfLast #-}
createOfLast :: (Unbox a, MonadIO m) => Int -> Fold m a (MutArray a)
createOfLast :: forall a (m :: * -> *).
(Unbox a, MonadIO m) =>
Int -> Fold m a (MutArray a)
createOfLast Int
n =
    m Bool
-> Fold m a (MutArray a)
-> Fold m a (MutArray a)
-> Fold m a (MutArray a)
forall (m :: * -> *) a b.
Monad m =>
m Bool -> Fold m a b -> Fold m a b -> Fold m a b
Fold.ifThen
        (Bool -> m Bool
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Int
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
0))
        (MutArray a -> Fold m a (MutArray a)
forall (m :: * -> *) b a. Applicative m => b -> Fold m a b
Fold.fromPure MutArray a
forall a. MutArray a
empty)
        ((RingArray a -> m (MutArray a))
-> Fold m a (RingArray a) -> Fold m a (MutArray a)
forall (m :: * -> *) b c a.
Monad m =>
(b -> m c) -> Fold m a b -> Fold m a c
Fold.rmapM RingArray a -> m (MutArray a)
forall (m :: * -> *) a.
(MonadIO m, Unbox a) =>
RingArray a -> m (MutArray a)
RingArray.toMutArray (Fold m a (RingArray a) -> Fold m a (MutArray a))
-> Fold m a (RingArray a) -> Fold m a (MutArray a)
forall a b. (a -> b) -> a -> b
$ Int -> Fold m a (RingArray a)
forall a (m :: * -> *).
(Unbox a, MonadIO m) =>
Int -> Fold m a (RingArray a)
RingArray.createOfLast Int
n)

--------------------------------------------------------------------------------
-- IoRef (Deprecated)
--------------------------------------------------------------------------------

{-# DEPRECATED IORef "Use IORef from MutByteArray module." #-}
type IORef = IORef.IORef

{-# DEPRECATED pollIntIORef "Use pollIntIORef from MutByteArray module." #-}
pollIntIORef :: (MonadIO m, Unbox a) => IORef a -> Stream m a
pollIntIORef :: forall (m :: * -> *) a.
(MonadIO m, Unbox a) =>
IORef a -> Stream m a
pollIntIORef = IORef a -> Stream m a
forall (m :: * -> *) a.
(MonadIO m, Unbox a) =>
IORef a -> Stream m a
IORef.pollIntIORef

{-# DEPRECATED newIORef "Use newIORef from MutByteArray module." #-}
newIORef :: forall a. Unbox a => a -> IO (IORef a)
newIORef :: forall a. Unbox a => a -> IO (IORef a)
newIORef = a -> IO (IORef a)
forall a. Unbox a => a -> IO (IORef a)
IORef.newIORef


{-# DEPRECATED writeIORef "Use writeIORef from MutByteArray module." #-}
writeIORef :: Unbox a => IORef a -> a -> IO ()
writeIORef :: forall a. Unbox a => IORef a -> a -> IO ()
writeIORef = IORef a -> a -> IO ()
forall a. Unbox a => IORef a -> a -> IO ()
IORef.writeIORef


{-# DEPRECATED modifyIORef' "Use modifyIORef' from MutByteArray module." #-}
modifyIORef' :: Unbox a => IORef a -> (a -> a) -> IO ()
modifyIORef' :: forall a. Unbox a => IORef a -> (a -> a) -> IO ()
modifyIORef' = IORef a -> (a -> a) -> IO ()
forall a. Unbox a => IORef a -> (a -> a) -> IO ()
IORef.modifyIORef'


{-# DEPRECATED readIORef "Use readIORef from MutByteArray module." #-}
readIORef :: Unbox a => IORef a -> IO a
readIORef :: forall a. Unbox a => IORef a -> IO a
readIORef = IORef a -> IO a
forall a. Unbox a => IORef a -> IO a
IORef.readIORef