{-# 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.SmallArray
  ( -- * Types
    A.SmallUnliftedArray_(..)
  , A.SmallUnliftedArray
  , A.SmallMutableUnliftedArray_(..)
  , A.SmallMutableUnliftedArray
    -- * Operations
  , newSmallUnliftedArray
  , unsafeNewSmallUnliftedArray
  , A.sizeofSmallUnliftedArray
  , getSizeofSmallMutableUnliftedArray
  , A.sameSmallMutableUnliftedArray
  , shrinkSmallMutableUnliftedArray
  , writeSmallUnliftedArray
  , readSmallUnliftedArray
  , A.indexSmallUnliftedArray
  , unsafeFreezeSmallUnliftedArray
  , freezeSmallUnliftedArray
  , thawSmallUnliftedArray
  , unsafeThawSmallUnliftedArray
  , setSmallUnliftedArray
  , copySmallUnliftedArray
  , copySmallMutableUnliftedArray
  , A.cloneSmallUnliftedArray
  , cloneSmallMutableUnliftedArray
  , A.emptySmallUnliftedArray
  , A.singletonSmallUnliftedArray
  , A.runSmallUnliftedArray
  , A.dupableRunSmallUnliftedArray
    -- * List Conversion
  , A.smallUnliftedArrayToList
  , A.smallUnliftedArrayFromList
  , A.smallUnliftedArrayFromListN
    -- * Folding
  , A.foldrSmallUnliftedArray
  , A.foldrSmallUnliftedArray'
  , A.foldlSmallUnliftedArray
  , A.foldlSmallUnliftedArray'
  , A.foldlSmallUnliftedArrayM'
    -- * Traversals
  , A.traverseSmallUnliftedArray_
  , A.itraverseSmallUnliftedArray_
    -- * Mapping
  , A.mapSmallUnliftedArray
  ) where

import Control.Monad.Primitive (PrimMonad,PrimState,stToPrim)
import Data.Primitive.Unlifted.Class (PrimUnlifted (..))
import qualified Data.Primitive.Unlifted.SmallArray.ST as A
import Data.Primitive.Unlifted.SmallArray.ST (SmallUnliftedArray, SmallMutableUnliftedArray)

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

setSmallUnliftedArray
  :: (PrimMonad m, PrimUnlifted a)
  => SmallMutableUnliftedArray (PrimState m) a -- ^ destination
  -> a -- ^ value to fill with
  -> Int -- ^ offset
  -> Int -- ^ length
  -> m ()
{-# inline setSmallUnliftedArray #-}
setSmallUnliftedArray :: forall (m :: * -> *) a.
(PrimMonad m, PrimUnlifted a) =>
SmallMutableUnliftedArray (PrimState m) a
-> a -> Int -> Int -> m ()
setSmallUnliftedArray SmallMutableUnliftedArray (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
$ SmallMutableUnliftedArray (PrimState m) a
-> a -> Int -> Int -> ST (PrimState m) ()
forall a s.
PrimUnlifted a =>
SmallMutableUnliftedArray s a -> a -> Int -> Int -> ST s ()
A.setSmallUnliftedArray SmallMutableUnliftedArray (PrimState m) a
mua a
v Int
off Int
len

shrinkSmallMutableUnliftedArray
  :: PrimMonad m
  => SmallMutableUnliftedArray (PrimState m) a
  -> Int
  -> m ()
shrinkSmallMutableUnliftedArray :: forall (m :: * -> *) a.
PrimMonad m =>
SmallMutableUnliftedArray (PrimState m) a -> Int -> m ()
shrinkSmallMutableUnliftedArray SmallMutableUnliftedArray (PrimState m) a
mary Int
sz = 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
$ SmallMutableUnliftedArray (PrimState m) a
-> Int -> ST (PrimState m) ()
forall s a. SmallMutableUnliftedArray s a -> Int -> ST s ()
A.shrinkSmallMutableUnliftedArray SmallMutableUnliftedArray (PrimState m) a
mary Int
sz
{-# inline shrinkSmallMutableUnliftedArray #-}

writeSmallUnliftedArray :: (PrimMonad m, PrimUnlifted a)
  => SmallMutableUnliftedArray (PrimState m) a
  -> Int
  -> a
  -> m ()
{-# inline writeSmallUnliftedArray #-}
writeSmallUnliftedArray :: forall (m :: * -> *) a.
(PrimMonad m, PrimUnlifted a) =>
SmallMutableUnliftedArray (PrimState m) a -> Int -> a -> m ()
writeSmallUnliftedArray SmallMutableUnliftedArray (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
$ SmallMutableUnliftedArray (PrimState m) a
-> Int -> a -> ST (PrimState m) ()
forall a s.
PrimUnlifted a =>
SmallMutableUnliftedArray s a -> Int -> a -> ST s ()
A.writeSmallUnliftedArray SmallMutableUnliftedArray (PrimState m) a
mary Int
ix a
a

readSmallUnliftedArray :: (PrimMonad m, PrimUnlifted a)
  => SmallMutableUnliftedArray (PrimState m) a
  -> Int
  -> m a
{-# inline readSmallUnliftedArray #-}
readSmallUnliftedArray :: forall (m :: * -> *) a.
(PrimMonad m, PrimUnlifted a) =>
SmallMutableUnliftedArray (PrimState m) a -> Int -> m a
readSmallUnliftedArray SmallMutableUnliftedArray (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
$ SmallMutableUnliftedArray (PrimState m) a
-> Int -> ST (PrimState m) a
forall a s.
PrimUnlifted a =>
SmallMutableUnliftedArray s a -> Int -> ST s a
A.readSmallUnliftedArray SmallMutableUnliftedArray (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.
unsafeFreezeSmallUnliftedArray
  :: PrimMonad m
  => SmallMutableUnliftedArray (PrimState m) a
  -> m (SmallUnliftedArray a)
unsafeFreezeSmallUnliftedArray :: forall (m :: * -> *) a.
PrimMonad m =>
SmallMutableUnliftedArray (PrimState m) a
-> m (SmallUnliftedArray a)
unsafeFreezeSmallUnliftedArray SmallMutableUnliftedArray (PrimState m) a
mary = ST (PrimState m) (SmallUnliftedArray a) -> m (SmallUnliftedArray a)
forall (m :: * -> *) a. PrimMonad m => ST (PrimState m) a -> m a
stToPrim (ST (PrimState m) (SmallUnliftedArray a)
 -> m (SmallUnliftedArray a))
-> ST (PrimState m) (SmallUnliftedArray a)
-> m (SmallUnliftedArray a)
forall a b. (a -> b) -> a -> b
$ SmallMutableUnliftedArray (PrimState m) a
-> ST (PrimState m) (SmallUnliftedArray a)
forall s a.
SmallMutableUnliftedArray s a -> ST s (SmallUnliftedArray a)
A.unsafeFreezeSmallUnliftedArray SmallMutableUnliftedArray (PrimState m) a
mary
{-# inline unsafeFreezeSmallUnliftedArray #-}

-- | Copies the contents of an immutable array into a mutable array.
copySmallUnliftedArray
  :: PrimMonad m
  => SmallMutableUnliftedArray (PrimState m) a -- ^ destination
  -> Int -- ^ offset into destination
  -> SmallUnliftedArray a -- ^ source
  -> Int -- ^ offset into source
  -> Int -- ^ number of elements to copy
  -> m ()
{-# inline copySmallUnliftedArray #-}
copySmallUnliftedArray :: forall (m :: * -> *) a.
PrimMonad m =>
SmallMutableUnliftedArray (PrimState m) a
-> Int -> SmallUnliftedArray a -> Int -> Int -> m ()
copySmallUnliftedArray SmallMutableUnliftedArray (PrimState m) a
dst Int
doff SmallUnliftedArray 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
$ SmallMutableUnliftedArray (PrimState m) a
-> Int -> SmallUnliftedArray a -> Int -> Int -> ST (PrimState m) ()
forall s a.
SmallMutableUnliftedArray s a
-> Int -> SmallUnliftedArray a -> Int -> Int -> ST s ()
A.copySmallUnliftedArray SmallMutableUnliftedArray (PrimState m) a
dst Int
doff SmallUnliftedArray a
src Int
soff Int
ln

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

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

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

-- | Thaw a 'SmallUnliftedArray', yielding a 'SmallMutableUnliftedArray'.
-- This does not make a copy.
unsafeThawSmallUnliftedArray
  :: PrimMonad m
  => SmallUnliftedArray a -- ^ source
  -> m (SmallMutableUnliftedArray (PrimState m) a)
{-# inline unsafeThawSmallUnliftedArray #-}
unsafeThawSmallUnliftedArray :: forall (m :: * -> *) a.
PrimMonad m =>
SmallUnliftedArray a
-> m (SmallMutableUnliftedArray (PrimState m) a)
unsafeThawSmallUnliftedArray SmallUnliftedArray a
ary = ST (PrimState m) (SmallMutableUnliftedArray (PrimState m) a)
-> m (SmallMutableUnliftedArray (PrimState m) a)
forall (m :: * -> *) a. PrimMonad m => ST (PrimState m) a -> m a
stToPrim (ST (PrimState m) (SmallMutableUnliftedArray (PrimState m) a)
 -> m (SmallMutableUnliftedArray (PrimState m) a))
-> ST (PrimState m) (SmallMutableUnliftedArray (PrimState m) a)
-> m (SmallMutableUnliftedArray (PrimState m) a)
forall a b. (a -> b) -> a -> b
$ SmallUnliftedArray a
-> ST (PrimState m) (SmallMutableUnliftedArray (PrimState m) a)
forall a s.
SmallUnliftedArray a -> ST s (SmallMutableUnliftedArray s a)
A.unsafeThawSmallUnliftedArray SmallUnliftedArray 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.
unsafeNewSmallUnliftedArray
  :: PrimMonad m
  => Int -- ^ size
  -> m (SmallMutableUnliftedArray (PrimState m) a)
{-# inline unsafeNewSmallUnliftedArray #-}
unsafeNewSmallUnliftedArray :: forall (m :: * -> *) a.
PrimMonad m =>
Int -> m (SmallMutableUnliftedArray (PrimState m) a)
unsafeNewSmallUnliftedArray Int
len = ST (PrimState m) (SmallMutableUnliftedArray (PrimState m) a)
-> m (SmallMutableUnliftedArray (PrimState m) a)
forall (m :: * -> *) a. PrimMonad m => ST (PrimState m) a -> m a
stToPrim (ST (PrimState m) (SmallMutableUnliftedArray (PrimState m) a)
 -> m (SmallMutableUnliftedArray (PrimState m) a))
-> ST (PrimState m) (SmallMutableUnliftedArray (PrimState m) a)
-> m (SmallMutableUnliftedArray (PrimState m) a)
forall a b. (a -> b) -> a -> b
$ Int -> ST (PrimState m) (SmallMutableUnliftedArray (PrimState m) a)
forall s a. Int -> ST s (SmallMutableUnliftedArray s a)
A.unsafeNewSmallUnliftedArray Int
len

-- | Yields the length of a 'MutableUnliftedArray'.
getSizeofSmallMutableUnliftedArray
  :: PrimMonad m
  => SmallMutableUnliftedArray (PrimState m) a
  -> m Int
getSizeofSmallMutableUnliftedArray :: forall (m :: * -> *) a.
PrimMonad m =>
SmallMutableUnliftedArray (PrimState m) a -> m Int
getSizeofSmallMutableUnliftedArray SmallMutableUnliftedArray (PrimState m) a
a = ST (PrimState m) Int -> m Int
forall (m :: * -> *) a. PrimMonad m => ST (PrimState m) a -> m a
stToPrim (ST (PrimState m) Int -> m Int) -> ST (PrimState m) Int -> m Int
forall a b. (a -> b) -> a -> b
$ SmallMutableUnliftedArray (PrimState m) a -> ST (PrimState m) Int
forall s e. SmallMutableUnliftedArray s e -> ST s Int
A.getSizeofSmallMutableUnliftedArray SmallMutableUnliftedArray (PrimState m) a
a

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