{-# language BangPatterns #-}
{-# language MagicHash #-}
{-# language RankNTypes #-}
{-# language ScopedTypeVariables #-}
{-# language TypeFamilies #-}
{-# language UnboxedTuples #-}
{-# language RoleAnnotations #-}

-- |
-- GHC contains three general classes of value types:
--
--   1. Unboxed types: values are machine values made up of fixed numbers of bytes.
--      These include types like @Int#@, @Char#@ and @Addr#@.
--   2. Unlifted types: values are pointers, but strictly evaluated. These include
--      types like @MutVar# s a@, @Array# a@, and @MVar# s a@.
--   3. Lifted types: values are pointers, lazily evaluated.
--
-- Certain lifted types are really just thin wrappers around unboxed types (we can call
-- these category 3a) or unlifted pointer types (we can call these category 3b)
-- Category 3a includes `Int`, `Char`, and `Ptr a`, while category 3b includes
-- @IORef a@, @Data.Primitive.Array.Array a@, and @MVar a@.
--
-- Types in category 3a can be stored efficiently in a @Data.Primitive.PrimArray.PrimArray@,
-- removing and applying wrappers as required. This module provides the same facility for
-- types in category 3b.
module Data.Primitive.Unlifted.Array
  ( -- * Types
    A.UnliftedArray_(..)
  , A.UnliftedArray
  , A.MutableUnliftedArray_(..)
  , A.MutableUnliftedArray
    -- * Operations
  , newUnliftedArray
  , unsafeNewUnliftedArray
  , A.sizeofUnliftedArray
  , A.sizeofMutableUnliftedArray
  , A.sameMutableUnliftedArray
  , writeUnliftedArray
  , readUnliftedArray
  , A.indexUnliftedArray
  , unsafeFreezeUnliftedArray
  , freezeUnliftedArray
  , thawUnliftedArray
  , unsafeThawUnliftedArray
  , setUnliftedArray
  , copyUnliftedArray
  , copyMutableUnliftedArray
  , A.cloneUnliftedArray
  , cloneMutableUnliftedArray
  , A.emptyUnliftedArray
  , A.singletonUnliftedArray
  , A.runUnliftedArray
  , A.dupableRunUnliftedArray
    -- * List Conversion
  , A.unliftedArrayToList
  , A.unliftedArrayFromList
  , A.unliftedArrayFromListN
    -- * Folding
  , A.foldrUnliftedArray
  , A.foldrUnliftedArray'
  , A.foldlUnliftedArray
  , A.foldlUnliftedArray'
  , A.foldlUnliftedArrayM'
    -- * Traversals
  , A.traverseUnliftedArray_
  , A.itraverseUnliftedArray_
    -- * Mapping
  , A.mapUnliftedArray
  ) where

import Control.Monad.Primitive (PrimMonad,PrimState,stToPrim)
import Data.Primitive.Unlifted.Class (PrimUnlifted (..))
import qualified Data.Primitive.Unlifted.Array.ST as A
import Data.Primitive.Unlifted.Array.ST (UnliftedArray, MutableUnliftedArray)

-- | Creates a new 'MutableUnliftedArray' with the specified value as initial
-- contents.
newUnliftedArray
  :: (PrimMonad m, PrimUnlifted a)
  => Int -- ^ size
  -> a -- ^ initial value
  -> m (MutableUnliftedArray (PrimState m) a)
newUnliftedArray :: forall (m :: * -> *) a.
(PrimMonad m, PrimUnlifted a) =>
Int -> a -> m (MutableUnliftedArray (PrimState m) a)
newUnliftedArray Int
len a
v = ST (PrimState m) (MutableUnliftedArray (PrimState m) a)
-> m (MutableUnliftedArray (PrimState m) a)
forall (m :: * -> *) a. PrimMonad m => ST (PrimState m) a -> m a
stToPrim (ST (PrimState m) (MutableUnliftedArray (PrimState m) a)
 -> m (MutableUnliftedArray (PrimState m) a))
-> ST (PrimState m) (MutableUnliftedArray (PrimState m) a)
-> m (MutableUnliftedArray (PrimState m) a)
forall a b. (a -> b) -> a -> b
$ Int -> a -> ST (PrimState m) (MutableUnliftedArray (PrimState m) a)
forall a s.
PrimUnlifted a =>
Int -> a -> ST s (MutableUnliftedArray s a)
A.newUnliftedArray Int
len a
v
{-# inline newUnliftedArray #-}

setUnliftedArray
  :: (PrimMonad m, PrimUnlifted a)
  => MutableUnliftedArray (PrimState m) a -- ^ destination
  -> a -- ^ value to fill with
  -> Int -- ^ offset
  -> Int -- ^ length
  -> m ()
{-# inline setUnliftedArray #-}
setUnliftedArray :: forall (m :: * -> *) a.
(PrimMonad m, PrimUnlifted a) =>
MutableUnliftedArray (PrimState m) a -> a -> Int -> Int -> m ()
setUnliftedArray MutableUnliftedArray (PrimState m) a
mua a
v Int
off Int
len = ST (PrimState m) () -> m ()
forall (m :: * -> *) a. PrimMonad m => ST (PrimState m) a -> m a
stToPrim (ST (PrimState m) () -> m ()) -> ST (PrimState m) () -> m ()
forall a b. (a -> b) -> a -> b
$ MutableUnliftedArray (PrimState m) a
-> a -> Int -> Int -> ST (PrimState m) ()
forall a s.
PrimUnlifted a =>
MutableUnliftedArray s a -> a -> Int -> Int -> ST s ()
A.setUnliftedArray MutableUnliftedArray (PrimState m) a
mua a
v Int
off Int
len

writeUnliftedArray :: (PrimMonad m, PrimUnlifted a)
  => MutableUnliftedArray (PrimState m) a
  -> Int
  -> a
  -> m ()
{-# inline writeUnliftedArray #-}
writeUnliftedArray :: forall (m :: * -> *) a.
(PrimMonad m, PrimUnlifted a) =>
MutableUnliftedArray (PrimState m) a -> Int -> a -> m ()
writeUnliftedArray MutableUnliftedArray (PrimState m) a
mary Int
ix a
a = ST (PrimState m) () -> m ()
forall (m :: * -> *) a. PrimMonad m => ST (PrimState m) a -> m a
stToPrim (ST (PrimState m) () -> m ()) -> ST (PrimState m) () -> m ()
forall a b. (a -> b) -> a -> b
$ MutableUnliftedArray (PrimState m) a
-> Int -> a -> ST (PrimState m) ()
forall a s.
PrimUnlifted a =>
MutableUnliftedArray s a -> Int -> a -> ST s ()
A.writeUnliftedArray MutableUnliftedArray (PrimState m) a
mary Int
ix a
a

readUnliftedArray :: (PrimMonad m, PrimUnlifted a)
  => MutableUnliftedArray (PrimState m) a
  -> Int
  -> m a
{-# inline readUnliftedArray #-}
readUnliftedArray :: forall (m :: * -> *) a.
(PrimMonad m, PrimUnlifted a) =>
MutableUnliftedArray (PrimState m) a -> Int -> m a
readUnliftedArray MutableUnliftedArray (PrimState m) a
mary Int
ix = ST (PrimState m) a -> m a
forall (m :: * -> *) a. PrimMonad m => ST (PrimState m) a -> m a
stToPrim (ST (PrimState m) a -> m a) -> ST (PrimState m) a -> m a
forall a b. (a -> b) -> a -> b
$ MutableUnliftedArray (PrimState m) a -> Int -> ST (PrimState m) a
forall a s.
PrimUnlifted a =>
MutableUnliftedArray s a -> Int -> ST s a
A.readUnliftedArray MutableUnliftedArray (PrimState m) a
mary Int
ix

-- | Freezes a 'MutableUnliftedArray', yielding an 'UnliftedArray'. This simply
-- marks the array as frozen in place, so it should only be used when no further
-- modifications to the mutable array will be performed.
unsafeFreezeUnliftedArray
  :: PrimMonad m
  => MutableUnliftedArray (PrimState m) a
  -> m (UnliftedArray a)
unsafeFreezeUnliftedArray :: forall (m :: * -> *) a.
PrimMonad m =>
MutableUnliftedArray (PrimState m) a -> m (UnliftedArray a)
unsafeFreezeUnliftedArray MutableUnliftedArray (PrimState m) a
mary = ST (PrimState m) (UnliftedArray a) -> m (UnliftedArray a)
forall (m :: * -> *) a. PrimMonad m => ST (PrimState m) a -> m a
stToPrim (ST (PrimState m) (UnliftedArray a) -> m (UnliftedArray a))
-> ST (PrimState m) (UnliftedArray a) -> m (UnliftedArray a)
forall a b. (a -> b) -> a -> b
$ MutableUnliftedArray (PrimState m) a
-> ST (PrimState m) (UnliftedArray a)
forall s a. MutableUnliftedArray s a -> ST s (UnliftedArray a)
A.unsafeFreezeUnliftedArray MutableUnliftedArray (PrimState m) a
mary
{-# inline unsafeFreezeUnliftedArray #-}

-- | Copies the contents of an immutable array into a mutable array.
copyUnliftedArray
  :: PrimMonad m
  => MutableUnliftedArray (PrimState m) a -- ^ destination
  -> Int -- ^ offset into destination
  -> UnliftedArray a -- ^ source
  -> Int -- ^ offset into source
  -> Int -- ^ number of elements to copy
  -> m ()
{-# inline copyUnliftedArray #-}
copyUnliftedArray :: forall (m :: * -> *) a.
PrimMonad m =>
MutableUnliftedArray (PrimState m) a
-> Int -> UnliftedArray a -> Int -> Int -> m ()
copyUnliftedArray MutableUnliftedArray (PrimState m) a
dst Int
doff UnliftedArray a
src Int
soff Int
ln = ST (PrimState m) () -> m ()
forall (m :: * -> *) a. PrimMonad m => ST (PrimState m) a -> m a
stToPrim (ST (PrimState m) () -> m ()) -> ST (PrimState m) () -> m ()
forall a b. (a -> b) -> a -> b
$ MutableUnliftedArray (PrimState m) a
-> Int -> UnliftedArray a -> Int -> Int -> ST (PrimState m) ()
forall s a.
MutableUnliftedArray s a
-> Int -> UnliftedArray a -> Int -> Int -> ST s ()
A.copyUnliftedArray MutableUnliftedArray (PrimState m) a
dst Int
doff UnliftedArray a
src Int
soff Int
ln

-- | Copies the contents of one mutable array into another.
copyMutableUnliftedArray
  :: PrimMonad m
  => MutableUnliftedArray (PrimState m) a -- ^ destination
  -> Int -- ^ offset into destination
  -> MutableUnliftedArray (PrimState m) a -- ^ source
  -> Int -- ^ offset into source
  -> Int -- ^ number of elements to copy
  -> m ()
{-# inline copyMutableUnliftedArray #-}
copyMutableUnliftedArray :: forall (m :: * -> *) a.
PrimMonad m =>
MutableUnliftedArray (PrimState m) a
-> Int
-> MutableUnliftedArray (PrimState m) a
-> Int
-> Int
-> m ()
copyMutableUnliftedArray MutableUnliftedArray (PrimState m) a
dst Int
doff MutableUnliftedArray (PrimState m) a
src Int
soff Int
ln = ST (PrimState m) () -> m ()
forall (m :: * -> *) a. PrimMonad m => ST (PrimState m) a -> m a
stToPrim (ST (PrimState m) () -> m ()) -> ST (PrimState m) () -> m ()
forall a b. (a -> b) -> a -> b
$ MutableUnliftedArray (PrimState m) a
-> Int
-> MutableUnliftedArray (PrimState m) a
-> Int
-> Int
-> ST (PrimState m) ()
forall s a.
MutableUnliftedArray s a
-> Int -> MutableUnliftedArray s a -> Int -> Int -> ST s ()
A.copyMutableUnliftedArray MutableUnliftedArray (PrimState m) a
dst Int
doff MutableUnliftedArray (PrimState m) a
src Int
soff Int
ln

-- | Freezes a portion of a 'MutableUnliftedArray', yielding an 'UnliftedArray'.
-- This operation is safe, in that it copies the frozen portion, and the
-- existing mutable array may still be used afterward.
freezeUnliftedArray
  :: PrimMonad m
  => MutableUnliftedArray (PrimState m) a -- ^ source
  -> Int -- ^ offset
  -> Int -- ^ length
  -> m (UnliftedArray a)
freezeUnliftedArray :: forall (m :: * -> *) a.
PrimMonad m =>
MutableUnliftedArray (PrimState m) a
-> Int -> Int -> m (UnliftedArray a)
freezeUnliftedArray MutableUnliftedArray (PrimState m) a
mary Int
off Int
len = ST (PrimState m) (UnliftedArray a) -> m (UnliftedArray a)
forall (m :: * -> *) a. PrimMonad m => ST (PrimState m) a -> m a
stToPrim (ST (PrimState m) (UnliftedArray a) -> m (UnliftedArray a))
-> ST (PrimState m) (UnliftedArray a) -> m (UnliftedArray a)
forall a b. (a -> b) -> a -> b
$ MutableUnliftedArray (PrimState m) a
-> Int -> Int -> ST (PrimState m) (UnliftedArray a)
forall s a.
MutableUnliftedArray s a -> Int -> Int -> ST s (UnliftedArray a)
A.freezeUnliftedArray MutableUnliftedArray (PrimState m) a
mary Int
off Int
len
{-# inline freezeUnliftedArray #-}

-- | Thaws a portion of an 'UnliftedArray', yielding a 'MutableUnliftedArray'.
-- This copies the thawed portion, so mutations will not affect the original
-- array.
thawUnliftedArray
  :: PrimMonad m
  => UnliftedArray a -- ^ source
  -> Int -- ^ offset
  -> Int -- ^ length
  -> m (MutableUnliftedArray (PrimState m) a)
{-# inline thawUnliftedArray #-}
thawUnliftedArray :: forall (m :: * -> *) a.
PrimMonad m =>
UnliftedArray a
-> Int -> Int -> m (MutableUnliftedArray (PrimState m) a)
thawUnliftedArray UnliftedArray a
ary Int
off Int
len = ST (PrimState m) (MutableUnliftedArray (PrimState m) a)
-> m (MutableUnliftedArray (PrimState m) a)
forall (m :: * -> *) a. PrimMonad m => ST (PrimState m) a -> m a
stToPrim (ST (PrimState m) (MutableUnliftedArray (PrimState m) a)
 -> m (MutableUnliftedArray (PrimState m) a))
-> ST (PrimState m) (MutableUnliftedArray (PrimState m) a)
-> m (MutableUnliftedArray (PrimState m) a)
forall a b. (a -> b) -> a -> b
$ UnliftedArray a
-> Int
-> Int
-> ST (PrimState m) (MutableUnliftedArray (PrimState m) a)
forall a s.
UnliftedArray a -> Int -> Int -> ST s (MutableUnliftedArray s a)
A.thawUnliftedArray UnliftedArray a
ary Int
off Int
len

-- | Thaws an 'UnliftedArray', yielding a 'MutableUnliftedArray'.
-- This does not make a copy.
unsafeThawUnliftedArray
  :: PrimMonad m
  => UnliftedArray a -- ^ source
  -> m (MutableUnliftedArray (PrimState m) a)
{-# inline unsafeThawUnliftedArray #-}
unsafeThawUnliftedArray :: forall (m :: * -> *) a.
PrimMonad m =>
UnliftedArray a -> m (MutableUnliftedArray (PrimState m) a)
unsafeThawUnliftedArray UnliftedArray a
ary = ST (PrimState m) (MutableUnliftedArray (PrimState m) a)
-> m (MutableUnliftedArray (PrimState m) a)
forall (m :: * -> *) a. PrimMonad m => ST (PrimState m) a -> m a
stToPrim (ST (PrimState m) (MutableUnliftedArray (PrimState m) a)
 -> m (MutableUnliftedArray (PrimState m) a))
-> ST (PrimState m) (MutableUnliftedArray (PrimState m) a)
-> m (MutableUnliftedArray (PrimState m) a)
forall a b. (a -> b) -> a -> b
$ UnliftedArray a
-> ST (PrimState m) (MutableUnliftedArray (PrimState m) a)
forall a s. UnliftedArray a -> ST s (MutableUnliftedArray s a)
A.unsafeThawUnliftedArray UnliftedArray a
ary

-- | Creates a new 'MutableUnliftedArray'. This function is unsafe because it
-- initializes all elements of the array as pointers to the empty array. Attempting
-- to read one of these elements before writing to it is in effect an unsafe
-- coercion from @'UnliftedArray' a@ to the element type.
unsafeNewUnliftedArray
  :: PrimMonad m
  => Int -- ^ size
  -> m (MutableUnliftedArray (PrimState m) a)
{-# inline unsafeNewUnliftedArray #-}
unsafeNewUnliftedArray :: forall (m :: * -> *) a.
PrimMonad m =>
Int -> m (MutableUnliftedArray (PrimState m) a)
unsafeNewUnliftedArray Int
len = ST (PrimState m) (MutableUnliftedArray (PrimState m) a)
-> m (MutableUnliftedArray (PrimState m) a)
forall (m :: * -> *) a. PrimMonad m => ST (PrimState m) a -> m a
stToPrim (ST (PrimState m) (MutableUnliftedArray (PrimState m) a)
 -> m (MutableUnliftedArray (PrimState m) a))
-> ST (PrimState m) (MutableUnliftedArray (PrimState m) a)
-> m (MutableUnliftedArray (PrimState m) a)
forall a b. (a -> b) -> a -> b
$ Int -> ST (PrimState m) (MutableUnliftedArray (PrimState m) a)
forall s a. Int -> ST s (MutableUnliftedArray s a)
A.unsafeNewUnliftedArray Int
len

-- | Creates a new 'MutableUnliftedArray' containing a copy of a portion of
-- another mutable array.
cloneMutableUnliftedArray
  :: (PrimMonad m)
  => MutableUnliftedArray (PrimState m) a -- ^ source
  -> Int -- ^ offset
  -> Int -- ^ length
  -> m (MutableUnliftedArray (PrimState m) a)
{-# inline cloneMutableUnliftedArray #-}
cloneMutableUnliftedArray :: forall (m :: * -> *) a.
PrimMonad m =>
MutableUnliftedArray (PrimState m) a
-> Int -> Int -> m (MutableUnliftedArray (PrimState m) a)
cloneMutableUnliftedArray MutableUnliftedArray (PrimState m) a
mary Int
off Int
len = ST (PrimState m) (MutableUnliftedArray (PrimState m) a)
-> m (MutableUnliftedArray (PrimState m) a)
forall (m :: * -> *) a. PrimMonad m => ST (PrimState m) a -> m a
stToPrim (ST (PrimState m) (MutableUnliftedArray (PrimState m) a)
 -> m (MutableUnliftedArray (PrimState m) a))
-> ST (PrimState m) (MutableUnliftedArray (PrimState m) a)
-> m (MutableUnliftedArray (PrimState m) a)
forall a b. (a -> b) -> a -> b
$ MutableUnliftedArray (PrimState m) a
-> Int
-> Int
-> ST (PrimState m) (MutableUnliftedArray (PrimState m) a)
forall s a.
MutableUnliftedArray s a
-> Int -> Int -> ST s (MutableUnliftedArray s a)
A.cloneMutableUnliftedArray MutableUnliftedArray (PrimState m) a
mary Int
off Int
len