{-# LANGUAGE CPP #-}
-- |
-- Module      : Streamly.Internal.Data.Array
-- Copyright   : (c) 2019 Composewell Technologies
-- License     : BSD3
-- Maintainer  : streamly@composewell.com
-- Stability   : experimental
-- Portability : GHC
--
module Streamly.Internal.Data.Array
    (
    -- * Setup
    -- $setup

    -- * Design Notes
    -- $design

    -- * The Array Type
      module Streamly.Internal.Data.Array.Type

    -- * Construction
    -- Monadic Folds
    , createOfLast

    -- * Random Access
    -- , getIndicesFrom    -- read from a given position to the end of file
    -- , getIndicesUpto    -- read from beginning up to the given position
    -- , getIndicesFromTo
    -- , getIndicesFromRev  -- read from a given position to the beginning of file
    -- , getIndicesUptoRev  -- read from end to the given position in file
    , indexReader
    , indexReaderFromThenTo

    -- * Search
    , binarySearch
    , findIndicesOf
    -- getIndicesOf
    , indexFinder -- see splitOn
    -- , findIndexOf
    -- , find

    -- * Casting
    , cast
    , asBytes
    , unsafeCast
    , asCStringUnsafe -- XXX asCString
    , asCWString

    -- * Subarrays
    -- , sliceOffLen
    , indexerFromLen
    , splitterFromLen

    -- * Streaming Operations
    , streamTransform

    -- * Folding
    , streamFold
    , foldM
    , foldRev

    -- * Stream of Arrays
    , concatSepBy
    , concatEndBy
    , concatEndBySeq

    , compactMax
    , compactMax'
    , compactSepByByte_
    , compactEndByByte_
    , compactEndByLn_

    -- * Parsing Stream of Arrays
    , foldBreakChunks -- Uses Stream, bad perf on break
    , foldChunks
    , foldBreak
    -- , parseBreakChunksK -- XXX uses Parser. parseBreak is better?
    , toParserK
    , parseBreak
    , parseBreakPos
    , parse
    , parsePos

    -- * Serialization
    , encodeAs
    , serialize
    , serialize'
    , deserialize

    -- * Deprecated
    , slicerFromLen
    , sliceIndexerFromLen
    , castUnsafe
    , getSliceUnsafe
    , pinnedSerialize
    , genSlicesFromLen
    , getSlicesFromLen
    , getIndices
    , writeLastN
    , interpose
    , interposeSuffix
    , intercalateSuffix
    , compactLE
    , pinnedCompactLE
    , compactOnByte
    , compactOnByteSuffix
    , splitOn
    , fold
    , foldBreakChunksK
    )
where

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

import Control.Monad.IO.Class (MonadIO(..))
-- import Data.Bifunctor (first)
-- import Data.Either (fromRight)
import Data.Functor.Identity (Identity(..))
import Data.Proxy (Proxy(..))
import Data.Word (Word8)
import Foreign.C.String (CString, CWString)
import GHC.Types (SPEC(..))
import Streamly.Internal.Data.Unbox (Unbox(..))
import Prelude hiding (length, null, last, map, (!!), read, concat)

import Streamly.Internal.Data.MutByteArray.Type (PinnedState(..), MutByteArray)
import Streamly.Internal.Data.Serialize.Type (Serialize)
import Streamly.Internal.Data.Fold.Type (Fold(..))
import Streamly.Internal.Data.Parser (ParseError(..), ParseErrorPos(..))
import Streamly.Internal.Data.ParserK.Type
    (ParserK, ParseResult(..), Input(..), Step(..))
import Streamly.Internal.Data.Stream (Stream(..))
import Streamly.Internal.Data.StreamK.Type (StreamK)
import Streamly.Internal.Data.SVar.Type (adaptState, defState)
import Streamly.Internal.Data.Tuple.Strict (Tuple'(..))
import Streamly.Internal.Data.Unfold.Type (Unfold(..))
import Streamly.Internal.System.IO (unsafeInlineIO)

import qualified Streamly.Internal.Data.Fold.Type as Fold
import qualified Streamly.Internal.Data.Serialize.Type as Serialize
import qualified Streamly.Internal.Data.MutByteArray.Type as MBA
import qualified Streamly.Internal.Data.MutArray as MA
import qualified Streamly.Internal.Data.RingArray as RB
import qualified Streamly.Internal.Data.ParserDrivers as Drivers
import qualified Streamly.Internal.Data.Parser.Type as ParserD
import qualified Streamly.Internal.Data.ParserK.Type as ParserK
import qualified Streamly.Internal.Data.Stream as D
import qualified Streamly.Internal.Data.Stream as Stream
import qualified Streamly.Internal.Data.StreamK.Type as StreamK
import qualified Streamly.Internal.Data.Unfold as Unfold

import Streamly.Internal.Data.Array.Type

#include "DocTestDataArray.hs"

-- $design
--
-- To summarize:
--
--  * Arrays are finite and fixed in size
--  * provide /O(1)/ access to elements
--  * store only data and not functions
--  * provide efficient IO interfacing
--
-- 'Foldable' instance is not provided because the implementation would be much
-- less efficient compared to folding via streams.  'Semigroup' and 'Monoid'
-- instances should be used with care; concatenating arrays using binary
-- operations can be highly inefficient.  Instead, use
-- 'Streamly.Internal.Data.Stream.Chunked.toArray' to concatenate N
-- arrays at once.
--
-- Each array is one pointer visible to the GC.  Too many small arrays (e.g.
-- single byte) are only as good as holding those elements in a Haskell list.
-- However, small arrays can be compacted into large ones to reduce the
-- overhead. To hold 32GB memory in 32k sized buffers we need 1 million arrays
-- if we use one array for each chunk. This is still significant to add
-- pressure to GC.

-------------------------------------------------------------------------------
-- Folds with Array as the container
-------------------------------------------------------------------------------

-- NOTE: We could possible write this in terms of "MutArray.createOfLast" but
-- this causes regression. This is probably because mapping inside "Fold.ifThen"
-- is more efficient than mapping over "Fold.ifTen".
--
-- | @createOfLast n@ folds a maximum of @n@ elements from the end of the input
-- stream to an 'Array'.
--
{-# INLINE createOfLast #-}
createOfLast ::
       (Unbox a, MonadIO m) => Int -> Fold m a (Array a)
createOfLast :: forall a (m :: * -> *).
(Unbox a, MonadIO m) =>
Int -> Fold m a (Array a)
createOfLast Int
n = m Bool
-> Fold m a (Array a) -> Fold m a (Array a) -> Fold m a (Array 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)) (Array a -> Fold m a (Array a)
forall (m :: * -> *) b a. Applicative m => b -> Fold m a b
Fold.fromPure Array a
forall a. Array a
empty) Fold m a (Array a)
lst

    where

    lst :: Fold m a (Array a)
lst =
        let f :: RingArray a -> m (Array a)
f = (MutArray a -> Array a) -> m (MutArray a) -> m (Array a)
forall a b. (a -> b) -> m a -> m b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap MutArray a -> Array a
forall a. MutArray a -> Array a
unsafeFreeze (m (MutArray a) -> m (Array a))
-> (RingArray a -> m (MutArray a)) -> RingArray a -> m (Array a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. RingArray a -> m (MutArray a)
forall (m :: * -> *) a.
(MonadIO m, Unbox a) =>
RingArray a -> m (MutArray a)
RB.toMutArray
         in (RingArray a -> m (Array a))
-> Fold m a (RingArray a) -> Fold m a (Array a)
forall (m :: * -> *) b c a.
Monad m =>
(b -> m c) -> Fold m a b -> Fold m a c
Fold.rmapM RingArray a -> m (Array a)
f (Fold m a (RingArray a) -> Fold m a (Array a))
-> Fold m a (RingArray a) -> Fold m a (Array 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)
RB.createOfLast Int
n

{-# DEPRECATED writeLastN "Please use createOfLast instead." #-}
{-# INLINE writeLastN #-}
writeLastN :: (Unbox a, MonadIO m) => Int -> Fold m a (Array a)
writeLastN :: forall a (m :: * -> *).
(Unbox a, MonadIO m) =>
Int -> Fold m a (Array a)
writeLastN = Int -> Fold m a (Array a)
forall a (m :: * -> *).
(Unbox a, MonadIO m) =>
Int -> Fold m a (Array a)
createOfLast

-------------------------------------------------------------------------------
-- Random Access
-------------------------------------------------------------------------------

-------------------------------------------------------------------------------
-- Searching
-------------------------------------------------------------------------------

-- | Given a sorted array, perform a binary search to find the given element.
-- Returns the index of the element if found.
--
-- /Unimplemented/
{-# INLINE binarySearch #-}
binarySearch :: a -> Array a -> Maybe Int
binarySearch :: forall a. a -> Array a -> Maybe Int
binarySearch = a -> Array a -> Maybe Int
forall a. HasCallStack => a
undefined

-- find/findIndex etc can potentially be implemented more efficiently on arrays
-- compared to streams by using SIMD instructions.
-- We can also return a bit array instead.

-- Can use SIMD.

-- | Perform a linear search to find all the indices where a given element is
-- present in an array.
--
-- /Unimplemented/
indexFinder :: (a -> Bool) -> Unfold Identity (Array a) Int
indexFinder :: forall a. (a -> Bool) -> Unfold Identity (Array a) Int
indexFinder = (a -> Bool) -> Unfold Identity (Array a) Int
forall a. HasCallStack => a
undefined

-- |
-- /Unimplemented/
findIndicesOf :: (a -> Bool) -> Array a -> Stream Identity Int
findIndicesOf :: forall a. (a -> Bool) -> Array a -> Stream Identity Int
findIndicesOf a -> Bool
p = Unfold Identity (Array a) Int -> Array a -> Stream Identity Int
forall (m :: * -> *) a b.
Applicative m =>
Unfold m a b -> a -> Stream m b
Stream.unfold ((a -> Bool) -> Unfold Identity (Array a) Int
forall a. (a -> Bool) -> Unfold Identity (Array a) Int
indexFinder a -> Bool
p)

{-
findIndexOf :: (a -> Bool) -> Array a -> Maybe Int
findIndexOf p = Unfold.fold Fold.one . Stream.unfold (indexFinder p)

find :: (a -> Bool) -> Array a -> Bool
find = Unfold.fold Fold.null . Stream.unfold (indexFinder p)
-}

-------------------------------------------------------------------------------
-- Folds
-------------------------------------------------------------------------------

-- XXX We can potentially use SIMD instructions on arrays to fold faster.

-------------------------------------------------------------------------------
-- Slice
-------------------------------------------------------------------------------

getSliceUnsafe ::
       forall a. Unbox a
    => Int -- ^ starting index
    -> Int -- ^ length of the slice
    -> Array a
    -> Array a
RENAME(getSliceUnsafe,unsafeSliceOffLen)

splitOn :: (Monad m, Unbox a) =>
    (a -> Bool) -> Array a -> Stream m (Array a)
RENAME(splitOn,splitEndBy_)

{-# INLINE indexerFromLen #-}
indexerFromLen, sliceIndexerFromLen :: forall m a. (Monad m, Unbox a)
    => Int -- ^ from index
    -> Int -- ^ length of the slice
    -> Unfold m (Array a) (Int, Int)
indexerFromLen :: forall (m :: * -> *) a.
(Monad m, Unbox a) =>
Int -> Int -> Unfold m (Array a) (Int, Int)
indexerFromLen Int
from Int
len =
    (Array a -> MutArray a)
-> Unfold m (MutArray a) (Int, Int)
-> Unfold m (Array a) (Int, Int)
forall a c (m :: * -> *) b.
(a -> c) -> Unfold m c b -> Unfold m a b
Unfold.lmap Array a -> MutArray a
forall a. Array a -> MutArray a
unsafeThaw (Int -> Int -> Unfold m (MutArray a) (Int, Int)
forall (m :: * -> *) a.
(Monad m, Unbox a) =>
Int -> Int -> Unfold m (MutArray a) (Int, Int)
MA.indexerFromLen Int
from Int
len)
RENAME(sliceIndexerFromLen,indexerFromLen)

{-# DEPRECATED genSlicesFromLen "Please use indexerFromLen instead." #-}
{-# INLINE genSlicesFromLen #-}
genSlicesFromLen :: forall m a. (Monad m, Unbox a)
    => Int -- ^ from index
    -> Int -- ^ length of the slice
    -> Unfold m (Array a) (Int, Int)
genSlicesFromLen :: forall (m :: * -> *) a.
(Monad m, Unbox a) =>
Int -> Int -> Unfold m (Array a) (Int, Int)
genSlicesFromLen = Int -> Int -> Unfold m (Array a) (Int, Int)
forall (m :: * -> *) a.
(Monad m, Unbox a) =>
Int -> Int -> Unfold m (Array 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.
--
-- /Pre-release//
{-# INLINE splitterFromLen #-}
splitterFromLen, slicerFromLen :: forall m a. (Monad m, Unbox a)
    => Int -- ^ from index
    -> Int -- ^ length of the slice
    -> Unfold m (Array a) (Array a)
splitterFromLen :: forall (m :: * -> *) a.
(Monad m, Unbox a) =>
Int -> Int -> Unfold m (Array a) (Array a)
splitterFromLen Int
from Int
len =
    (MutArray a -> Array a)
-> Unfold m (Array a) (MutArray a) -> Unfold m (Array a) (Array a)
forall a b.
(a -> b) -> Unfold m (Array a) a -> Unfold m (Array a) b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap MutArray a -> Array a
forall a. MutArray a -> Array a
unsafeFreeze
        (Unfold m (Array a) (MutArray a) -> Unfold m (Array a) (Array a))
-> Unfold m (Array a) (MutArray a) -> Unfold m (Array a) (Array a)
forall a b. (a -> b) -> a -> b
$ (Array a -> MutArray a)
-> Unfold m (MutArray a) (MutArray a)
-> Unfold m (Array a) (MutArray a)
forall a c (m :: * -> *) b.
(a -> c) -> Unfold m c b -> Unfold m a b
Unfold.lmap Array a -> MutArray a
forall a. Array a -> MutArray a
unsafeThaw (Int -> Int -> Unfold m (MutArray a) (MutArray a)
forall (m :: * -> *) a.
(Monad m, Unbox a) =>
Int -> Int -> Unfold m (MutArray a) (MutArray a)
MA.splitterFromLen Int
from Int
len)
RENAME(slicerFromLen,splitterFromLen)

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

-------------------------------------------------------------------------------
-- Random reads and writes
-------------------------------------------------------------------------------

-- | Given a stream of array indices, read the elements on those indices from
-- the supplied Array. An exception is thrown if an index is out of bounds.
--
-- This is the most general operation. We can implement other operations in
-- terms of this:
--
-- @
-- read =
--      let u = lmap (\arr -> (0, length arr - 1)) Unfold.enumerateFromTo
--       in Unfold.lmap f (indexReader arr)
--
-- readRev =
--      let i = length arr - 1
--       in Unfold.lmap f (indexReaderFromThenTo i (i - 1) 0)
-- @
--
-- /Pre-release/
{-# INLINE indexReader #-}
indexReader :: (Monad m, Unbox a) => Stream m Int -> Unfold m (Array a) a
indexReader :: forall (m :: * -> *) a.
(Monad m, Unbox a) =>
Stream m Int -> Unfold m (Array a) a
indexReader Stream m Int
m =
    let unf :: Unfold m (MutArray a) a
unf = (forall b. IO b -> m b) -> Stream m Int -> Unfold m (MutArray a) a
forall (m :: * -> *) a.
(Monad m, Unbox a) =>
(forall b. IO b -> m b) -> Stream m Int -> Unfold m (MutArray a) a
MA.indexReaderWith (b -> m b
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (b -> m b) -> (IO b -> b) -> IO b -> m b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. IO b -> b
forall a. IO a -> a
unsafeInlineIO) Stream m Int
m
     in (Array a -> MutArray a)
-> Unfold m (MutArray a) a -> Unfold m (Array a) a
forall a c (m :: * -> *) b.
(a -> c) -> Unfold m c b -> Unfold m a b
Unfold.lmap Array a -> MutArray a
forall a. Array a -> MutArray a
unsafeThaw Unfold m (MutArray a) a
unf

-- XXX DO NOT REMOVE, change the signature to use Stream instead of unfold
{-# DEPRECATED getIndices "Please use getIndices instead." #-}
{-# INLINE getIndices #-}
getIndices :: (Monad m, Unbox a) => Stream m Int -> Unfold m (Array a) a
getIndices :: forall (m :: * -> *) a.
(Monad m, Unbox a) =>
Stream m Int -> Unfold m (Array a) a
getIndices = Stream m Int -> Unfold m (Array a) a
forall (m :: * -> *) a.
(Monad m, Unbox a) =>
Stream m Int -> Unfold m (Array a) a
indexReader

-- | Unfolds @(from, then, to, array)@ generating a finite stream whose first
-- element is the array value from the index @from@ and the successive elements
-- are from the indices in increments of @then@ up to @to@. Index enumeration
-- can occur downwards or upwards depending on whether @then@ comes before or
-- after @from@.
--
-- @
-- getIndicesFromThenTo =
--     let f (from, next, to, arr) =
--             (Stream.enumerateFromThenTo from next to, arr)
--      in Unfold.lmap f getIndices
-- @
--
-- /Unimplemented/
{-# INLINE indexReaderFromThenTo #-}
indexReaderFromThenTo :: Unfold m (Int, Int, Int, Array a) a
indexReaderFromThenTo :: forall (m :: * -> *) a. Unfold m (Int, Int, Int, Array a) a
indexReaderFromThenTo = Unfold m (Int, Int, Int, Array a) a
forall a. HasCallStack => a
undefined

-------------------------------------------------------------------------------
-- Transform via stream operations
-------------------------------------------------------------------------------

-- for non-length changing operations we can use the original length for
-- allocation. If we can predict the length then we can use the prediction for
-- new allocation. Otherwise we can use a hint and adjust dynamically.

{-
-- | Transform an array into another array using a pipe transformation
-- operation.
--
{-# INLINE runPipe #-}
runPipe :: (MonadIO m, Unbox a, Unbox b)
    => Pipe m a b -> Array a -> m (Array b)
runPipe f arr = P.runPipe (toArrayMinChunk (length arr)) $ f (read arr)
-}

-- XXX For transformations that cannot change the number of elements e.g. "map"
-- we can use a predetermined array length.
--
-- | Transform an array into another array using a stream transformation
-- operation.
--
-- /Pre-release/
{-# INLINE streamTransform #-}
streamTransform :: forall m a b. (MonadIO m, Unbox a, Unbox b)
    => (Stream m a -> Stream m b) -> Array a -> m (Array b)
streamTransform :: forall (m :: * -> *) a b.
(MonadIO m, Unbox a, Unbox b) =>
(Stream m a -> Stream m b) -> Array a -> m (Array b)
streamTransform Stream m a -> Stream m b
f Array a
arr =
    Fold m b (Array b) -> Stream m b -> m (Array b)
forall (m :: * -> *) a b.
Monad m =>
Fold m a b -> Stream m a -> m b
Stream.fold (Int -> Fold m b (Array b)
forall (m :: * -> *) a.
(MonadIO m, Unbox a) =>
Int -> Fold m a (Array a)
createWith (Array a -> Int
forall a. Unbox a => Array a -> Int
length Array a
arr)) (Stream m b -> m (Array b)) -> Stream m b -> m (Array b)
forall a b. (a -> b) -> a -> b
$ Stream m a -> Stream m b
f (Array a -> Stream m a
forall (m :: * -> *) a. (Monad m, Unbox a) => Array a -> Stream m a
read Array a
arr)

-------------------------------------------------------------------------------
-- Casts
-------------------------------------------------------------------------------

-- | Cast an array having elements of type @a@ into an array having elements of
-- type @b@. The array size must be a multiple of the size of type @b@
-- otherwise accessing the last element of the array may result into a crash or
-- a random value.
--
-- /Pre-release/
--
unsafeCast, castUnsafe ::
#ifdef DEVBUILD
    Unbox b =>
#endif
    Array a -> Array b
unsafeCast :: forall a b. Array a -> Array b
unsafeCast (Array MutByteArray
contents Int
start Int
end) =
    MutByteArray -> Int -> Int -> Array b
forall a. MutByteArray -> Int -> Int -> Array a
Array MutByteArray
contents Int
start Int
end
RENAME(castUnsafe,unsafeCast)

-- | Cast an @Array a@ into an @Array Word8@.
--
--
asBytes :: Array a -> Array Word8
asBytes :: forall a. Array a -> Array Word8
asBytes = Array a -> Array Word8
forall a b. Array a -> Array b
unsafeCast

-- | Cast an array having elements of type @a@ into an array having elements of
-- type @b@. The length of the array should be a multiple of the size of the
-- target element otherwise 'Nothing' is returned.
--
--
cast :: forall a b. (Unbox b) => Array a -> Maybe (Array b)
cast :: forall a b. Unbox b => Array a -> Maybe (Array b)
cast Array a
arr =
    let len :: Int
len = Array a -> Int
forall a. Array a -> Int
byteLength Array a
arr
        r :: Int
r = Int
len Int -> Int -> Int
forall a. Integral a => a -> a -> a
`mod` SIZE_OF(b)
     in if Int
r Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
/= Int
0
        then Maybe (Array b)
forall a. Maybe a
Nothing
        else Array b -> Maybe (Array b)
forall a. a -> Maybe a
Just (Array b -> Maybe (Array b)) -> Array b -> Maybe (Array b)
forall a b. (a -> b) -> a -> b
$ Array a -> Array b
forall a b. Array a -> Array b
unsafeCast Array a
arr

-- | Convert an array of any element type into a null terminated CString Ptr.
-- The array is copied to pinned memory.
--
-- /Unsafe/
--
-- /O(n) Time: (creates a copy of the array)/
--
-- /Pre-release/
--
asCStringUnsafe :: Array a -> (CString -> IO b) -> IO b
asCStringUnsafe :: forall a b. Array a -> (CString -> IO b) -> IO b
asCStringUnsafe Array a
arr = MutArray a -> (CString -> IO b) -> IO b
forall a b. MutArray a -> (CString -> IO b) -> IO b
MA.asCString (Array a -> MutArray a
forall a. Array a -> MutArray a
unsafeThaw Array a
arr)

-- | Convert an array of any element type into a null terminated CWString Ptr.
-- The array is copied to pinned memory.
--
-- /Unsafe/
--
-- /O(n) Time: (creates a copy of the array)/
--
-- /Pre-release/
--
asCWString :: Array a -> (CWString -> IO b) -> IO b
asCWString :: forall a b. Array a -> (CWString -> IO b) -> IO b
asCWString Array a
arr = MutArray a -> (CWString -> IO b) -> IO b
forall a b. MutArray a -> (CWString -> IO b) -> IO b
MA.asCWString (Array a -> MutArray a
forall a. Array a -> MutArray a
unsafeThaw Array a
arr)

-------------------------------------------------------------------------------
-- Folds
-------------------------------------------------------------------------------

-- XXX Use runIdentity for pure fold
-- XXX Rename fold to foldM, we can then use "fold" for pure folds.
-- XXX We do not need an INLINE on fold?

-- | Fold an array using a 'Fold'.
--
-- /Pre-release/
{-# INLINE foldM #-}
fold, foldM :: (Monad m, Unbox a) => Fold m a b -> Array a -> m b
foldM :: forall (m :: * -> *) a b.
(Monad m, Unbox a) =>
Fold m a b -> Array a -> m b
foldM Fold m a b
f Array a
arr = Fold m a b -> Stream m a -> m b
forall (m :: * -> *) a b.
Monad m =>
Fold m a b -> Stream m a -> m b
Stream.fold Fold m a b
f (Array a -> Stream m a
forall (m :: * -> *) a. (Monad m, Unbox a) => Array a -> Stream m a
read Array a
arr)
RENAME(fold,foldM)

foldRev :: Unbox a => Fold.Fold Identity a b -> Array a -> b
foldRev :: forall a b. Unbox a => Fold Identity a b -> Array a -> b
foldRev Fold Identity a b
f Array a
arr = Identity b -> b
forall a. Identity a -> a
runIdentity (Identity b -> b) -> Identity b -> b
forall a b. (a -> b) -> a -> b
$ Fold Identity a b -> Stream Identity a -> Identity b
forall (m :: * -> *) a b.
Monad m =>
Fold m a b -> Stream m a -> m b
Stream.fold Fold Identity a b
f (Array a -> Stream Identity a
forall (m :: * -> *) a. (Monad m, Unbox a) => Array a -> Stream m a
readRev Array a
arr)

-- | Fold an array using a stream fold operation.
--
-- /Pre-release/
{-# INLINE streamFold #-}
streamFold :: (Monad m, Unbox a) => (Stream m a -> m b) -> Array a -> m b
streamFold :: forall (m :: * -> *) a b.
(Monad m, Unbox a) =>
(Stream m a -> m b) -> Array a -> m b
streamFold Stream m a -> m b
f Array a
arr = Stream m a -> m b
f (Array a -> Stream m a
forall (m :: * -> *) a. (Monad m, Unbox a) => Array a -> Stream m a
read Array a
arr)

--------------------------------------------------------------------------------
-- Serialization
--------------------------------------------------------------------------------

{-# INLINE encodeAs #-}
encodeAs :: forall a. Serialize a => PinnedState -> a -> Array Word8
encodeAs :: forall a. Serialize a => PinnedState -> a -> Array Word8
encodeAs PinnedState
ps a
a =
    IO (Array Word8) -> Array Word8
forall a. IO a -> a
unsafeInlineIO (IO (Array Word8) -> Array Word8)
-> IO (Array Word8) -> Array Word8
forall a b. (a -> b) -> a -> b
$ do
        let len :: Int
len = Int -> a -> Int
forall a. Serialize a => Int -> a -> Int
Serialize.addSizeTo Int
0 a
a
        MutByteArray
mbarr <- PinnedState -> Int -> IO MutByteArray
MBA.newAs PinnedState
ps Int
len
        Int
off <- Int -> MutByteArray -> a -> IO Int
forall a. Serialize a => Int -> MutByteArray -> a -> IO Int
Serialize.serializeAt Int
0 MutByteArray
mbarr a
a
        assertM(Int
len Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
off)
        Array Word8 -> IO (Array Word8)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Array Word8 -> IO (Array Word8))
-> Array Word8 -> IO (Array Word8)
forall a b. (a -> b) -> a -> b
$ MutByteArray -> Int -> Int -> Array Word8
forall a. MutByteArray -> Int -> Int -> Array a
Array MutByteArray
mbarr Int
0 Int
off

-- |
-- Properties:
-- 1. Identity: @deserialize . serialize == id@
-- 2. Encoded equivalence: @serialize a == serialize a@
{-# INLINE serialize #-}
serialize :: Serialize a => a -> Array Word8
serialize :: forall a. Serialize a => a -> Array Word8
serialize = PinnedState -> a -> Array Word8
forall a. Serialize a => PinnedState -> a -> Array Word8
encodeAs PinnedState
Unpinned

-- | Serialize a Haskell type to a pinned byte array. The array is allocated
-- using pinned memory so that it can be used directly in OS APIs for writing
-- to file or sending over the network.
--
-- Properties:
--
-- 1. Identity: @deserialize . serialize' == id@
-- 2. Encoded equivalence: @serialize' a == serialize' a@
{-# INLINE serialize' #-}
pinnedSerialize, serialize' :: Serialize a => a -> Array Word8
serialize' :: forall a. Serialize a => a -> Array Word8
serialize' = PinnedState -> a -> Array Word8
forall a. Serialize a => PinnedState -> a -> Array Word8
encodeAs PinnedState
Pinned
RENAME_PRIME(pinnedSerialize,serialize)

-- XXX We can deserialize it like MutArray, returning the remaining slice.

-- | Decode a Haskell type from a byte array containing its serialized
-- representation.
{-# INLINE deserialize #-}
deserialize :: Serialize a => Array Word8 -> (a, Array Word8)
deserialize :: forall a. Serialize a => Array Word8 -> (a, Array Word8)
deserialize Array Word8
arr =
    let (a
a, MutArray Word8
b) = IO (a, MutArray Word8) -> (a, MutArray Word8)
forall a. IO a -> a
unsafeInlineIO (IO (a, MutArray Word8) -> (a, MutArray Word8))
-> IO (a, MutArray Word8) -> (a, MutArray Word8)
forall a b. (a -> b) -> a -> b
$ MutArray Word8 -> IO (a, MutArray Word8)
forall (m :: * -> *) a.
(MonadIO m, Serialize a) =>
MutArray Word8 -> m (a, MutArray Word8)
MA.deserialize (Array Word8 -> MutArray Word8
forall a. Array a -> MutArray a
unsafeThaw Array Word8
arr)
     in (a
a, MutArray Word8 -> Array Word8
forall a. MutArray a -> Array a
unsafeFreeze MutArray Word8
b)

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

-- TODO: efficiently compare two streams of arrays. Two streams can have chunks
-- of different sizes, we can handle that in the stream comparison abstraction.
-- This could be useful e.g. to fast compare whether two files differ.

-- | Insert the given element between arrays and flatten.
--
-- >>> concatSepBy x = Stream.unfoldEachSepBy x Array.reader
--
{-# INLINE concatSepBy #-}
concatSepBy, interpose :: (Monad m, Unbox a) =>
    a -> Stream m (Array a) -> Stream m a
concatSepBy :: forall (m :: * -> *) a.
(Monad m, Unbox a) =>
a -> Stream m (Array a) -> Stream m a
concatSepBy a
x = a -> Unfold m (Array a) a -> Stream m (Array a) -> Stream m a
forall (m :: * -> *) c b.
Monad m =>
c -> Unfold m b c -> Stream m b -> Stream m c
D.unfoldEachSepBy a
x Unfold m (Array a) a
forall (m :: * -> *) a. (Monad m, Unbox a) => Unfold m (Array a) a
reader

RENAME(interpose,concatSepBy)

data FlattenState s =
      OuterLoop s
    | InnerLoop s !MutByteArray !Int !Int

-- | Insert the given element after each array and flatten. This is similar to
-- unlines.
--
-- >>> concatEndBy x = Stream.unfoldEachEndBy x Array.reader
--
{-# INLINE_NORMAL concatEndBy #-}
concatEndBy, interposeSuffix :: forall m a. (Monad m, Unbox a)
    => a -> Stream m (Array a) -> Stream m a
-- concatEndBy x = D.unfoldEachEndBy x reader
concatEndBy :: forall (m :: * -> *) a.
(Monad m, Unbox a) =>
a -> Stream m (Array a) -> Stream m a
concatEndBy a
sep (D.Stream State StreamK m (Array a) -> s -> m (Step s (Array a))
step s
state) = (State StreamK m a
 -> FlattenState s -> m (Step (FlattenState s) a))
-> FlattenState s -> Stream m a
forall (m :: * -> *) a s.
(State StreamK m a -> s -> m (Step s a)) -> s -> Stream m a
D.Stream State StreamK m a -> FlattenState s -> m (Step (FlattenState s) a)
forall {m :: * -> *} {a}.
State StreamK m a -> FlattenState s -> m (Step (FlattenState s) a)
step' (s -> FlattenState s
forall s. s -> FlattenState s
OuterLoop s
state)

    where

    {-# INLINE_LATE step' #-}
    step' :: State StreamK m a -> FlattenState s -> m (Step (FlattenState s) a)
step' State StreamK m a
gst (OuterLoop s
st) = do
        Step s (Array a)
r <- State StreamK m (Array a) -> s -> m (Step s (Array a))
step (State StreamK m a -> State StreamK m (Array a)
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a (n :: * -> *) b.
State t m a -> State t n b
adaptState State StreamK m a
gst) s
st
        Step (FlattenState s) a -> m (Step (FlattenState s) a)
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (Step (FlattenState s) a -> m (Step (FlattenState s) a))
-> Step (FlattenState s) a -> m (Step (FlattenState s) a)
forall a b. (a -> b) -> a -> b
$ case Step s (Array a)
r of
            D.Yield Array{Int
MutByteArray
arrContents :: MutByteArray
arrStart :: Int
arrEnd :: Int
arrEnd :: forall a. Array a -> Int
arrStart :: forall a. Array a -> Int
arrContents :: forall a. Array a -> MutByteArray
..} s
s ->
                FlattenState s -> Step (FlattenState s) a
forall s a. s -> Step s a
D.Skip (s -> MutByteArray -> Int -> Int -> FlattenState s
forall s. s -> MutByteArray -> Int -> Int -> FlattenState s
InnerLoop s
s MutByteArray
arrContents Int
arrStart Int
arrEnd)
            D.Skip s
s -> FlattenState s -> Step (FlattenState s) a
forall s a. s -> Step s a
D.Skip (s -> FlattenState s
forall s. s -> FlattenState s
OuterLoop s
s)
            Step s (Array a)
D.Stop -> Step (FlattenState s) a
forall s a. Step s a
D.Stop

    step' State StreamK m a
_ (InnerLoop s
st MutByteArray
_ Int
p Int
end) | Int
p Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
end =
        Step (FlattenState s) a -> m (Step (FlattenState s) a)
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (Step (FlattenState s) a -> m (Step (FlattenState s) a))
-> Step (FlattenState s) a -> m (Step (FlattenState s) a)
forall a b. (a -> b) -> a -> b
$ a -> FlattenState s -> Step (FlattenState s) a
forall s a. a -> s -> Step s a
D.Yield a
sep (FlattenState s -> Step (FlattenState s) a)
-> FlattenState s -> Step (FlattenState s) a
forall a b. (a -> b) -> a -> b
$ s -> FlattenState s
forall s. s -> FlattenState s
OuterLoop s
st

    step' State StreamK m a
_ (InnerLoop s
st MutByteArray
contents Int
p Int
end) = do
        let !x :: a
x = IO a -> a
forall a. IO a -> a
unsafeInlineIO (IO a -> a) -> IO a -> a
forall a b. (a -> b) -> a -> b
$ Int -> MutByteArray -> IO a
forall a. Unbox a => Int -> MutByteArray -> IO a
peekAt Int
p MutByteArray
contents
        Step (FlattenState s) a -> m (Step (FlattenState s) a)
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (Step (FlattenState s) a -> m (Step (FlattenState s) a))
-> Step (FlattenState s) a -> m (Step (FlattenState s) a)
forall a b. (a -> b) -> a -> b
$ a -> FlattenState s -> Step (FlattenState s) a
forall s a. a -> s -> Step s a
D.Yield a
x (s -> MutByteArray -> Int -> Int -> FlattenState s
forall s. s -> MutByteArray -> Int -> Int -> FlattenState s
InnerLoop s
st MutByteArray
contents (INDEX_NEXT(p,a)) end)

RENAME(interposeSuffix,concatEndBy)

-- | Insert the given array after each array and flatten.
--
-- >>> concatEndBySeq x = Stream.unfoldEachEndBySeq x Array.reader
--
{-# INLINE concatEndBySeq #-}
concatEndBySeq, intercalateSuffix :: (Monad m, Unbox a)
    => Array a -> Stream m (Array a) -> Stream m a
concatEndBySeq :: forall (m :: * -> *) a.
(Monad m, Unbox a) =>
Array a -> Stream m (Array a) -> Stream m a
concatEndBySeq Array a
x = Array a -> Unfold m (Array a) a -> Stream m (Array a) -> Stream m a
forall (m :: * -> *) b c.
Monad m =>
b -> Unfold m b c -> Stream m b -> Stream m c
D.unfoldEachEndBySeq Array a
x Unfold m (Array a) a
forall (m :: * -> *) a. (Monad m, Unbox a) => Unfold m (Array a) a
reader

RENAME(intercalateSuffix,concatEndBySeq)

-- | @compactMax n@ coalesces adjacent arrays in the input stream
-- only if the combined size would be less than or equal to n.
--
-- Generates unpinned arrays irrespective of the pinning status of input
-- arrays.
{-# INLINE_NORMAL compactMax #-}
compactMax, compactLE :: (MonadIO m, Unbox a)
    => Int -> Stream m (Array a) -> Stream m (Array a)
compactMax :: forall (m :: * -> *) a.
(MonadIO m, Unbox a) =>
Int -> Stream m (Array a) -> Stream m (Array a)
compactMax Int
n Stream m (Array a)
stream =
    (MutArray a -> Array a)
-> Stream m (MutArray a) -> Stream m (Array a)
forall (m :: * -> *) a b.
Monad m =>
(a -> b) -> Stream m a -> Stream m b
D.map MutArray a -> Array a
forall a. MutArray a -> Array a
unsafeFreeze (Stream m (MutArray a) -> Stream m (Array a))
-> Stream m (MutArray a) -> Stream m (Array a)
forall a b. (a -> b) -> a -> b
$ 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)
MA.compactMax Int
n (Stream m (MutArray a) -> Stream m (MutArray a))
-> Stream m (MutArray a) -> Stream m (MutArray a)
forall a b. (a -> b) -> a -> b
$ (Array a -> MutArray a)
-> Stream m (Array a) -> Stream m (MutArray a)
forall (m :: * -> *) a b.
Monad m =>
(a -> b) -> Stream m a -> Stream m b
D.map Array a -> MutArray a
forall a. Array a -> MutArray a
unsafeThaw Stream m (Array a)
stream

RENAME(compactLE,compactMax)

-- | Like 'compactMax' but generates pinned arrays.
{-# INLINE_NORMAL compactMax' #-}
compactMax', pinnedCompactLE :: (MonadIO m, Unbox a)
    => Int -> Stream m (Array a) -> Stream m (Array a)
compactMax' :: forall (m :: * -> *) a.
(MonadIO m, Unbox a) =>
Int -> Stream m (Array a) -> Stream m (Array a)
compactMax' Int
n Stream m (Array a)
stream =
    (MutArray a -> Array a)
-> Stream m (MutArray a) -> Stream m (Array a)
forall (m :: * -> *) a b.
Monad m =>
(a -> b) -> Stream m a -> Stream m b
D.map MutArray a -> Array a
forall a. MutArray a -> Array a
unsafeFreeze (Stream m (MutArray a) -> Stream m (Array a))
-> Stream m (MutArray a) -> Stream m (Array a)
forall a b. (a -> b) -> a -> b
$ 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)
MA.compactMax' Int
n (Stream m (MutArray a) -> Stream m (MutArray a))
-> Stream m (MutArray a) -> Stream m (MutArray a)
forall a b. (a -> b) -> a -> b
$ (Array a -> MutArray a)
-> Stream m (Array a) -> Stream m (MutArray a)
forall (m :: * -> *) a b.
Monad m =>
(a -> b) -> Stream m a -> Stream m b
D.map Array a -> MutArray a
forall a. Array a -> MutArray a
unsafeThaw Stream m (Array a)
stream

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

-- | Split a stream of byte 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 (Array Word8)
    -> Stream m (Array Word8)
compactSepByByte_ :: forall (m :: * -> *).
MonadIO m =>
Word8 -> Stream m (Array Word8) -> Stream m (Array Word8)
compactSepByByte_ Word8
byte =
    (MutArray Word8 -> Array Word8)
-> Stream m (MutArray Word8) -> Stream m (Array Word8)
forall a b. (a -> b) -> Stream m a -> Stream m b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap MutArray Word8 -> Array Word8
forall a. MutArray a -> Array a
unsafeFreeze (Stream m (MutArray Word8) -> Stream m (Array Word8))
-> (Stream m (Array Word8) -> Stream m (MutArray Word8))
-> Stream m (Array Word8)
-> Stream m (Array Word8)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word8 -> Stream m (MutArray Word8) -> Stream m (MutArray Word8)
forall (m :: * -> *).
MonadIO m =>
Word8 -> Stream m (MutArray Word8) -> Stream m (MutArray Word8)
MA.compactSepByByte_ Word8
byte (Stream m (MutArray Word8) -> Stream m (MutArray Word8))
-> (Stream m (Array Word8) -> Stream m (MutArray Word8))
-> Stream m (Array Word8)
-> Stream m (MutArray Word8)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Array Word8 -> MutArray Word8)
-> Stream m (Array Word8) -> Stream m (MutArray Word8)
forall a b. (a -> b) -> Stream m a -> Stream m b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Array Word8 -> MutArray Word8
forall a. Array a -> MutArray a
unsafeThaw

RENAME(compactOnByte,compactSepByByte_)

-- | Like 'compactSepByByte_', but considers the separator in suffix position
-- instead of infix position.
{-# INLINE compactEndByByte_ #-}
compactEndByByte_, compactOnByteSuffix
    :: (MonadIO m)
    => Word8
    -> Stream m (Array Word8)
    -> Stream m (Array Word8)
compactEndByByte_ :: forall (m :: * -> *).
MonadIO m =>
Word8 -> Stream m (Array Word8) -> Stream m (Array Word8)
compactEndByByte_ Word8
byte =
    (MutArray Word8 -> Array Word8)
-> Stream m (MutArray Word8) -> Stream m (Array Word8)
forall a b. (a -> b) -> Stream m a -> Stream m b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap MutArray Word8 -> Array Word8
forall a. MutArray a -> Array a
unsafeFreeze (Stream m (MutArray Word8) -> Stream m (Array Word8))
-> (Stream m (Array Word8) -> Stream m (MutArray Word8))
-> Stream m (Array Word8)
-> Stream m (Array Word8)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word8 -> Stream m (MutArray Word8) -> Stream m (MutArray Word8)
forall (m :: * -> *).
MonadIO m =>
Word8 -> Stream m (MutArray Word8) -> Stream m (MutArray Word8)
MA.compactEndByByte_ Word8
byte (Stream m (MutArray Word8) -> Stream m (MutArray Word8))
-> (Stream m (Array Word8) -> Stream m (MutArray Word8))
-> Stream m (Array Word8)
-> Stream m (MutArray Word8)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Array Word8 -> MutArray Word8)
-> Stream m (Array Word8) -> Stream m (MutArray Word8)
forall a b. (a -> b) -> Stream m a -> Stream m b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Array Word8 -> MutArray Word8
forall a. Array a -> MutArray a
unsafeThaw
-- compactEndByByte_ byte = chunksEndBy_ (== byte) . concat

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 (Array Word8)
    -> Stream m (Array Word8)
compactEndByLn_ :: forall (m :: * -> *).
MonadIO m =>
Stream m (Array Word8) -> Stream m (Array Word8)
compactEndByLn_ = Word8 -> Stream m (Array Word8) -> Stream m (Array Word8)
forall (m :: * -> *).
MonadIO m =>
Word8 -> Stream m (Array Word8) -> Stream m (Array Word8)
compactEndByByte_ Word8
10

-------------------------------------------------------------------------------
-- Folding Streams of Arrays
-------------------------------------------------------------------------------

-- XXX This should not be used for breaking a stream as the D.cons used in
-- reconstructing the stream could be very bad for performance. This can only
-- be useful in folding without breaking.
{-# INLINE_NORMAL foldBreakChunks #-}
foldBreakChunks :: forall m a b. (MonadIO m, Unbox a) =>
    Fold m a b -> Stream m (Array a) -> m (b, Stream m (Array a))
foldBreakChunks :: forall (m :: * -> *) a b.
(MonadIO m, Unbox a) =>
Fold m a b -> Stream m (Array a) -> m (b, Stream m (Array a))
foldBreakChunks (Fold s -> a -> m (Step s b)
fstep m (Step s b)
initial s -> m b
_ s -> m b
final) stream :: Stream m (Array a)
stream@(Stream State StreamK m (Array a) -> s -> m (Step s (Array a))
step s
state) = do
    Step s b
res <- m (Step s b)
initial
    case Step s b
res of
        Fold.Partial s
fs -> SPEC -> s -> s -> m (b, Stream m (Array a))
go SPEC
SPEC s
state s
fs
        Fold.Done b
fb -> (b, Stream m (Array a)) -> m (b, Stream m (Array a))
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return ((b, Stream m (Array a)) -> m (b, Stream m (Array a)))
-> (b, Stream m (Array a)) -> m (b, Stream m (Array a))
forall a b. (a -> b) -> a -> b
$! (b
fb, Stream m (Array a)
stream)

    where

    {-# INLINE go #-}
    go :: SPEC -> s -> s -> m (b, Stream m (Array a))
go !SPEC
_ s
st !s
fs = do
        Step s (Array a)
r <- State StreamK m (Array a) -> s -> m (Step s (Array a))
step State StreamK m (Array a)
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a. State t m a
defState s
st
        case Step s (Array a)
r of
            Stream.Yield (Array MutByteArray
contents Int
start Int
end) s
s ->
                let fp :: Tuple' Int MutByteArray
fp = Int -> MutByteArray -> Tuple' Int MutByteArray
forall a b. a -> b -> Tuple' a b
Tuple' Int
end MutByteArray
contents
                 in SPEC
-> s
-> Tuple' Int MutByteArray
-> Int
-> s
-> m (b, Stream m (Array a))
goArray SPEC
SPEC s
s Tuple' Int MutByteArray
fp Int
start s
fs
            Stream.Skip s
s -> SPEC -> s -> s -> m (b, Stream m (Array a))
go SPEC
SPEC s
s s
fs
            Step s (Array a)
Stream.Stop -> do
                b
b <- s -> m b
final s
fs
                (b, Stream m (Array a)) -> m (b, Stream m (Array a))
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (b
b, Stream m (Array a)
forall (m :: * -> *) a. Applicative m => Stream m a
D.nil)

    goArray :: SPEC
-> s
-> Tuple' Int MutByteArray
-> Int
-> s
-> m (b, Stream m (Array a))
goArray !SPEC
_ s
s (Tuple' Int
end MutByteArray
_) !Int
cur !s
fs
        | Int
cur Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
end = do
            SPEC -> s -> s -> m (b, Stream m (Array a))
go SPEC
SPEC s
s s
fs
    goArray !SPEC
_ s
st fp :: Tuple' Int MutByteArray
fp@(Tuple' Int
end MutByteArray
contents) !Int
cur !s
fs = do
        a
x <- IO a -> m a
forall a. IO a -> m a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO a -> m a) -> IO a -> m a
forall a b. (a -> b) -> a -> b
$ Int -> MutByteArray -> IO a
forall a. Unbox a => Int -> MutByteArray -> IO a
peekAt Int
cur MutByteArray
contents
        Step s b
res <- s -> a -> m (Step s b)
fstep s
fs a
x
        let next :: Int
next = INDEX_NEXT(cur,a)
        case Step s b
res of
            Fold.Done b
b -> do
                let arr :: Array a
arr = MutByteArray -> Int -> Int -> Array a
forall a. MutByteArray -> Int -> Int -> Array a
Array MutByteArray
contents Int
next Int
end
                (b, Stream m (Array a)) -> m (b, Stream m (Array a))
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return ((b, Stream m (Array a)) -> m (b, Stream m (Array a)))
-> (b, Stream m (Array a)) -> m (b, Stream m (Array a))
forall a b. (a -> b) -> a -> b
$! (b
b, Array a -> Stream m (Array a) -> Stream m (Array a)
forall (m :: * -> *) a.
Applicative m =>
a -> Stream m a -> Stream m a
D.cons Array a
forall a. Array a
arr ((State StreamK m (Array a) -> s -> m (Step s (Array a)))
-> s -> Stream m (Array a)
forall (m :: * -> *) a s.
(State StreamK m a -> s -> m (Step s a)) -> s -> Stream m a
D.Stream State StreamK m (Array a) -> s -> m (Step s (Array a))
step s
st))
            Fold.Partial s
fs1 -> SPEC
-> s
-> Tuple' Int MutByteArray
-> Int
-> s
-> m (b, Stream m (Array a))
goArray SPEC
SPEC s
st Tuple' Int MutByteArray
fp Int
next s
fs1

-- This may be more robust wrt fusion compared to unfoldMany?

-- | Fold a stream of arrays using a 'Fold'. This is equivalent to the
-- following:
--
-- >>> foldChunks f = Stream.fold f . Stream.unfoldEach Array.reader
--
foldChunks :: (MonadIO m, Unbox a) => Fold m a b -> Stream m (Array a) -> m b
foldChunks :: forall (m :: * -> *) a b.
(MonadIO m, Unbox a) =>
Fold m a b -> Stream m (Array a) -> m b
foldChunks Fold m a b
f Stream m (Array a)
s = ((b, Stream m (Array a)) -> b) -> m (b, Stream m (Array a)) -> m b
forall a b. (a -> b) -> m a -> m b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (b, Stream m (Array a)) -> b
forall a b. (a, b) -> a
fst (Fold m a b -> Stream m (Array a) -> m (b, Stream m (Array a))
forall (m :: * -> *) a b.
(MonadIO m, Unbox a) =>
Fold m a b -> Stream m (Array a) -> m (b, Stream m (Array a))
foldBreakChunks Fold m a b
f Stream m (Array a)
s)
-- foldStream f = Stream.fold f . Stream.unfoldEach reader

-- | Fold a stream of arrays using a 'Fold' and return the remaining stream.
--
-- The following alternative to this function allows composing the fold using
-- the parser Monad:
--
-- @
-- foldBreakStreamK f s =
--       fmap (first (fromRight undefined))
--     $ StreamK.parseBreakChunks (ParserK.adaptC (Parser.fromFold f)) s
-- @
--
-- We can compare perf and remove this one or define it in terms of that.
--
foldBreak, foldBreakChunksK :: forall m a b. (MonadIO m, Unbox a) =>
    Fold m a b -> StreamK m (Array a) -> m (b, StreamK m (Array a))
{-
foldBreakChunksK f s =
      fmap (first (fromRight undefined))
    $ StreamK.parseBreakChunks (ParserK.adaptC (Parser.fromFold f)) s
-}
foldBreak :: forall (m :: * -> *) a b.
(MonadIO m, Unbox a) =>
Fold m a b -> StreamK m (Array a) -> m (b, StreamK m (Array a))
foldBreak (Fold s -> a -> m (Step s b)
fstep m (Step s b)
initial s -> m b
_ s -> m b
final) StreamK m (Array a)
stream = do
    Step s b
res <- m (Step s b)
initial
    case Step s b
res of
        Fold.Partial s
fs -> s -> StreamK m (Array a) -> m (b, StreamK m (Array a))
forall {a}. s -> StreamK m (Array a) -> m (b, StreamK m (Array a))
go s
fs StreamK m (Array a)
stream
        Fold.Done b
fb -> (b, StreamK m (Array a)) -> m (b, StreamK m (Array a))
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (b
fb, StreamK m (Array a)
stream)

    where

    {-# INLINE go #-}
    go :: s -> StreamK m (Array a) -> m (b, StreamK m (Array a))
go !s
fs StreamK m (Array a)
st = do
        let stop :: m (b, StreamK m a)
stop = (, StreamK m a
forall (m :: * -> *) a. StreamK m a
StreamK.nil) (b -> (b, StreamK m a)) -> m b -> m (b, StreamK m a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> s -> m b
final s
fs
            single :: Array a -> m (b, StreamK m (Array a))
single Array a
a = Array a -> StreamK m (Array a) -> m (b, StreamK m (Array a))
forall {a}.
Array a -> StreamK m (Array a) -> m (b, StreamK m (Array a))
yieldk Array a
a StreamK m (Array a)
forall (m :: * -> *) a. StreamK m a
StreamK.nil
            yieldk :: Array a -> StreamK m (Array a) -> m (b, StreamK m (Array a))
yieldk (Array MutByteArray
contents Int
start Int
end) StreamK m (Array a)
r =
                let fp :: Tuple' Int MutByteArray
fp = Int -> MutByteArray -> Tuple' Int MutByteArray
forall a b. a -> b -> Tuple' a b
Tuple' Int
end MutByteArray
contents
                 in s
-> StreamK m (Array a)
-> Tuple' Int MutByteArray
-> Int
-> m (b, StreamK m (Array a))
goArray s
fs StreamK m (Array a)
r Tuple' Int MutByteArray
fp Int
start
         in State StreamK m (Array a)
-> (Array a -> StreamK m (Array a) -> m (b, StreamK m (Array a)))
-> (Array a -> m (b, StreamK m (Array a)))
-> m (b, StreamK m (Array a))
-> StreamK m (Array a)
-> m (b, StreamK m (Array a))
forall (m :: * -> *) a r.
State StreamK m a
-> (a -> StreamK m a -> m r)
-> (a -> m r)
-> m r
-> StreamK m a
-> m r
StreamK.foldStream State StreamK m (Array a)
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a. State t m a
defState Array a -> StreamK m (Array a) -> m (b, StreamK m (Array a))
forall {a}.
Array a -> StreamK m (Array a) -> m (b, StreamK m (Array a))
yieldk Array a -> m (b, StreamK m (Array a))
forall {a}. Array a -> m (b, StreamK m (Array a))
single m (b, StreamK m (Array a))
forall {m :: * -> *} {a}. m (b, StreamK m a)
stop StreamK m (Array a)
st

    goArray :: s
-> StreamK m (Array a)
-> Tuple' Int MutByteArray
-> Int
-> m (b, StreamK m (Array a))
goArray !s
fs StreamK m (Array a)
st (Tuple' Int
end MutByteArray
_) !Int
cur
        | Int
cur Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
end = do
            s -> StreamK m (Array a) -> m (b, StreamK m (Array a))
go s
fs StreamK m (Array a)
st
    goArray !s
fs StreamK m (Array a)
st fp :: Tuple' Int MutByteArray
fp@(Tuple' Int
end MutByteArray
contents) !Int
cur = do
        a
x <- IO a -> m a
forall a. IO a -> m a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO a -> m a) -> IO a -> m a
forall a b. (a -> b) -> a -> b
$ Int -> MutByteArray -> IO a
forall a. Unbox a => Int -> MutByteArray -> IO a
peekAt Int
cur MutByteArray
contents
        Step s b
res <- s -> a -> m (Step s b)
fstep s
fs a
x
        let next :: Int
next = INDEX_NEXT(cur,a)
        case Step s b
res of
            Fold.Done b
b -> do
                let arr :: Array a
arr = MutByteArray -> Int -> Int -> Array a
forall a. MutByteArray -> Int -> Int -> Array a
Array MutByteArray
contents Int
next Int
end
                (b, StreamK m (Array a)) -> m (b, StreamK m (Array a))
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return ((b, StreamK m (Array a)) -> m (b, StreamK m (Array a)))
-> (b, StreamK m (Array a)) -> m (b, StreamK m (Array a))
forall a b. (a -> b) -> a -> b
$! (b
b, Array a -> StreamK m (Array a) -> StreamK m (Array a)
forall a (m :: * -> *). a -> StreamK m a -> StreamK m a
StreamK.cons Array a
forall a. Array a
arr StreamK m (Array a)
st)
            Fold.Partial s
fs1 -> s
-> StreamK m (Array a)
-> Tuple' Int MutByteArray
-> Int
-> m (b, StreamK m (Array a))
goArray s
fs1 StreamK m (Array a)
st Tuple' Int MutByteArray
fp Int
next

RENAME(foldBreakChunksK,foldBreak)

{-
-- This can be generalized to any type provided it can be unfolded to a stream
-- and it can be combined using a semigroup operation.
--
{-# INLINE_NORMAL parseBreakD #-}
parseBreakD ::
       forall m a b. (MonadIO m, MonadThrow m, Unbox a)
    => PRD.Parser a m b
    -> D.Stream m (Array.Array a)
    -> m (b, D.Stream m (Array.Array a))
parseBreakD
    (PRD.Parser pstep initial extract) stream@(D.Stream step state) = do

    res <- initial
    case res of
        PRD.IPartial s -> go SPEC state (List []) s
        PRD.IDone b -> return (b, stream)
        PRD.IError err -> throwM $ ParseError err

    where

    -- "backBuf" contains last few items in the stream that we may have to
    -- backtrack to.
    --
    -- XXX currently we are using a dumb list based approach for backtracking
    -- buffer. This can be replaced by a sliding/ring buffer using Data.Array.
    -- That will allow us more efficient random back and forth movement.
    go !_ st backBuf !pst = do
        r <- step defState st
        case r of
            D.Yield (Array contents start end) s ->
                gobuf SPEC s backBuf
                    (Tuple' end contents) start pst
            D.Skip s -> go SPEC s backBuf pst
            D.Stop -> do
                b <- extract pst
                return (b, D.nil)

    -- Use strictness on "cur" to keep it unboxed
    gobuf !_ s backBuf (Tuple' end _) !cur !pst
        | cur == end = do
            go SPEC s backBuf pst
    gobuf !_ s backBuf fp@(Tuple' end contents) !cur !pst = do
        x <- liftIO $ peekByteIndex contents cur
        pRes <- pstep pst x
        let next = INDEX_NEXT(cur,a)
        case pRes of
            PR.Partial 0 pst1 ->
                 gobuf SPEC s (List []) fp next pst1
            PR.Partial n pst1 -> do
                assert (n <= Prelude.length (x:getList backBuf)) (return ())
                let src0 = Prelude.take n (x:getList backBuf)
                    arr0 = A.fromListN n (Prelude.reverse src0)
                    arr1 = Array contents next end
                    src = arr0 <> arr1
                let !(Array cont1 start end1) = src
                    fp1 = Tuple' end1 cont1
                gobuf SPEC s (List []) fp1 start pst1
            PR.Continue 0 pst1 ->
                gobuf SPEC s (List (x:getList backBuf)) fp next pst1
            PR.Continue n pst1 -> do
                assert (n <= Prelude.length (x:getList backBuf)) (return ())
                let (src0, buf1) = splitAt n (x:getList backBuf)
                    arr0 = A.fromListN n (Prelude.reverse src0)
                    arr1 = Array contents next end
                    src = arr0 <> arr1
                let !(Array cont1 start end1) = src
                    fp1 = Tuple' end1 cont1
                gobuf SPEC s (List buf1) fp1 start pst1
            PR.Done 0 b -> do
                let arr = Array contents next end
                return (b, D.cons arr (D.Stream step s))
            PR.Done n b -> do
                assert (n <= Prelude.length (x:getList backBuf)) (return ())
                let src0 = Prelude.take n (x:getList backBuf)
                    -- XXX create the array in reverse instead
                    arr0 = A.fromListN n (Prelude.reverse src0)
                    arr1 = Array contents next end
                    -- XXX Use StreamK to avoid adding arbitrary layers of
                    -- constructors every time.
                    str = D.cons arr0 (D.cons arr1 (D.Stream step s))
                return (b, str)
            PR.SError err -> throwM $ ParseError err

-- | Parse an array stream using the supplied 'Parser'.  Returns the parse
-- result and the unconsumed stream. Throws 'ParseError' if the parse fails.
--
-- 'parseBreak' is an alternative to this function which allows composing the
-- parser using the parser Monad.
--
-- We can compare perf and remove this one or define it in terms of that.
--
-- /Internal/
--
{-# INLINE_NORMAL parseBreakChunksK #-}
parseBreakChunksK ::
       forall m a b. (MonadIO m, Unbox a)
    => Parser a m b
    -> StreamK m (Array a)
    -> m (Either ParseError b, StreamK m (Array a))
parseBreakChunksK (Parser pstep initial extract) stream = do
    res <- initial
    case res of
        IPartial s -> go s stream []
        IDone b -> return (Right b, stream)
        IError err -> return (Left (ParseError err), stream)

    where

    -- "backBuf" contains last few items in the stream that we may have to
    -- backtrack to.
    --
    -- XXX currently we are using a dumb list based approach for backtracking
    -- buffer. This can be replaced by a sliding/ring buffer using Data.Array.
    -- That will allow us more efficient random back and forth movement.
    go !pst st backBuf = do
        let stop = goStop pst backBuf -- (, K.nil) <$> extract pst
            single a = yieldk a StreamK.nil
            yieldk arr r = goArray pst backBuf r arr
         in StreamK.foldStream defState yieldk single stop st

    -- Use strictness on "cur" to keep it unboxed
    goArray !pst backBuf st (Array _ cur end) | cur == end = go pst st backBuf
    goArray !pst backBuf st (Array contents cur end) = do
        x <- liftIO $ peekAt cur contents
        pRes <- pstep pst x
        let next = INDEX_NEXT(cur,a)
        case pRes of
            Parser.SPartial 1 s ->
                 goArray s [] st (Array contents next end)
            Parser.SPartial m s -> do
                assertM(m <= 1)
                let n = 1 - m
                assert (n <= Prelude.length (x:backBuf)) (return ())
                let src0 = Prelude.take n (x:backBuf)
                    arr0 = fromListN n (Prelude.reverse src0)
                    arr1 = Array contents next end
                    src = arr0 <> arr1
                goArray s [] st src
            Parser.SContinue 1 s ->
                goArray s (x:backBuf) st (Array contents next end)
            Parser.SContinue m s -> do
                assertM(m <= 1)
                let n = 1 - m
                assert (n <= Prelude.length (x:backBuf)) (return ())
                let (src0, buf1) = Prelude.splitAt n (x:backBuf)
                    arr0 = fromListN n (Prelude.reverse src0)
                    arr1 = Array contents next end
                    src = arr0 <> arr1
                goArray s buf1 st src
            Parser.SDone 1 b -> do
                let arr = Array contents next end
                return (Right b, StreamK.cons arr st)
            Parser.SDone m b -> do
                assertM(m <= 1)
                let n = 1 - m
                assert (n <= Prelude.length (x:backBuf)) (return ())
                let src0 = Prelude.take n (x:backBuf)
                    -- XXX Use fromListRevN once implemented
                    -- arr0 = A.fromListRevN n src0
                    arr0 = fromListN n (Prelude.reverse src0)
                    arr1 = Array contents next end
                    str = StreamK.cons arr0 (StreamK.cons arr1 st)
                return (Right b, str)
            Parser.SError err -> do
                let n = Prelude.length backBuf
                    arr0 = fromListN n (Prelude.reverse backBuf)
                    arr1 = Array contents cur end
                    str = StreamK.cons arr0 (StreamK.cons arr1 st)
                return (Left (ParseError err), str)

    -- This is a simplified goArray
    goExtract !pst backBuf (Array _ cur end)
        | cur == end = goStop pst backBuf
    goExtract !pst backBuf (Array contents cur end) = do
        x <- liftIO $ peekAt cur contents
        pRes <- pstep pst x
        let next = INDEX_NEXT(cur,a)
        case pRes of
            Parser.SPartial 0 s ->
                 goExtract s [] (Array contents next end)
            Parser.SPartial m s -> do
                assertM(m <= 0)
                let n = negate m
                assert (n <= Prelude.length (x:backBuf)) (return ())
                let src0 = Prelude.take n (x:backBuf)
                    arr0 = fromListN n (Prelude.reverse src0)
                    arr1 = Array contents next end
                    src = arr0 <> arr1
                goExtract s [] src
            Parser.SContinue 0 s ->
                goExtract s backBuf (Array contents next end)
            Parser.SContinue m s -> do
                assertM(m <= 0)
                let n = negate m
                assert (n <= Prelude.length (x:backBuf)) (return ())
                let (src0, buf1) = Prelude.splitAt n (x:backBuf)
                    arr0 = fromListN n (Prelude.reverse src0)
                    arr1 = Array contents next end
                    src = arr0 <> arr1
                goExtract s buf1 src
            Parser.SDone 0 b -> do
                let arr = Array contents next end
                return (Right b, StreamK.fromPure arr)
            Parser.SDone m b -> do
                assertM(m <= 0)
                let n = negate m
                assert (n <= Prelude.length backBuf) (return ())
                let src0 = Prelude.take n (x:backBuf)
                    -- XXX Use fromListRevN once implemented
                    -- arr0 = A.fromListRevN n src0
                    arr0 = fromListN n (Prelude.reverse src0)
                    arr1 = Array contents next end
                    str = StreamK.cons arr0 (StreamK.fromPure arr1)
                return (Right b, str)
            Parser.SError err -> do
                let n = Prelude.length backBuf
                    arr0 = fromListN n (Prelude.reverse backBuf)
                    arr1 = Array contents cur end
                    str = StreamK.cons arr0 (StreamK.fromPure arr1)
                return (Left (ParseError err), str)

    -- This is a simplified goExtract
    {-# INLINE goStop #-}
    goStop !pst backBuf = do
        pRes <- extract pst
        case pRes of
            Parser.SPartial _ _ -> error "Bug: parseBreak: Partial in extract"
            Parser.SContinue 0 s ->
                goStop s backBuf
            Parser.SContinue m s -> do
                assertM(m <= 0)
                let n = negate m
                assert (n <= Prelude.length backBuf) (return ())
                let (src0, buf1) = Prelude.splitAt n backBuf
                    arr = fromListN n (Prelude.reverse src0)
                goExtract s buf1 arr
            Parser.SDone 0 b ->
                return (Right b, StreamK.nil)
            Parser.SDone m b -> do
                assertM(m <= 0)
                let n = negate m
                assert (n <= Prelude.length backBuf) (return ())
                let src0 = Prelude.take n backBuf
                    -- XXX Use fromListRevN once implemented
                    -- arr0 = A.fromListRevN n src0
                    arr0 = fromListN n (Prelude.reverse src0)
                return (Right b, StreamK.fromPure arr0)
            Parser.SError err -> do
                let n = Prelude.length backBuf
                    arr0 = fromListN n (Prelude.reverse backBuf)
                return (Left (ParseError err), StreamK.fromPure arr0)
-}

-- | Run a 'ParserK' over a 'StreamK' of Arrays and return the parse result and
-- the remaining Stream.
{-# INLINE parseBreak #-}
parseBreak
    :: (Monad m, Unbox a)
    => ParserK (Array a) m b
    -> StreamK m (Array a)
    -> m (Either ParseError b, StreamK m (Array a))
parseBreak :: forall (m :: * -> *) a b.
(Monad m, Unbox a) =>
ParserK (Array a) m b
-> StreamK m (Array a)
-> m (Either ParseError b, StreamK m (Array a))
parseBreak = ParserK (Array a) m b
-> StreamK m (Array a)
-> m (Either ParseError b, StreamK m (Array a))
forall (m :: * -> *) a b.
(Monad m, Unbox a) =>
ParserK (Array a) m b
-> StreamK m (Array a)
-> m (Either ParseError b, StreamK m (Array a))
Drivers.parseBreakChunks

-- | Like 'parseBreak' but includes stream position information in the error
-- messages.
--
{-# INLINE parseBreakPos #-}
parseBreakPos
    :: (Monad m, Unbox a)
    => ParserK (Array a) m b
    -> StreamK m (Array a)
    -> m (Either ParseErrorPos b, StreamK m (Array a))
parseBreakPos :: forall (m :: * -> *) a b.
(Monad m, Unbox a) =>
ParserK (Array a) m b
-> StreamK m (Array a)
-> m (Either ParseErrorPos b, StreamK m (Array a))
parseBreakPos = ParserK (Array a) m b
-> StreamK m (Array a)
-> m (Either ParseErrorPos b, StreamK m (Array a))
forall (m :: * -> *) a b.
(Monad m, Unbox a) =>
ParserK (Array a) m b
-> StreamK m (Array a)
-> m (Either ParseErrorPos b, StreamK m (Array a))
Drivers.parseBreakChunksPos

{-# INLINE parse #-}
parse :: (Monad m, Unbox a) =>
    ParserK (Array a) m b -> StreamK m (Array a) -> m (Either ParseError b)
parse :: forall (m :: * -> *) a b.
(Monad m, Unbox a) =>
ParserK (Array a) m b
-> StreamK m (Array a) -> m (Either ParseError b)
parse ParserK (Array a) m b
f = ((Either ParseError b, StreamK m (Array a)) -> Either ParseError b)
-> m (Either ParseError b, StreamK m (Array a))
-> m (Either ParseError b)
forall a b. (a -> b) -> m a -> m b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Either ParseError b, StreamK m (Array a)) -> Either ParseError b
forall a b. (a, b) -> a
fst (m (Either ParseError b, StreamK m (Array a))
 -> m (Either ParseError b))
-> (StreamK m (Array a)
    -> m (Either ParseError b, StreamK m (Array a)))
-> StreamK m (Array a)
-> m (Either ParseError b)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ParserK (Array a) m b
-> StreamK m (Array a)
-> m (Either ParseError b, StreamK m (Array a))
forall (m :: * -> *) a b.
(Monad m, Unbox a) =>
ParserK (Array a) m b
-> StreamK m (Array a)
-> m (Either ParseError b, StreamK m (Array a))
parseBreak ParserK (Array a) m b
f

-- | Like 'parse' but includes stream position information in the error
-- messages.
--
{-# INLINE parsePos #-}
parsePos :: (Monad m, Unbox a) =>
    ParserK (Array a) m b -> StreamK m (Array a) -> m (Either ParseErrorPos b)
parsePos :: forall (m :: * -> *) a b.
(Monad m, Unbox a) =>
ParserK (Array a) m b
-> StreamK m (Array a) -> m (Either ParseErrorPos b)
parsePos ParserK (Array a) m b
f = ((Either ParseErrorPos b, StreamK m (Array a))
 -> Either ParseErrorPos b)
-> m (Either ParseErrorPos b, StreamK m (Array a))
-> m (Either ParseErrorPos b)
forall a b. (a -> b) -> m a -> m b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Either ParseErrorPos b, StreamK m (Array a))
-> Either ParseErrorPos b
forall a b. (a, b) -> a
fst (m (Either ParseErrorPos b, StreamK m (Array a))
 -> m (Either ParseErrorPos b))
-> (StreamK m (Array a)
    -> m (Either ParseErrorPos b, StreamK m (Array a)))
-> StreamK m (Array a)
-> m (Either ParseErrorPos b)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ParserK (Array a) m b
-> StreamK m (Array a)
-> m (Either ParseErrorPos b, StreamK m (Array a))
forall (m :: * -> *) a b.
(Monad m, Unbox a) =>
ParserK (Array a) m b
-> StreamK m (Array a)
-> m (Either ParseErrorPos b, StreamK m (Array a))
parseBreakPos ParserK (Array a) m b
f

-------------------------------------------------------------------------------
-- Convert ParserD to ParserK
-------------------------------------------------------------------------------

{-# INLINE adaptCWith #-}
adaptCWith
    :: forall m a s b r. (Monad m, Unbox a)
    => (s -> a -> m (ParserD.Step s b))
    -> m (ParserD.Initial s b)
    -> (s -> m (ParserD.Final s b))
    -> (ParseResult b -> Int -> Input (Array a) -> m (Step (Array a) m r))
    -> Int
    -> Int
    -> Input (Array a)
    -> m (Step (Array a) m r)
adaptCWith :: forall (m :: * -> *) a s b r.
(Monad m, Unbox a) =>
(s -> a -> m (Step s b))
-> m (Initial s b)
-> (s -> m (Final s b))
-> (ParseResult b
    -> Int -> Input (Array a) -> m (Step (Array a) m r))
-> Int
-> Int
-> Input (Array a)
-> m (Step (Array a) m r)
adaptCWith s -> a -> m (Step s b)
pstep m (Initial s b)
initial s -> m (Final s b)
extract ParseResult b -> Int -> Input (Array a) -> m (Step (Array a) m r)
cont !Int
offset0 !Int
usedCount !Input (Array a)
input = do
    Initial s b
res <- m (Initial s b)
initial
    case Initial s b
res of
        ParserD.IPartial s
pst -> do
            case Input (Array a)
input of
                Chunk Array a
arr -> Int -> Int -> s -> Array a -> m (Step (Array a) m r)
parseContChunk Int
usedCount Int
offset0 s
pst Array a
arr
                Input (Array a)
None -> Int -> s -> m (Step (Array a) m r)
parseContNothing Int
usedCount s
pst
        ParserD.IDone b
b -> ParseResult b -> Int -> Input (Array a) -> m (Step (Array a) m r)
cont (Int -> b -> ParseResult b
forall b. Int -> b -> ParseResult b
Success Int
offset0 b
b) Int
usedCount Input (Array a)
input
        ParserD.IError String
err -> ParseResult b -> Int -> Input (Array a) -> m (Step (Array a) m r)
cont (Int -> String -> ParseResult b
forall b. Int -> String -> ParseResult b
Failure Int
offset0 String
err) Int
usedCount Input (Array a)
input

    where

    -- XXX We can maintain an absolute position instead of relative that will
    -- help in reporting of error location in the stream.
    {-# NOINLINE parseContChunk #-}
    parseContChunk :: Int -> Int -> s -> Array a -> m (Step (Array a) m r)
parseContChunk !Int
count !Int
offset !s
state arr :: Array a
arr@(Array MutByteArray
contents Int
start Int
end) = do
         if Int
offset Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
0
         then SPEC -> Int -> s -> m (Step (Array a) m r)
go SPEC
SPEC (Int
start Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
offset Int -> Int -> Int
forall a. Num a => a -> a -> a
* SIZE_OF(a)) state
         else Step (Array a) m r -> m (Step (Array a) m r)
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (Step (Array a) m r -> m (Step (Array a) m r))
-> Step (Array a) m r -> m (Step (Array a) m r)
forall a b. (a -> b) -> a -> b
$ Int
-> (Input (Array a) -> m (Step (Array a) m r))
-> Step (Array a) m r
forall a (m :: * -> *) r. Int -> StepParser a m r -> Step a m r
Continue Int
offset (Int -> s -> Input (Array a) -> m (Step (Array a) m r)
parseCont Int
count s
state)

        where

        {-# INLINE onDone #-}
        onDone :: Int -> b -> m (Step (Array a) m r)
onDone Int
n b
b =
            Bool -> m (Step (Array a) m r) -> m (Step (Array a) m r)
forall a. HasCallStack => Bool -> a -> a
assert (Int
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Array a -> Int
forall a. Unbox a => Array a -> Int
length Array a
arr)
                (ParseResult b -> Int -> Input (Array a) -> m (Step (Array a) m r)
cont (Int -> b -> ParseResult b
forall b. Int -> b -> ParseResult b
Success Int
n b
b) (Int
count Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
offset) (Array a -> Input (Array a)
forall a. a -> Input a
Chunk Array a
arr))

        {-# INLINE callParseCont #-}
        callParseCont :: (Int -> (Input (Array a) -> m (Step (Array a) m r)) -> a)
-> Int -> s -> m a
callParseCont Int -> (Input (Array a) -> m (Step (Array a) m r)) -> a
constr Int
n s
pst1 =
            Bool -> m a -> m a
forall a. HasCallStack => Bool -> a -> a
assert (Int
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
0 Bool -> Bool -> Bool
|| Int
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Array a -> Int
forall a. Unbox a => Array a -> Int
length Array a
arr)
                (a -> m a
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (a -> m a) -> a -> m a
forall a b. (a -> b) -> a -> b
$ Int -> (Input (Array a) -> m (Step (Array a) m r)) -> a
constr Int
n (Int -> s -> Input (Array a) -> m (Step (Array a) m r)
parseCont (Int
count Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
offset) s
pst1))

        {-# INLINE onPartial #-}
        onPartial :: Int -> s -> m (Step (Array a) m r)
onPartial = (Int
 -> (Input (Array a) -> m (Step (Array a) m r))
 -> Step (Array a) m r)
-> Int -> s -> m (Step (Array a) m r)
forall {m :: * -> *} {a}.
Monad m =>
(Int -> (Input (Array a) -> m (Step (Array a) m r)) -> a)
-> Int -> s -> m a
callParseCont Int
-> (Input (Array a) -> m (Step (Array a) m r))
-> Step (Array a) m r
forall a (m :: * -> *) r. Int -> StepParser a m r -> Step a m r
Partial

        {-# INLINE onContinue #-}
        onContinue :: Int -> s -> m (Step (Array a) m r)
onContinue = (Int
 -> (Input (Array a) -> m (Step (Array a) m r))
 -> Step (Array a) m r)
-> Int -> s -> m (Step (Array a) m r)
forall {m :: * -> *} {a}.
Monad m =>
(Int -> (Input (Array a) -> m (Step (Array a) m r)) -> a)
-> Int -> s -> m a
callParseCont Int
-> (Input (Array a) -> m (Step (Array a) m r))
-> Step (Array a) m r
forall a (m :: * -> *) r. Int -> StepParser a m r -> Step a m r
Continue

        {-# INLINE onError #-}
        onError :: Int -> String -> m (Step (Array a) m r)
onError Int
n String
err =
            ParseResult b -> Int -> Input (Array a) -> m (Step (Array a) m r)
cont (Int -> String -> ParseResult b
forall b. Int -> String -> ParseResult b
Failure Int
n String
err) (Int
count Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
offset) (Array a -> Input (Array a)
forall a. a -> Input a
Chunk Array a
arr)

        {-# INLINE onBack #-}
        onBack :: Int
-> Int
-> (Int -> s -> m (Step (Array a) m r))
-> s
-> m (Step (Array a) m r)
onBack Int
offset1 Int
elemSize Int -> s -> m (Step (Array a) m r)
constr s
pst = do
            let pos :: Int
pos = Int
offset1 Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
start
             in if Int
pos Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
0
                then SPEC -> Int -> s -> m (Step (Array a) m r)
go SPEC
SPEC Int
offset1 s
pst
                else Int -> s -> m (Step (Array a) m r)
constr (Int
pos Int -> Int -> Int
forall a. Integral a => a -> a -> a
`div` Int
elemSize) s
pst

        -- Note: div may be expensive but the alternative is to maintain an element
        -- offset in addition to a byte offset or just the element offset and use
        -- multiplication to get the byte offset every time, both these options
        -- turned out to be more expensive than using div.
        go :: SPEC -> Int -> s -> m (Step (Array a) m r)
go !SPEC
_ !Int
cur !s
pst | Int
cur Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
end =
            Int -> s -> m (Step (Array a) m r)
onContinue ((Int
end Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
start) Int -> Int -> Int
forall a. Integral a => a -> a -> a
`div` SIZE_OF(a))  pst
        go !SPEC
_ !Int
cur !s
pst = do
            let !x :: a
x = IO a -> a
forall a. IO a -> a
unsafeInlineIO (IO a -> a) -> IO a -> a
forall a b. (a -> b) -> a -> b
$ Int -> MutByteArray -> IO a
forall a. Unbox a => Int -> MutByteArray -> IO a
peekAt Int
cur MutByteArray
contents
            Step s b
pRes <- s -> a -> m (Step s b)
pstep s
pst a
x
            let elemSize :: Int
elemSize = SIZE_OF(a)
                next :: Int
next = INDEX_NEXT(cur,a)
                move :: Int -> Int
move Int
n = Int
cur Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
elemSize
                curOff :: Int
curOff = (Int
cur Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
start) Int -> Int -> Int
forall a. Integral a => a -> a -> a
`div` Int
elemSize
                nextOff :: Int
nextOff = (Int
next Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
start) Int -> Int -> Int
forall a. Integral a => a -> a -> a
`div` Int
elemSize
            case Step s b
pRes of
                ParserD.SDone Int
1 b
b ->
                    Int -> b -> m (Step (Array a) m r)
onDone Int
nextOff b
b
                ParserD.SDone Int
0 b
b ->
                    Int -> b -> m (Step (Array a) m r)
onDone Int
curOff b
b
                ParserD.SDone Int
n b
b ->
                    Int -> b -> m (Step (Array a) m r)
onDone ((Int -> Int
move Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
start) Int -> Int -> Int
forall a. Integral a => a -> a -> a
`div` Int
elemSize) b
b
                ParserD.SPartial Int
1 s
pst1 ->
                    SPEC -> Int -> s -> m (Step (Array a) m r)
go SPEC
SPEC Int
next s
pst1
                ParserD.SPartial Int
0 s
pst1 ->
                    SPEC -> Int -> s -> m (Step (Array a) m r)
go SPEC
SPEC Int
cur s
pst1
                ParserD.SPartial Int
n s
pst1 ->
                    Int
-> Int
-> (Int -> s -> m (Step (Array a) m r))
-> s
-> m (Step (Array a) m r)
onBack (Int -> Int
move Int
n) Int
elemSize Int -> s -> m (Step (Array a) m r)
onPartial s
pst1
                ParserD.SContinue Int
1 s
pst1 ->
                    SPEC -> Int -> s -> m (Step (Array a) m r)
go SPEC
SPEC Int
next s
pst1
                ParserD.SContinue Int
0 s
pst1 ->
                    SPEC -> Int -> s -> m (Step (Array a) m r)
go SPEC
SPEC Int
cur s
pst1
                ParserD.SContinue Int
n s
pst1 ->
                    Int
-> Int
-> (Int -> s -> m (Step (Array a) m r))
-> s
-> m (Step (Array a) m r)
onBack (Int -> Int
move Int
n) Int
elemSize Int -> s -> m (Step (Array a) m r)
onContinue s
pst1
                ParserD.SError String
err ->
                    Int -> String -> m (Step (Array a) m r)
onError Int
curOff String
err

    {-# NOINLINE parseContNothing #-}
    parseContNothing :: Int -> s -> m (Step (Array a) m r)
parseContNothing !Int
count !s
pst = do
        Final s b
r <- s -> m (Final s b)
extract s
pst
        case Final s b
r of
            ParserD.FDone Int
n b
b ->
                Bool -> m (Step (Array a) m r) -> m (Step (Array a) m r)
forall a. HasCallStack => Bool -> a -> a
assert (Int
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
0) (ParseResult b -> Int -> Input (Array a) -> m (Step (Array a) m r)
cont (Int -> b -> ParseResult b
forall b. Int -> b -> ParseResult b
Success Int
n b
b) (Int
count Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
n) Input (Array a)
forall a. Input a
None)
            ParserD.FContinue Int
n s
pst1 ->
                Bool -> m (Step (Array a) m r) -> m (Step (Array a) m r)
forall a. HasCallStack => Bool -> a -> a
assert (Int
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
0)
                    (Step (Array a) m r -> m (Step (Array a) m r)
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (Step (Array a) m r -> m (Step (Array a) m r))
-> Step (Array a) m r -> m (Step (Array a) m r)
forall a b. (a -> b) -> a -> b
$ Int
-> (Input (Array a) -> m (Step (Array a) m r))
-> Step (Array a) m r
forall a (m :: * -> *) r. Int -> StepParser a m r -> Step a m r
Continue Int
n (Int -> s -> Input (Array a) -> m (Step (Array a) m r)
parseCont (Int
count Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
n) s
pst1))
            ParserD.FError String
err ->
                -- XXX It is called only when there is no input arr. So using 0
                -- as the position is correct?
                ParseResult b -> Int -> Input (Array a) -> m (Step (Array a) m r)
cont (Int -> String -> ParseResult b
forall b. Int -> String -> ParseResult b
Failure Int
0 String
err) Int
count Input (Array a)
forall a. Input a
None

    -- XXX Maybe we can use two separate continuations instead of using
    -- Just/Nothing cases here. That may help in avoiding the parseContJust
    -- function call.
    {-# INLINE parseCont #-}
    parseCont :: Int -> s -> Input (Array a) -> m (Step (Array a) m r)
parseCont !Int
cnt !s
pst (Chunk Array a
arr) = Int -> Int -> s -> Array a -> m (Step (Array a) m r)
parseContChunk Int
cnt Int
0 s
pst Array a
arr
    parseCont !Int
cnt !s
pst Input (Array a)
None = Int -> s -> m (Step (Array a) m r)
parseContNothing Int
cnt s
pst

-- | Convert a 'Parser' to 'ParserK' working on an Array stream.
--
-- /Pre-release/
--
{-# INLINE_LATE toParserK #-}
toParserK :: (Monad m, Unbox a) => ParserD.Parser a m b -> ParserK (Array a) m b
toParserK :: forall (m :: * -> *) a b.
(Monad m, Unbox a) =>
Parser a m b -> ParserK (Array a) m b
toParserK (ParserD.Parser s -> a -> m (Step s b)
step m (Initial s b)
initial s -> m (Final s b)
extract) =
    (forall r.
 (ParseResult b -> Int -> StepParser (Array a) m r)
 -> Int -> Int -> StepParser (Array a) m r)
-> ParserK (Array a) m b
forall a (m :: * -> *) b.
(forall r.
 (ParseResult b -> Int -> StepParser a m r)
 -> Int -> Int -> StepParser a m r)
-> ParserK a m b
ParserK.MkParser ((forall r.
  (ParseResult b -> Int -> StepParser (Array a) m r)
  -> Int -> Int -> StepParser (Array a) m r)
 -> ParserK (Array a) m b)
-> (forall r.
    (ParseResult b -> Int -> StepParser (Array a) m r)
    -> Int -> Int -> StepParser (Array a) m r)
-> ParserK (Array a) m b
forall a b. (a -> b) -> a -> b
$ (s -> a -> m (Step s b))
-> m (Initial s b)
-> (s -> m (Final s b))
-> (ParseResult b
    -> Int -> Input (Array a) -> m (Step (Array a) m r))
-> Int
-> Int
-> Input (Array a)
-> m (Step (Array a) m r)
forall (m :: * -> *) a s b r.
(Monad m, Unbox a) =>
(s -> a -> m (Step s b))
-> m (Initial s b)
-> (s -> m (Final s b))
-> (ParseResult b
    -> Int -> Input (Array a) -> m (Step (Array a) m r))
-> Int
-> Int
-> Input (Array a)
-> m (Step (Array a) m r)
adaptCWith s -> a -> m (Step s b)
step m (Initial s b)
initial s -> m (Final s b)
extract