{-# LANGUAGE CPP #-}
-- |
-- Module      : Streamly.Internal.Data.Array.Type
-- Copyright   : (c) 2020 Composewell Technologies
--
-- License     : BSD3-3-Clause
-- Maintainer  : streamly@composewell.com
-- Stability   : experimental
-- Portability : GHC
--
-- See notes in "Streamly.Internal.Data.MutArray.Type"
--
module Streamly.Internal.Data.Array.Type
    (
    -- ** Type
    -- $arrayNotes
      Array (..)
    , asPtrUnsafe
    , nil

    -- ** Freezing and Thawing
    , unsafeFreeze
    , unsafeFreezeWithShrink
    , unsafeThaw

    -- ** Pinning and Unpinning
    , pin
    , unpin
    , isPinned

    -- ** Construction
    , splice

    , fromList
    , pinnedFromList
    , fromListN
    , pinnedFromListN
    , fromListRev
    , fromListRevN
    , fromStreamDN
    , fromStreamD
    , fromPureStream
    , fromByteStr#

    -- ** Split
    , breakOn

    -- ** Cloning arrays
    , clone
    , pinnedClone

    -- ** Elimination
    , unsafeIndexIO
    , getIndexUnsafe
    , byteLength
    , length

    , foldl'
    , foldr
    , splitAt

    , toStreamD
    , toStreamDRev
    , toStreamK
    , toStreamKRev
    , toStream
    , toStreamRev
    , read
    , readRev
    , readerRev
    , toList

    -- ** Folds
    , writeWith
    , writeN
    , pinnedWriteN
    , writeNUnsafe
    , pinnedWriteNUnsafe
    , MA.ArrayUnsafe (..)
    , pinnedWriteNAligned
    , write
    , pinnedWrite
    , unsafeMakePure

    -- ** Streams of arrays
    , chunksOf
    , pinnedChunksOf
    , bufferChunks
    , flattenArrays
    , flattenArraysRev

    -- ** Deprecated
    , unsafeIndex
    )
where

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

import Control.Exception (assert)
import Control.Monad (replicateM)
import Control.Monad.IO.Class (MonadIO(..))
import Data.Functor.Identity (Identity(..))
import Data.Proxy (Proxy(..))
import Data.Word (Word8)
import GHC.Base (build)
import GHC.Exts (IsList, IsString(..), Addr#)

import GHC.IO (unsafePerformIO)
import GHC.Ptr (Ptr(..))
import Streamly.Internal.Data.MutArray.Type (MutArray(..), MutByteArray)
import Streamly.Internal.Data.Fold.Type (Fold(..))
import Streamly.Internal.Data.Stream.Type (Stream)
import Streamly.Internal.Data.Unbox (Unbox(..))
import Streamly.Internal.Data.Unfold.Type (Unfold(..))
import Text.Read (readPrec)

import Prelude hiding (Foldable(..), read, unlines, splitAt)

import qualified GHC.Exts as Exts
import qualified Streamly.Internal.Data.MutArray.Type as MA
import qualified Streamly.Internal.Data.Stream.Type as D
import qualified Streamly.Internal.Data.Stream.Generate as D
import qualified Streamly.Internal.Data.StreamK.Type as K
import qualified Streamly.Internal.Data.MutByteArray.Type as Unboxed
import qualified Streamly.Internal.Data.Unfold.Type as Unfold
import qualified Text.ParserCombinators.ReadPrec as ReadPrec

import Streamly.Internal.System.IO (unsafeInlineIO, defaultChunkSize)

#include "DocTestDataArray.hs"

-------------------------------------------------------------------------------
-- Notes
-------------------------------------------------------------------------------

-- IMPORTANT:

-- We need to be careful while using unsafePerformIO when array creation is
-- involved.
--
-- * We need to make sure the unsafe IO line does not float out of the binding.
-- * The order of the IO actions should be sane. For example, `touch` after `f`.
--
-- Assume the unsafe IO action floats up. If it makes sense given this
-- assumption, it's probably OK to use usafe IO.
--
-- A general approach should be never to use unsafe IO where Array creation is
-- involved or touch is involved.

-------------------------------------------------------------------------------
-- Array Data Type
-------------------------------------------------------------------------------

-- $arrayNotes
--
-- We can use an 'Unbox' constraint in the Array type and the constraint can
-- be automatically provided to a function that pattern matches on the Array
-- type. However, it has huge performance cost, so we do not use it.
-- Investigate a GHC improvement possiblity.
--
data Array a =
#ifdef DEVBUILD
    Unbox a =>
#endif
    -- All offsets are in terms of bytes from the start of arraycontents
    Array
    { forall a. Array a -> MutByteArray
arrContents :: {-# UNPACK #-} !MutByteArray
    , forall a. Array a -> Int
arrStart :: {-# UNPACK #-} !Int -- offset
    , forall a. Array a -> Int
arrEnd   :: {-# UNPACK #-} !Int   -- offset + len
    }

-------------------------------------------------------------------------------
-- Utility functions
-------------------------------------------------------------------------------

-- | Use an @Array a@ as @Ptr a@.
--
-- See 'MA.asPtrUnsafe' in the Mutable array module for more details.
--
-- /Unsafe/
--
-- /Pre-release/
--
{-# INLINE asPtrUnsafe #-}
asPtrUnsafe :: MonadIO m => Array a -> (Ptr a -> m b) -> m b
asPtrUnsafe :: forall (m :: * -> *) a b.
MonadIO m =>
Array a -> (Ptr a -> m b) -> m b
asPtrUnsafe Array a
arr = forall (m :: * -> *) a b.
MonadIO m =>
MutArray a -> (Ptr a -> m b) -> m b
MA.asPtrUnsafe (forall a. Array a -> MutArray a
unsafeThaw Array a
arr)

-------------------------------------------------------------------------------
-- Freezing and Thawing
-------------------------------------------------------------------------------

-- XXX For debugging we can track slices/references through a weak IORef.  Then
-- trigger a GC after freeze/thaw and assert that there are no references
-- remaining.

-- | Makes an immutable array using the underlying memory of the mutable
-- array.
--
-- Please make sure that there are no other references to the mutable array
-- lying around, so that it is never used after freezing it using
-- /unsafeFreeze/.  If the underlying array is mutated, the immutable promise
-- is lost.
--
-- /Pre-release/
{-# INLINE unsafeFreeze #-}
unsafeFreeze :: MutArray a -> Array a
unsafeFreeze :: forall a. MutArray a -> Array a
unsafeFreeze (MutArray MutByteArray
ac Int
as Int
ae Int
_) = forall a. MutByteArray -> Int -> Int -> Array a
Array MutByteArray
ac Int
as Int
ae

-- | Similar to 'unsafeFreeze' but uses 'MA.rightSize' on the mutable array
-- first.
{-# INLINE unsafeFreezeWithShrink #-}
unsafeFreezeWithShrink :: Unbox a => MutArray a -> Array a
unsafeFreezeWithShrink :: forall a. Unbox a => MutArray a -> Array a
unsafeFreezeWithShrink MutArray a
arr = forall a. IO a -> a
unsafePerformIO forall a b. (a -> b) -> a -> b
$ do
  MutArray MutByteArray
ac Int
as Int
ae Int
_ <- forall (m :: * -> *) a.
(MonadIO m, Unbox a) =>
MutArray a -> m (MutArray a)
MA.rightSize MutArray a
arr
  forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall a. MutByteArray -> Int -> Int -> Array a
Array MutByteArray
ac Int
as Int
ae

-- | Makes a mutable array using the underlying memory of the immutable array.
--
-- Please make sure that there are no other references to the immutable array
-- lying around, so that it is never used after thawing it using /unsafeThaw/.
-- If the resulting array is mutated, any references to the older immutable
-- array are mutated as well.
--
-- /Pre-release/
{-# INLINE unsafeThaw #-}
unsafeThaw :: Array a -> MutArray a
unsafeThaw :: forall a. Array a -> MutArray a
unsafeThaw (Array MutByteArray
ac Int
as Int
ae) = forall a. MutByteArray -> Int -> Int -> Int -> MutArray a
MutArray MutByteArray
ac Int
as Int
ae Int
ae

-------------------------------------------------------------------------------
-- Pinning & Unpinning
-------------------------------------------------------------------------------

-- | Return a copy of the 'Array' in pinned memory if unpinned, else return the
-- original array.
{-# INLINE pin #-}
pin :: Array a -> IO (Array a)
pin :: forall a. Array a -> IO (Array a)
pin = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall a. MutArray a -> Array a
unsafeFreeze forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. MutArray a -> IO (MutArray a)
MA.pin forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Array a -> MutArray a
unsafeThaw

-- | Return a copy of the 'Array' in unpinned memory if pinned, else return the
-- original array.
{-# INLINE unpin #-}
unpin :: Array a -> IO (Array a)
unpin :: forall a. Array a -> IO (Array a)
unpin = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall a. MutArray a -> Array a
unsafeFreeze forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. MutArray a -> IO (MutArray a)
MA.unpin forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Array a -> MutArray a
unsafeThaw

-- | Return 'True' if the array is allocated in pinned memory.
{-# INLINE isPinned #-}
isPinned :: Array a -> Bool
isPinned :: forall a. Array a -> Bool
isPinned = forall a. MutArray a -> Bool
MA.isPinned forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Array a -> MutArray a
unsafeThaw

-------------------------------------------------------------------------------
-- Construction
-------------------------------------------------------------------------------

-- Splice two immutable arrays creating a new array.
{-# INLINE splice #-}
splice :: (MonadIO m, Unbox a) => Array a -> Array a -> m (Array a)
splice :: forall (m :: * -> *) a.
(MonadIO m, Unbox a) =>
Array a -> Array a -> m (Array a)
splice Array a
arr1 Array a
arr2 =
    forall a. MutArray a -> Array a
unsafeFreeze forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (m :: * -> *) a.
(MonadIO m, Unbox a) =>
MutArray a -> MutArray a -> m (MutArray a)
MA.splice (forall a. Array a -> MutArray a
unsafeThaw Array a
arr1) (forall a. Array a -> MutArray a
unsafeThaw Array a
arr2)

-- | Create an 'Array' from the first N elements of a list. The array is
-- allocated to size N, if the list terminates before N elements then the
-- array may hold less than N elements.
--
{-# INLINABLE fromListN #-}
fromListN :: Unbox a => Int -> [a] -> Array a
fromListN :: forall a. Unbox a => Int -> [a] -> Array a
fromListN Int
n [a]
xs = forall a. IO a -> a
unsafePerformIO forall a b. (a -> b) -> a -> b
$ forall a. MutArray a -> Array a
unsafeFreeze forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (m :: * -> *) a.
(MonadIO m, Unbox a) =>
Int -> [a] -> m (MutArray a)
MA.fromListN Int
n [a]
xs

-- | Like 'fromListN' but creates a pinned array.
{-# INLINABLE pinnedFromListN #-}
pinnedFromListN :: Unbox a => Int -> [a] -> Array a
pinnedFromListN :: forall a. Unbox a => Int -> [a] -> Array a
pinnedFromListN Int
n [a]
xs =
    forall a. IO a -> a
unsafePerformIO forall a b. (a -> b) -> a -> b
$ forall a. MutArray a -> Array a
unsafeFreeze forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (m :: * -> *) a.
(MonadIO m, Unbox a) =>
Int -> [a] -> m (MutArray a)
MA.pinnedFromListN Int
n [a]
xs

-- | Create an 'Array' from the first N elements of a list in reverse order.
-- The array is allocated to size N, if the list terminates before N elements
-- then the array may hold less than N elements.
--
-- /Pre-release/
{-# INLINABLE fromListRevN #-}
fromListRevN :: Unbox a => Int -> [a] -> Array a
fromListRevN :: forall a. Unbox a => Int -> [a] -> Array a
fromListRevN Int
n [a]
xs = forall a. IO a -> a
unsafePerformIO forall a b. (a -> b) -> a -> b
$ forall a. MutArray a -> Array a
unsafeFreeze forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (m :: * -> *) a.
(MonadIO m, Unbox a) =>
Int -> [a] -> m (MutArray a)
MA.fromListRevN Int
n [a]
xs

-- | Create an 'Array' from a list. The list must be of finite size.
--
{-# INLINE fromList #-}
fromList :: Unbox a => [a] -> Array a
fromList :: forall a. Unbox a => [a] -> Array a
fromList [a]
xs = forall a. IO a -> a
unsafePerformIO forall a b. (a -> b) -> a -> b
$ forall a. MutArray a -> Array a
unsafeFreeze forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (m :: * -> *) a.
(MonadIO m, Unbox a) =>
[a] -> m (MutArray a)
MA.fromList [a]
xs

-- | Like 'fromList' but creates a pinned array.
{-# INLINE pinnedFromList #-}
pinnedFromList :: Unbox a => [a] -> Array a
pinnedFromList :: forall a. Unbox a => [a] -> Array a
pinnedFromList [a]
xs = forall a. IO a -> a
unsafePerformIO forall a b. (a -> b) -> a -> b
$ forall a. MutArray a -> Array a
unsafeFreeze forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (m :: * -> *) a.
(MonadIO m, Unbox a) =>
[a] -> m (MutArray a)
MA.pinnedFromList [a]
xs

-- | Create an 'Array' from a list in reverse order. The list must be of finite
-- size.
--
-- /Pre-release/
{-# INLINABLE fromListRev #-}
fromListRev :: Unbox a => [a] -> Array a
fromListRev :: forall a. Unbox a => [a] -> Array a
fromListRev [a]
xs = forall a. IO a -> a
unsafePerformIO forall a b. (a -> b) -> a -> b
$ forall a. MutArray a -> Array a
unsafeFreeze forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (m :: * -> *) a.
(MonadIO m, Unbox a) =>
[a] -> m (MutArray a)
MA.fromListRev [a]
xs

{-# INLINE_NORMAL fromStreamDN #-}
fromStreamDN :: forall m a. (MonadIO m, Unbox a)
    => Int -> D.Stream m a -> m (Array a)
fromStreamDN :: forall (m :: * -> *) a.
(MonadIO m, Unbox a) =>
Int -> Stream m a -> m (Array a)
fromStreamDN Int
limit Stream m a
str = forall a. MutArray a -> Array a
unsafeFreeze forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (m :: * -> *) a.
(MonadIO m, Unbox a) =>
Int -> Stream m a -> m (MutArray a)
MA.fromStreamDN Int
limit Stream m a
str

{-# INLINE_NORMAL fromStreamD #-}
fromStreamD :: forall m a. (MonadIO m, Unbox a)
    => D.Stream m a -> m (Array a)
fromStreamD :: forall (m :: * -> *) a.
(MonadIO m, Unbox a) =>
Stream m a -> m (Array a)
fromStreamD Stream m a
str = forall a. MutArray a -> Array a
unsafeFreeze forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (m :: * -> *) a.
(MonadIO m, Unbox a) =>
Stream m a -> m (MutArray a)
MA.fromStreamD Stream m a
str

-------------------------------------------------------------------------------
-- Cloning
-------------------------------------------------------------------------------

{-# INLINE clone #-}
clone ::
    ( MonadIO m
#ifdef DEVBUILD
    , Unbox a
#endif
    )
    => Array a -> m (Array a)
clone :: forall (m :: * -> *) a. MonadIO m => Array a -> m (Array a)
clone = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall a. MutArray a -> Array a
unsafeFreeze forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *) a. MonadIO m => MutArray a -> m (MutArray a)
MA.clone forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Array a -> MutArray a
unsafeThaw

{-# INLINE pinnedClone #-}
pinnedClone ::
    ( MonadIO m
#ifdef DEVBUILD
    , Unbox a
#endif
    )
    => Array a -> m (Array a)
pinnedClone :: forall (m :: * -> *) a. MonadIO m => Array a -> m (Array a)
pinnedClone = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall a. MutArray a -> Array a
unsafeFreeze forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *) a. MonadIO m => MutArray a -> m (MutArray a)
MA.pinnedClone forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Array a -> MutArray a
unsafeThaw

-------------------------------------------------------------------------------
-- Streams of arrays
-------------------------------------------------------------------------------

{-# INLINE bufferChunks #-}
bufferChunks :: (MonadIO m, Unbox a) =>
    D.Stream m a -> m (K.StreamK m (Array a))
bufferChunks :: forall (m :: * -> *) a.
(MonadIO m, Unbox a) =>
Stream m a -> m (StreamK m (Array a))
bufferChunks Stream m a
m = forall (m :: * -> *) a b.
Monad m =>
(a -> b -> b) -> b -> Stream m a -> m b
D.foldr forall a (m :: * -> *). a -> StreamK m a -> StreamK m a
K.cons forall (m :: * -> *) a. StreamK m a
K.nil forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) a.
(MonadIO m, Unbox a) =>
Int -> Stream m a -> Stream m (Array a)
chunksOf Int
defaultChunkSize Stream m a
m

-- | @chunksOf n stream@ groups the elements in the input stream into arrays of
-- @n@ elements each.
--
-- Same as the following but may be more efficient:
--
-- >>> chunksOf n = Stream.foldMany (Array.writeN n)
--
-- /Pre-release/
{-# INLINE_NORMAL chunksOf #-}
chunksOf :: forall m a. (MonadIO m, Unbox a)
    => Int -> D.Stream m a -> D.Stream m (Array a)
chunksOf :: forall (m :: * -> *) a.
(MonadIO m, Unbox a) =>
Int -> Stream m a -> Stream m (Array a)
chunksOf Int
n Stream m a
str = forall (m :: * -> *) a b.
Monad m =>
(a -> b) -> Stream m a -> Stream m b
D.map forall a. MutArray a -> Array a
unsafeFreeze forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) a.
(MonadIO m, Unbox a) =>
Int -> Stream m a -> Stream m (MutArray a)
MA.chunksOf Int
n Stream m a
str

-- | Like 'chunksOf' but creates pinned arrays.
{-# INLINE_NORMAL pinnedChunksOf #-}
pinnedChunksOf :: forall m a. (MonadIO m, Unbox a)
    => Int -> D.Stream m a -> D.Stream m (Array a)
pinnedChunksOf :: forall (m :: * -> *) a.
(MonadIO m, Unbox a) =>
Int -> Stream m a -> Stream m (Array a)
pinnedChunksOf Int
n Stream m a
str = forall (m :: * -> *) a b.
Monad m =>
(a -> b) -> Stream m a -> Stream m b
D.map forall a. MutArray a -> Array a
unsafeFreeze forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) a.
(MonadIO m, Unbox a) =>
Int -> Stream m a -> Stream m (MutArray a)
MA.pinnedChunksOf Int
n Stream m a
str

-- | Use the "read" unfold instead.
--
-- @flattenArrays = unfoldMany read@
--
-- We can try this if there are any fusion issues in the unfold.
--
{-# INLINE_NORMAL flattenArrays #-}
flattenArrays :: forall m a. (MonadIO m, Unbox a)
    => D.Stream m (Array a) -> D.Stream m a
flattenArrays :: forall (m :: * -> *) a.
(MonadIO m, Unbox a) =>
Stream m (Array a) -> Stream m a
flattenArrays = forall (m :: * -> *) a.
(MonadIO m, Unbox a) =>
Stream m (MutArray a) -> Stream m a
MA.flattenArrays forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *) a b.
Monad m =>
(a -> b) -> Stream m a -> Stream m b
D.map forall a. Array a -> MutArray a
unsafeThaw

-- | Use the "readRev" unfold instead.
--
-- @flattenArrays = unfoldMany readRev@
--
-- We can try this if there are any fusion issues in the unfold.
--
{-# INLINE_NORMAL flattenArraysRev #-}
flattenArraysRev :: forall m a. (MonadIO m, Unbox a)
    => D.Stream m (Array a) -> D.Stream m a
flattenArraysRev :: forall (m :: * -> *) a.
(MonadIO m, Unbox a) =>
Stream m (Array a) -> Stream m a
flattenArraysRev = forall (m :: * -> *) a.
(MonadIO m, Unbox a) =>
Stream m (MutArray a) -> Stream m a
MA.flattenArraysRev forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *) a b.
Monad m =>
(a -> b) -> Stream m a -> Stream m b
D.map forall a. Array a -> MutArray a
unsafeThaw

-- Drops the separator byte
{-# INLINE breakOn #-}
breakOn :: MonadIO m
    => Word8 -> Array Word8 -> m (Array Word8, Maybe (Array Word8))
breakOn :: forall (m :: * -> *).
MonadIO m =>
Word8 -> Array Word8 -> m (Array Word8, Maybe (Array Word8))
breakOn Word8
sep Array Word8
arr = do
  (MutArray Word8
a, Maybe (MutArray Word8)
b) <- forall (m :: * -> *).
MonadIO m =>
Word8
-> MutArray Word8 -> m (MutArray Word8, Maybe (MutArray Word8))
MA.breakOn Word8
sep (forall a. Array a -> MutArray a
unsafeThaw Array Word8
arr)
  forall (m :: * -> *) a. Monad m => a -> m a
return (forall a. MutArray a -> Array a
unsafeFreeze MutArray Word8
a, forall a. MutArray a -> Array a
unsafeFreeze forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Maybe (MutArray Word8)
b)

-------------------------------------------------------------------------------
-- Elimination
-------------------------------------------------------------------------------

-- | Return element at the specified index without checking the bounds.
--
-- Unsafe because it does not check the bounds of the array.
{-# INLINE_NORMAL unsafeIndexIO #-}
unsafeIndexIO :: forall a. Unbox a => Int -> Array a -> IO a
unsafeIndexIO :: forall a. Unbox a => Int -> Array a -> IO a
unsafeIndexIO Int
i Array a
arr = forall (m :: * -> *) a.
(MonadIO m, Unbox a) =>
Int -> MutArray a -> m a
MA.getIndexUnsafe Int
i (forall a. Array a -> MutArray a
unsafeThaw Array a
arr)

-- | Return element at the specified index without checking the bounds.
{-# INLINE_NORMAL getIndexUnsafe #-}
getIndexUnsafe :: forall a. Unbox a => Int -> Array a -> a
getIndexUnsafe :: forall a. Unbox a => Int -> Array a -> a
getIndexUnsafe Int
i Array a
arr = let !r :: a
r = forall a. IO a -> a
unsafeInlineIO forall a b. (a -> b) -> a -> b
$ forall a. Unbox a => Int -> Array a -> IO a
unsafeIndexIO Int
i Array a
arr in a
r

{-# DEPRECATED unsafeIndex "Please use 'getIndexUnsafe' instead" #-}
{-# INLINE_NORMAL unsafeIndex #-}
unsafeIndex :: forall a. Unbox a => Int -> Array a -> a
unsafeIndex :: forall a. Unbox a => Int -> Array a -> a
unsafeIndex = forall a. Unbox a => Int -> Array a -> a
getIndexUnsafe

-- | /O(1)/ Get the byte length of the array.
--
{-# INLINE byteLength #-}
byteLength :: Array a -> Int
byteLength :: forall a. Array a -> Int
byteLength = forall a. MutArray a -> Int
MA.byteLength forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Array a -> MutArray a
unsafeThaw

-- | /O(1)/ Get the length of the array i.e. the number of elements in the
-- array.
--
{-# INLINE length #-}
length :: Unbox a => Array a -> Int
length :: forall a. Unbox a => Array a -> Int
length Array a
arr = forall a. Unbox a => MutArray a -> Int
MA.length (forall a. Array a -> MutArray a
unsafeThaw Array a
arr)

-- | Unfold an array into a stream in reverse order.
--
{-# INLINE_NORMAL readerRev #-}
readerRev :: forall m a. (Monad m, Unbox a) => Unfold m (Array a) a
readerRev :: forall (m :: * -> *) a. (Monad m, Unbox a) => Unfold m (Array a) a
readerRev = forall a c (m :: * -> *) b.
(a -> c) -> Unfold m c b -> Unfold m a b
Unfold.lmap forall a. Array a -> MutArray a
unsafeThaw forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) a.
(Monad m, Unbox a) =>
(forall b. IO b -> m b) -> Unfold m (MutArray a) a
MA.readerRevWith (forall (m :: * -> *) a. Monad m => a -> m a
return forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. IO a -> a
unsafeInlineIO)

{-# INLINE_NORMAL toStreamD #-}
toStreamD :: forall m a. (Monad m, Unbox a) => Array a -> D.Stream m a
toStreamD :: forall (m :: * -> *) a. (Monad m, Unbox a) => Array a -> Stream m a
toStreamD Array a
arr = forall (m :: * -> *) a.
(Monad m, Unbox a) =>
(forall b. IO b -> m b) -> MutArray a -> Stream m a
MA.toStreamDWith (forall (m :: * -> *) a. Monad m => a -> m a
return forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. IO a -> a
unsafeInlineIO) (forall a. Array a -> MutArray a
unsafeThaw Array a
arr)

{-# INLINE toStreamK #-}
toStreamK :: forall m a. (Monad m, Unbox a) => Array a -> K.StreamK m a
toStreamK :: forall (m :: * -> *) a.
(Monad m, Unbox a) =>
Array a -> StreamK m a
toStreamK Array a
arr = forall (m :: * -> *) a.
(Monad m, Unbox a) =>
(forall b. IO b -> m b) -> MutArray a -> StreamK m a
MA.toStreamKWith (forall (m :: * -> *) a. Monad m => a -> m a
return forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. IO a -> a
unsafeInlineIO) (forall a. Array a -> MutArray a
unsafeThaw Array a
arr)

{-# INLINE_NORMAL toStreamDRev #-}
toStreamDRev :: forall m a. (Monad m, Unbox a) => Array a -> D.Stream m a
toStreamDRev :: forall (m :: * -> *) a. (Monad m, Unbox a) => Array a -> Stream m a
toStreamDRev Array a
arr =
    forall (m :: * -> *) a.
(Monad m, Unbox a) =>
(forall b. IO b -> m b) -> MutArray a -> Stream m a
MA.toStreamDRevWith (forall (m :: * -> *) a. Monad m => a -> m a
return forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. IO a -> a
unsafeInlineIO) (forall a. Array a -> MutArray a
unsafeThaw Array a
arr)

{-# INLINE toStreamKRev #-}
toStreamKRev :: forall m a. (Monad m, Unbox a) => Array a -> K.StreamK m a
toStreamKRev :: forall (m :: * -> *) a.
(Monad m, Unbox a) =>
Array a -> StreamK m a
toStreamKRev Array a
arr =
    forall (m :: * -> *) a.
(Monad m, Unbox a) =>
(forall b. IO b -> m b) -> MutArray a -> StreamK m a
MA.toStreamKRevWith (forall (m :: * -> *) a. Monad m => a -> m a
return forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. IO a -> a
unsafeInlineIO) (forall a. Array a -> MutArray a
unsafeThaw Array a
arr)

-- | Convert an 'Array' into a stream.
--
-- /Pre-release/
{-# INLINE_EARLY read #-}
read :: (Monad m, Unbox a) => Array a -> Stream m a
read :: forall (m :: * -> *) a. (Monad m, Unbox a) => Array a -> Stream m a
read = forall (m :: * -> *) a. (Monad m, Unbox a) => Array a -> Stream m a
toStreamD

-- | Same as 'read'
--
{-# DEPRECATED toStream "Please use 'read' instead." #-}
{-# INLINE_EARLY toStream #-}
toStream :: (Monad m, Unbox a) => Array a -> Stream m a
toStream :: forall (m :: * -> *) a. (Monad m, Unbox a) => Array a -> Stream m a
toStream = forall (m :: * -> *) a. (Monad m, Unbox a) => Array a -> Stream m a
read
-- XXX add fallback to StreamK rule
-- {-# RULES "Streamly.Array.read fallback to StreamK" [1]
--     forall a. S.readK (read a) = K.fromArray a #-}

-- | Convert an 'Array' into a stream in reverse order.
--
-- /Pre-release/
{-# INLINE_EARLY readRev #-}
readRev :: (Monad m, Unbox a) => Array a -> Stream m a
readRev :: forall (m :: * -> *) a. (Monad m, Unbox a) => Array a -> Stream m a
readRev = forall (m :: * -> *) a. (Monad m, Unbox a) => Array a -> Stream m a
toStreamDRev

-- | Same as 'readRev'
--
{-# DEPRECATED toStreamRev "Please use 'readRev' instead." #-}
{-# INLINE_EARLY toStreamRev #-}
toStreamRev :: (Monad m, Unbox a) => Array a -> Stream m a
toStreamRev :: forall (m :: * -> *) a. (Monad m, Unbox a) => Array a -> Stream m a
toStreamRev = forall (m :: * -> *) a. (Monad m, Unbox a) => Array a -> Stream m a
readRev

-- XXX add fallback to StreamK rule
-- {-# RULES "Streamly.Array.readRev fallback to StreamK" [1]
--     forall a. S.toStreamK (readRev a) = K.revFromArray a #-}

{-# INLINE_NORMAL foldl' #-}
foldl' :: forall a b. Unbox a => (b -> a -> b) -> b -> Array a -> b
foldl' :: forall a b. Unbox a => (b -> a -> b) -> b -> Array a -> b
foldl' b -> a -> b
f b
z Array a
arr = forall a. Identity a -> a
runIdentity forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) b a.
Monad m =>
(b -> a -> b) -> b -> Stream m a -> m b
D.foldl' b -> a -> b
f b
z forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) a. (Monad m, Unbox a) => Array a -> Stream m a
toStreamD Array a
arr

{-# INLINE_NORMAL foldr #-}
foldr :: Unbox a => (a -> b -> b) -> b -> Array a -> b
foldr :: forall a b. Unbox a => (a -> b -> b) -> b -> Array a -> b
foldr a -> b -> b
f b
z Array a
arr = forall a. Identity a -> a
runIdentity forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) a b.
Monad m =>
(a -> b -> b) -> b -> Stream m a -> m b
D.foldr a -> b -> b
f b
z forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) a. (Monad m, Unbox a) => Array a -> Stream m a
toStreamD Array a
arr

-- | Create two slices of an array without copying the original array. The
-- specified index @i@ is the first index of the second slice.
--
splitAt :: Unbox a => Int -> Array a -> (Array a, Array a)
splitAt :: forall a. Unbox a => Int -> Array a -> (Array a, Array a)
splitAt Int
i Array a
arr = (forall a. MutArray a -> Array a
unsafeFreeze MutArray a
a, forall a. MutArray a -> Array a
unsafeFreeze MutArray a
b)
  where
    (MutArray a
a, MutArray a
b) = forall a. Unbox a => Int -> MutArray a -> (MutArray a, MutArray a)
MA.splitAt Int
i (forall a. Array a -> MutArray a
unsafeThaw Array a
arr)

-- Use foldr/build fusion to fuse with list consumers
-- This can be useful when using the IsList instance
{-# INLINE_LATE toListFB #-}
toListFB :: forall a b. Unbox a => (a -> b -> b) -> b -> Array a -> b
toListFB :: forall a b. Unbox a => (a -> b -> b) -> b -> Array a -> b
toListFB a -> b -> b
c b
n Array{Int
MutByteArray
arrEnd :: Int
arrStart :: Int
arrContents :: MutByteArray
arrEnd :: forall a. Array a -> Int
arrStart :: forall a. Array a -> Int
arrContents :: forall a. Array a -> MutByteArray
..} = Int -> b
go Int
arrStart
    where

    go :: Int -> b
go Int
p | forall a. (?callStack::CallStack) => Bool -> a -> a
assert (Int
p forall a. Ord a => a -> a -> Bool
<= Int
arrEnd) (Int
p forall a. Eq a => a -> a -> Bool
== Int
arrEnd) = b
n
    go Int
p =
        -- unsafeInlineIO allows us to run this in Identity monad for pure
        -- toList/foldr case which makes them much faster due to not
        -- accumulating the list and fusing better with the pure consumers.
        --
        -- This should be safe as the array contents are guaranteed to be
        -- evaluated/written to before we peekAt at them.
        let !x :: a
x = forall a. IO a -> a
unsafeInlineIO forall a b. (a -> b) -> a -> b
$ forall a. Unbox a => Int -> MutByteArray -> IO a
peekAt Int
p MutByteArray
arrContents
        in a -> b -> b
c a
x (Int -> b
go (INDEX_NEXT(p,a)))

-- | Convert an 'Array' into a list.
--
{-# INLINE toList #-}
toList :: Unbox a => Array a -> [a]
toList :: forall a. Unbox a => Array a -> [a]
toList Array a
s = forall a. (forall b. (a -> b -> b) -> b -> b) -> [a]
build (\a -> b -> b
c b
n -> forall a b. Unbox a => (a -> b -> b) -> b -> Array a -> b
toListFB a -> b -> b
c b
n Array a
s)

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

-- | @writeN n@ folds a maximum of @n@ elements from the input stream to an
-- 'Array'.
--
{-# INLINE_NORMAL writeN #-}
writeN :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (Array a)
writeN :: forall (m :: * -> *) a.
(MonadIO m, Unbox a) =>
Int -> Fold m a (Array a)
writeN = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall a. MutArray a -> Array a
unsafeFreeze forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *) a.
(MonadIO m, Unbox a) =>
Int -> Fold m a (MutArray a)
MA.writeN

-- | Like 'fromListN' but creates a pinned array.
{-# INLINE_NORMAL pinnedWriteN #-}
pinnedWriteN :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (Array a)
pinnedWriteN :: forall (m :: * -> *) a.
(MonadIO m, Unbox a) =>
Int -> Fold m a (Array a)
pinnedWriteN = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall a. MutArray a -> Array a
unsafeFreeze forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *) a.
(MonadIO m, Unbox a) =>
Int -> Fold m a (MutArray a)
MA.pinnedWriteN

-- | @pinnedWriteNAligned alignment n@ folds a maximum of @n@ elements from the input
-- stream to an 'Array' aligned to the given size.
--
-- /Pre-release/
--
{-# INLINE_NORMAL pinnedWriteNAligned #-}
pinnedWriteNAligned :: forall m a. (MonadIO m, Unbox a)
    => Int -> Int -> Fold m a (Array a)
pinnedWriteNAligned :: forall (m :: * -> *) a.
(MonadIO m, Unbox a) =>
Int -> Int -> Fold m a (Array a)
pinnedWriteNAligned Int
alignSize = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall a. MutArray a -> Array a
unsafeFreeze forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *) a.
(MonadIO m, Unbox a) =>
Int -> Int -> Fold m a (MutArray a)
MA.pinnedWriteNAligned Int
alignSize

-- | Like 'writeN' but does not check the array bounds when writing. The fold
-- driver must not call the step function more than 'n' times otherwise it will
-- corrupt the memory and crash. This function exists mainly because any
-- conditional in the step function blocks fusion causing 10x performance
-- slowdown.
--
{-# INLINE_NORMAL writeNUnsafe #-}
writeNUnsafe :: forall m a. (MonadIO m, Unbox a)
    => Int -> Fold m a (Array a)
writeNUnsafe :: forall (m :: * -> *) a.
(MonadIO m, Unbox a) =>
Int -> Fold m a (Array a)
writeNUnsafe Int
n = forall a. MutArray a -> Array a
unsafeFreeze forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (m :: * -> *) a.
(MonadIO m, Unbox a) =>
Int -> Fold m a (MutArray a)
MA.writeNUnsafe Int
n

{-# INLINE_NORMAL pinnedWriteNUnsafe #-}
pinnedWriteNUnsafe :: forall m a. (MonadIO m, Unbox a)
    => Int -> Fold m a (Array a)
pinnedWriteNUnsafe :: forall (m :: * -> *) a.
(MonadIO m, Unbox a) =>
Int -> Fold m a (Array a)
pinnedWriteNUnsafe Int
n = forall a. MutArray a -> Array a
unsafeFreeze forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (m :: * -> *) a.
(MonadIO m, Unbox a) =>
Int -> Fold m a (MutArray a)
MA.pinnedWriteNUnsafe Int
n

{-# INLINE_NORMAL writeWith #-}
writeWith :: forall m a. (MonadIO m, Unbox a)
    => Int -> Fold m a (Array a)
-- writeWith n = FL.rmapM spliceArrays $ toArraysOf n
writeWith :: forall (m :: * -> *) a.
(MonadIO m, Unbox a) =>
Int -> Fold m a (Array a)
writeWith Int
elemCount = forall a. MutArray a -> Array a
unsafeFreeze forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (m :: * -> *) a.
(MonadIO m, Unbox a) =>
Int -> Fold m a (MutArray a)
MA.writeWith Int
elemCount

-- | Fold the whole input to a single array.
--
-- /Caution! Do not use this on infinite streams./
--
{-# INLINE write #-}
write :: forall m a. (MonadIO m, Unbox a) => Fold m a (Array a)
write :: forall (m :: * -> *) a. (MonadIO m, Unbox a) => Fold m a (Array a)
write = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall a. MutArray a -> Array a
unsafeFreeze forall (m :: * -> *) a.
(MonadIO m, Unbox a) =>
Fold m a (MutArray a)
MA.write

-- | Like 'write' but creates a pinned array.
{-# INLINE pinnedWrite #-}
pinnedWrite :: forall m a. (MonadIO m, Unbox a) => Fold m a (Array a)
pinnedWrite :: forall (m :: * -> *) a. (MonadIO m, Unbox a) => Fold m a (Array a)
pinnedWrite = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall a. MutArray a -> Array a
unsafeFreeze forall (m :: * -> *) a.
(MonadIO m, Unbox a) =>
Fold m a (MutArray a)
MA.pinnedWrite

-- | Fold "step" has a dependency on "initial", and each step is dependent on
-- the previous invocation of step due to state passing, finally extract
-- depends on the result of step, therefore, as long as the fold is driven in
-- the correct order the operations would be correctly ordered. We need to
-- ensure that we strictly evaluate the previous step completely before the
-- next step.
--
-- To not share the same array we need to make sure that the result of
-- "initial" is not shared. Existential type ensures that it does not get
-- shared across different folds. However, if we invoke "initial" multiple
-- times for the same fold, there is a possiblity of sharing the two because
-- the compiler would consider it as a pure value. One such example is the
-- chunksOf combinator, or using an array creation fold with foldMany
-- combinator. Is there a proper way in GHC to tell it to not share a pure
-- expression in a particular case?
--
-- For this reason array creation folds have a MonadIO constraint. Pure folds
-- could be unsafe and dangerous. This is dangerous especially when used with
-- foldMany like operations.
--
-- >>> unsafePureWrite = Array.unsafeMakePure Array.write
--
{-# INLINE unsafeMakePure #-}
unsafeMakePure :: Monad m => Fold IO a b -> Fold m a b
unsafeMakePure :: forall (m :: * -> *) a b. Monad m => Fold IO a b -> Fold m a b
unsafeMakePure (Fold s -> a -> IO (Step s b)
step IO (Step s b)
initial s -> IO b
extract s -> IO b
final) =
    forall (m :: * -> *) a b s.
(s -> a -> m (Step s b))
-> m (Step s b) -> (s -> m b) -> (s -> m b) -> Fold m a b
Fold (\s
x a
a -> forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$! forall a. IO a -> a
unsafeInlineIO (s -> a -> IO (Step s b)
step s
x a
a))
         (forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$! forall a. IO a -> a
unsafePerformIO IO (Step s b)
initial)
         (\s
s -> forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$! forall a. IO a -> a
unsafeInlineIO forall a b. (a -> b) -> a -> b
$ s -> IO b
extract s
s)
         (\s
s -> forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$! forall a. IO a -> a
unsafeInlineIO forall a b. (a -> b) -> a -> b
$ s -> IO b
final s
s)

-- | Convert a pure stream in Identity monad to an immutable array.
--
-- Same as the following but with better performance:
--
-- >>> fromPureStream = Array.fromList . runIdentity . Stream.toList
--
fromPureStream :: Unbox a => Stream Identity a -> Array a
fromPureStream :: forall a. Unbox a => Stream Identity a -> Array a
fromPureStream Stream Identity a
x = forall a. IO a -> a
unsafePerformIO forall a b. (a -> b) -> a -> b
$ forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (forall a. MutArray a -> Array a
unsafeFreeze) (forall (m :: * -> *) a.
(MonadIO m, Unbox a) =>
Stream Identity a -> m (MutArray a)
MA.fromPureStream Stream Identity a
x)
-- fromPureStream = runIdentity . D.fold (unsafeMakePure write)
-- fromPureStream = fromList . runIdentity . D.toList

-- | Copy a null terminated immutable 'Addr#' Word8 sequence into an array.
--
-- /Unsafe:/ The caller is responsible for safe addressing.
--
-- Note that this is completely safe when reading from Haskell string
-- literals because they are guaranteed to be NULL terminated:
--
-- >>> Array.toList $ Array.fromByteStr# "\1\2\3\0"#
-- [1,2,3]
--
fromByteStr# :: Addr# -> Array Word8
fromByteStr# :: Addr# -> Array Word8
fromByteStr# Addr#
addr = forall a. Unbox a => Stream Identity a -> Array a
fromPureStream (forall (m :: * -> *). Monad m => Addr# -> Stream m Word8
D.fromByteStr# Addr#
addr)

-------------------------------------------------------------------------------
-- Instances
-------------------------------------------------------------------------------

instance (Show a, Unbox a) => Show (Array a) where
    {-# INLINE show #-}
    show :: Array a -> String
show Array a
arr = String
"fromList " forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> String
show (forall a. Unbox a => Array a -> [a]
toList Array a
arr)

instance (Unbox a, Read a, Show a) => Read (Array a) where
    {-# INLINE readPrec #-}
    readPrec :: ReadPrec (Array a)
readPrec = do
        String
fromListWord <- forall (m :: * -> *) a. Applicative m => Int -> m a -> m [a]
replicateM Int
9 ReadPrec Char
ReadPrec.get
        if String
fromListWord forall a. Eq a => a -> a -> Bool
== String
"fromList "
        then forall a. Unbox a => [a] -> Array a
fromList forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall a. Read a => ReadPrec a
readPrec
        else forall a. ReadPrec a
ReadPrec.pfail

instance (a ~ Char) => IsString (Array a) where
    {-# INLINE fromString #-}
    fromString :: String -> Array a
fromString = forall a. Unbox a => [a] -> Array a
fromList

-- GHC versions 8.0 and below cannot derive IsList
instance Unbox a => IsList (Array a) where
    type (Item (Array a)) = a
    {-# INLINE fromList #-}
    fromList :: [Item (Array a)] -> Array a
fromList = forall a. Unbox a => [a] -> Array a
fromList
    {-# INLINE fromListN #-}
    fromListN :: Int -> [Item (Array a)] -> Array a
fromListN = forall a. Unbox a => Int -> [a] -> Array a
fromListN
    {-# INLINE toList #-}
    toList :: Array a -> [Item (Array a)]
toList = forall a. Unbox a => Array a -> [a]
toList

-- XXX we are assuming that Unboxed equality means element equality. This may
-- or may not be correct? arrcmp is 40% faster compared to stream equality.
instance (Unbox a, Eq a) => Eq (Array a) where
    {-# INLINE (==) #-}
    Array a
arr1 == :: Array a -> Array a -> Bool
== Array a
arr2 =
        forall a. Eq a => a -> a -> Bool
(==) Ordering
EQ forall a b. (a -> b) -> a -> b
$ forall a. IO a -> a
unsafeInlineIO forall a b. (a -> b) -> a -> b
$! forall a. Array a -> MutArray a
unsafeThaw Array a
arr1 forall (m :: * -> *) a.
MonadIO m =>
MutArray a -> MutArray a -> m Ordering
`MA.cmp` forall a. Array a -> MutArray a
unsafeThaw Array a
arr2

instance (Unbox a, Ord a) => Ord (Array a) where
    {-# INLINE compare #-}
    compare :: Array a -> Array a -> Ordering
compare Array a
arr1 Array a
arr2 = forall a. Identity a -> a
runIdentity forall a b. (a -> b) -> a -> b
$
        forall (m :: * -> *) a b.
Monad m =>
(a -> b -> Ordering) -> Stream m a -> Stream m b -> m Ordering
D.cmpBy forall a. Ord a => a -> a -> Ordering
compare (forall (m :: * -> *) a. (Monad m, Unbox a) => Array a -> Stream m a
toStreamD Array a
arr1) (forall (m :: * -> *) a. (Monad m, Unbox a) => Array a -> Stream m a
toStreamD Array a
arr2)

    -- Default definitions defined in base do not have an INLINE on them, so we
    -- replicate them here with an INLINE.
    {-# INLINE (<) #-}
    Array a
x < :: Array a -> Array a -> Bool
<  Array a
y = case forall a. Ord a => a -> a -> Ordering
compare Array a
x Array a
y of { Ordering
LT -> Bool
True;  Ordering
_ -> Bool
False }

    {-# INLINE (<=) #-}
    Array a
x <= :: Array a -> Array a -> Bool
<= Array a
y = case forall a. Ord a => a -> a -> Ordering
compare Array a
x Array a
y of { Ordering
GT -> Bool
False; Ordering
_ -> Bool
True }

    {-# INLINE (>) #-}
    Array a
x > :: Array a -> Array a -> Bool
>  Array a
y = case forall a. Ord a => a -> a -> Ordering
compare Array a
x Array a
y of { Ordering
GT -> Bool
True;  Ordering
_ -> Bool
False }

    {-# INLINE (>=) #-}
    Array a
x >= :: Array a -> Array a -> Bool
>= Array a
y = case forall a. Ord a => a -> a -> Ordering
compare Array a
x Array a
y of { Ordering
LT -> Bool
False; Ordering
_ -> Bool
True }

    -- These two default methods use '<=' rather than 'compare'
    -- because the latter is often more expensive
    {-# INLINE max #-}
    max :: Array a -> Array a -> Array a
max Array a
x Array a
y = if Array a
x forall a. Ord a => a -> a -> Bool
<= Array a
y then Array a
y else Array a
x

    {-# INLINE min #-}
    min :: Array a -> Array a -> Array a
min Array a
x Array a
y = if Array a
x forall a. Ord a => a -> a -> Bool
<= Array a
y then Array a
x else Array a
y

#ifdef DEVBUILD
-- Definitions using the Unboxed constraint from the Array type. These are to
-- make the Foldable instance possible though it is much slower (7x slower).
--
{-# INLINE_NORMAL _toStreamD_ #-}
_toStreamD_ :: forall m a. MonadIO m => Int -> Array a -> D.Stream m a
_toStreamD_ size Array{..} = D.Stream step arrStart

    where

    {-# INLINE_LATE step #-}
    step _ p | p == arrEnd = return D.Stop
    step _ p = liftIO $ do
        x <- peekAt p arrContents
        return $ D.Yield x (p + size)

{-
XXX Why isn't Unboxed implicit? This does not compile unless I use the Unboxed
contraint.
{-# INLINE_NORMAL _foldr #-}
_foldr :: forall a b. (a -> b -> b) -> b -> Array a -> b
_foldr f z arr =
    let !n = SIZE_OF(a)
    in unsafePerformIO $ D.foldr f z $ toStreamD_ n arr
-- | Note that the 'Foldable' instance is 7x slower than the direct
-- operations.
instance Foldable Array where
  foldr = _foldr
-}

#endif

-------------------------------------------------------------------------------
-- Semigroup and Monoid
-------------------------------------------------------------------------------

instance Unbox a => Semigroup (Array a) where
    Array a
arr1 <> :: Array a -> Array a -> Array a
<> Array a
arr2 = forall a. IO a -> a
unsafePerformIO forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) a.
(MonadIO m, Unbox a) =>
Array a -> Array a -> m (Array a)
splice Array a
arr1 Array a
arr2

nil ::
#ifdef DEVBUILD
    Unbox a =>
#endif
    Array a
nil :: forall a. Array a
nil = forall a. MutByteArray -> Int -> Int -> Array a
Array MutByteArray
Unboxed.nil Int
0 Int
0

instance Unbox a => Monoid (Array a) where
    mempty :: Array a
mempty = forall a. Array a
nil
    mappend :: Array a -> Array a -> Array a
mappend = forall a. Semigroup a => a -> a -> a
(<>)