    {-# LANGUAGE FlexibleContexts, StandaloneDeriving, TypeFamilies #-}
    -- | Arrays, based on Data.Vector.Unboxed, indexed by @Point@.
    module Game.LambdaHack.Common.PointArray
      ( UnboxRepClass(..), Array(..)
      , empty, (!), accessI, (//), replicateA, unfoldrNA
      , foldrA, foldrA', foldlA', ifoldlA', ifoldrA', foldMA'
      , mapA, imapA, imapMA_, minIndexesA, maxIndexA, maxIndexByA, maxLastIndexA
      , toListA
    #ifdef EXPOSE_INTERNAL
        -- * Internal operations
      , toUnboxRep
    #endif
      ) where

    import Prelude ()

    import Game.LambdaHack.Core.Prelude

    import           Data.Binary
    import           Data.Vector.Binary ()
    import qualified Data.Vector.Fusion.Bundle as Bundle
    import qualified Data.Vector.Generic as G
    import qualified Data.Vector.Unboxed as U

    import           Game.LambdaHack.Common.Point
    import qualified Game.LambdaHack.Definition.Color as Color
    import           Game.LambdaHack.Definition.Defs
    import qualified Game.LambdaHack.Definition.DefsInternal as DefsInternal

    class ( Ord c, Eq (UnboxRep c), Ord (UnboxRep c), Bounded (UnboxRep c)
          , Binary (UnboxRep c), U.Unbox (UnboxRep c) )
          => UnboxRepClass c where
      type UnboxRep c
      type instance UnboxRep c = c
      toUnboxRepUnsafe :: c -> UnboxRep c  -- has to be total
      fromUnboxRep :: UnboxRep c -> c  -- has to be total

    instance UnboxRepClass Bool where
      toUnboxRepUnsafe :: Bool -> UnboxRep Bool
    toUnboxRepUnsafe Bool
    c = Bool
    UnboxRep Bool
    c
      fromUnboxRep :: UnboxRep Bool -> Bool
    fromUnboxRep UnboxRep Bool
    c = Bool
    UnboxRep Bool
    c

    instance UnboxRepClass Word8 where
      toUnboxRepUnsafe :: Word8 -> UnboxRep Word8
    toUnboxRepUnsafe Word8
    c = Word8
    UnboxRep Word8
    c
      fromUnboxRep :: UnboxRep Word8 -> Word8
    fromUnboxRep UnboxRep Word8
    c = Word8
    UnboxRep Word8
    c

    instance UnboxRepClass (ContentId k) where
      type UnboxRep (ContentId k) = Word16
      toUnboxRepUnsafe :: ContentId k -> UnboxRep (ContentId k)
    toUnboxRepUnsafe = ContentId k -> Word16
    ContentId k -> UnboxRep (ContentId k)
    forall c. ContentId c -> Word16
    DefsInternal.fromContentId
      fromUnboxRep :: UnboxRep (ContentId k) -> ContentId k
    fromUnboxRep = Word16 -> ContentId k
    UnboxRep (ContentId k) -> ContentId k
    forall c. Word16 -> ContentId c
    DefsInternal.toContentId

    instance UnboxRepClass Color.AttrCharW32 where
      type UnboxRep Color.AttrCharW32 = Word32
      toUnboxRepUnsafe :: AttrCharW32 -> UnboxRep AttrCharW32
    toUnboxRepUnsafe = AttrCharW32 -> Word32
    AttrCharW32 -> UnboxRep AttrCharW32
    Color.attrCharW32
      fromUnboxRep :: UnboxRep AttrCharW32 -> AttrCharW32
    fromUnboxRep = Word32 -> AttrCharW32
    UnboxRep AttrCharW32 -> AttrCharW32
    Color.AttrCharW32

    -- | Arrays indexed by @Point@.
    data Array c = Array
      { forall c. Array c -> X
    axsize  :: X
      , forall c. Array c -> X
    aysize  :: Y
      , forall c. Array c -> Vector (UnboxRep c)
    avector :: U.Vector (UnboxRep c)
      }

    deriving instance UnboxRepClass c => Eq (Array c)

    instance Show (Array c) where
      show :: Array c -> String
    show Array c
    a = String
    "PointArray.Array with size " String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ (X, X) -> String
    forall a. Show a => a -> String
    show (Array c -> X
    forall c. Array c -> X
    axsize Array c
    a, Array c -> X
    forall c. Array c -> X
    aysize Array c
    a)

    instance UnboxRepClass c => Binary (Array c) where
      put :: Array c -> Put
    put Array{X
    Vector (UnboxRep c)
    axsize :: forall c. Array c -> X
    aysize :: forall c. Array c -> X
    avector :: forall c. Array c -> Vector (UnboxRep c)
    axsize :: X
    aysize :: X
    avector :: Vector (UnboxRep c)
    ..} = do
        X -> Put
    forall t. Binary t => t -> Put
    put X
    axsize
        X -> Put
    forall t. Binary t => t -> Put
    put X
    aysize
        Vector (UnboxRep c) -> Put
    forall t. Binary t => t -> Put
    put Vector (UnboxRep c)
    avector
      get :: Get (Array c)
    get = do
        axsize <- Get X
    forall t. Binary t => Get t
    get
        aysize <- get
        avector <- get
        return $! Array{..}

    toUnboxRep :: UnboxRepClass c => c -> UnboxRep c
    {-# INLINE toUnboxRep #-}
    toUnboxRep :: forall c. UnboxRepClass c => c -> UnboxRep c
    toUnboxRep c
    c =
    #ifdef WITH_EXPENSIVE_ASSERTIONS
      assert (c <= fromUnboxRep maxBound) $
    #endif
        c -> UnboxRep c
    forall c. UnboxRepClass c => c -> UnboxRep c
    toUnboxRepUnsafe c
    c

    empty :: UnboxRepClass c => Array c
    empty :: forall c. UnboxRepClass c => Array c
    empty = X -> X -> Vector (UnboxRep c) -> Array c
    forall c. X -> X -> Vector (UnboxRep c) -> Array c
    Array X
    0 X
    0 Vector (UnboxRep c)
    forall a. Unbox a => Vector a
    U.empty

    -- Note: there's no point specializing this to @Point@ arguments,
    -- since the extra few additions in @fromPoint@ may be less expensive than
    -- memory or register allocations needed for the extra @Int@ in @Point@.
    -- | Array lookup.
    (!) :: UnboxRepClass c => Array c -> Point -> c
    {-# INLINE (!) #-}
    ! :: forall c. UnboxRepClass c => Array c -> Point -> c
    (!) Array{X
    Vector (UnboxRep c)
    axsize :: forall c. Array c -> X
    aysize :: forall c. Array c -> X
    avector :: forall c. Array c -> Vector (UnboxRep c)
    axsize :: X
    aysize :: X
    avector :: Vector (UnboxRep c)
    ..} Point
    p = UnboxRep c -> c
    forall c. UnboxRepClass c => UnboxRep c -> c
    fromUnboxRep (UnboxRep c -> c) -> UnboxRep c -> c
    forall a b. (a -> b) -> a -> b
    $ Vector (UnboxRep c)
    avector Vector (UnboxRep c) -> X -> UnboxRep c
    forall a. Unbox a => Vector a -> X -> a
    U.! Point -> X
    forall a. Enum a => a -> X
    fromEnum Point
    p

    accessI :: UnboxRepClass c => Array c -> Int -> UnboxRep c
    {-# INLINE accessI #-}
    accessI :: forall c. UnboxRepClass c => Array c -> X -> UnboxRep c
    accessI Array{X
    Vector (UnboxRep c)
    axsize :: forall c. Array c -> X
    aysize :: forall c. Array c -> X
    avector :: forall c. Array c -> Vector (UnboxRep c)
    axsize :: X
    aysize :: X
    avector :: Vector (UnboxRep c)
    ..} X
    p = Vector (UnboxRep c)
    avector Vector (UnboxRep c) -> X -> UnboxRep c
    forall a. Unbox a => Vector a -> X -> a
    `vectorUnboxedUnsafeIndex` X
    p

    -- | Construct an array updated with the association list.
    (//) :: UnboxRepClass c => Array c -> [(Point, c)] -> Array c
    {-# INLINE (//) #-}
    // :: forall c. UnboxRepClass c => Array c -> [(Point, c)] -> Array c
    (//) Array{X
    Vector (UnboxRep c)
    axsize :: forall c. Array c -> X
    aysize :: forall c. Array c -> X
    avector :: forall c. Array c -> Vector (UnboxRep c)
    axsize :: X
    aysize :: X
    avector :: Vector (UnboxRep c)
    ..} [(Point, c)]
    l = let v :: Vector (UnboxRep c)
    v = Vector (UnboxRep c)
    avector Vector (UnboxRep c) -> [(X, UnboxRep c)] -> Vector (UnboxRep c)
    forall a. Unbox a => Vector a -> [(X, a)] -> Vector a
    U.// ((Point, c) -> (X, UnboxRep c))
    -> [(Point, c)] -> [(X, UnboxRep c)]
    forall a b. (a -> b) -> [a] -> [b]
    map (Point -> X
    forall a. Enum a => a -> X
    fromEnum (Point -> X) -> (c -> UnboxRep c) -> (Point, c) -> (X, UnboxRep c)
    forall b c b' c'. (b -> c) -> (b' -> c') -> (b, b') -> (c, c')
    forall (a :: * -> * -> *) b c b' c'.
    Arrow a =>
    a b c -> a b' c' -> a (b, b') (c, c')
    *** c -> UnboxRep c
    forall c. UnboxRepClass c => c -> UnboxRep c
    toUnboxRep) [(Point, c)]
    l
                       in Array{avector :: Vector (UnboxRep c)
    avector = Vector (UnboxRep c)
    v, X
    axsize :: X
    aysize :: X
    axsize :: X
    aysize :: X
    ..}

    -- unsafeUpdateA :: UnboxRepClass c => Array c -> [(Point, c)] -> ()
    -- {-# INLINE unsafeUpdateA #-}
    -- unsafeUpdateA Array{..} l = runST $ do
    --   vThawed <- U.unsafeThaw avector
    --   mapM_ (\(p, c) -> VM.write vThawed (fromEnum p) (toUnboxRep c)) l
    --   void $ U.unsafeFreeze vThawed

    -- unsafeWriteA :: UnboxRepClass c => Array c -> Point -> c -> ()
    -- {-# INLINE unsafeWriteA #-}
    -- unsafeWriteA Array{..} p c = runST $ do
    --   vThawed <- U.unsafeThaw avector
    --   VM.write vThawed (fromEnum p) (toUnboxRep c)
    --   void $ U.unsafeFreeze vThawed

    -- unsafeWriteManyA :: UnboxRepClass c => Array c -> [Point] -> c -> ()
    -- {-# INLINE unsafeWriteManyA #-}
    -- unsafeWriteManyA Array{..} l c = runST $ do
    --   vThawed <- U.unsafeThaw avector
    --   let d = toUnboxRep c
    --   mapM_ (\p -> VM.write vThawed (fromEnum p) d) l
    --   void $ U.unsafeFreeze vThawed

    -- | Create an array from a replicated element.
    replicateA :: UnboxRepClass c => X -> Y -> c -> Array c
    {-# INLINE replicateA #-}
    replicateA :: forall c. UnboxRepClass c => X -> X -> c -> Array c
    replicateA X
    axsize X
    aysize c
    c =
      Array{avector :: Vector (UnboxRep c)
    avector = X -> UnboxRep c -> Vector (UnboxRep c)
    forall a. Unbox a => X -> a -> Vector a
    U.replicate (X
    axsize X -> X -> X
    forall a. Num a => a -> a -> a
    * X
    aysize) (UnboxRep c -> Vector (UnboxRep c))
    -> UnboxRep c -> Vector (UnboxRep c)
    forall a b. (a -> b) -> a -> b
    $ c -> UnboxRep c
    forall c. UnboxRepClass c => c -> UnboxRep c
    toUnboxRep c
    c, X
    axsize :: X
    aysize :: X
    axsize :: X
    aysize :: X
    ..}

    -- -- | Create an array from a replicated monadic action.
    -- replicateMA :: (Monad m, UnboxRepClass c) => X -> Y -> m c -> m (Array c)
    -- {-# INLINE replicateMA #-}
    -- replicateMA axsize aysize m = do
    --   v <- U.replicateM (axsize * aysize) $ liftM toUnboxRep m
    --   return $! Array{avector = v, ..}

    -- -- | Create an array from a function.
    -- generateA :: UnboxRepClass c => X -> Y -> (Point -> c) -> Array c
    -- {-# INLINE generateA #-}
    -- generateA axsize aysize f =
    --   let g n = toUnboxRep $ f $ toEnum n
    --   in Array{avector = U.generate (axsize * aysize) g, ..}

    -- -- | Create an array from a monadic function.
    -- generateMA :: (Monad m, UnboxRepClass c)
    --            => X -> Y -> (Point -> m c) -> m (Array c)
    -- {-# INLINE generateMA #-}
    -- generateMA axsize aysize fm = do
    --   let gm n = liftM toUnboxRep $ fm $ toEnum n
    --   v <- U.generateM (axsize * aysize) gm
    --   return $! Array{avector = v, ..}

    unfoldrNA :: UnboxRepClass c => X -> Y -> (b -> (c, b)) -> b -> Array c
    {-# INLINE unfoldrNA #-}
    unfoldrNA :: forall c b.
    UnboxRepClass c =>
    X -> X -> (b -> (c, b)) -> b -> Array c
    unfoldrNA X
    axsize X
    aysize b -> (c, b)
    fm b
    b =
      let gm :: b -> Maybe (UnboxRep c, b)
    gm = (UnboxRep c, b) -> Maybe (UnboxRep c, b)
    forall a. a -> Maybe a
    Just ((UnboxRep c, b) -> Maybe (UnboxRep c, b))
    -> (b -> (UnboxRep c, b)) -> b -> Maybe (UnboxRep c, b)
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (c -> UnboxRep c) -> (c, b) -> (UnboxRep c, b)
    forall b c d. (b -> c) -> (b, d) -> (c, d)
    forall (a :: * -> * -> *) b c d.
    Arrow a =>
    a b c -> a (b, d) (c, d)
    first c -> UnboxRep c
    forall c. UnboxRepClass c => c -> UnboxRep c
    toUnboxRep ((c, b) -> (UnboxRep c, b))
    -> (b -> (c, b)) -> b -> (UnboxRep c, b)
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . b -> (c, b)
    fm
          v :: Vector (UnboxRep c)
    v = X -> (b -> Maybe (UnboxRep c, b)) -> b -> Vector (UnboxRep c)
    forall a b. Unbox a => X -> (b -> Maybe (a, b)) -> b -> Vector a
    U.unfoldrN (X
    axsize X -> X -> X
    forall a. Num a => a -> a -> a
    * X
    aysize) b -> Maybe (UnboxRep c, b)
    gm b
    b
      in Array {avector :: Vector (UnboxRep c)
    avector = Vector (UnboxRep c)
    v, X
    axsize :: X
    aysize :: X
    axsize :: X
    aysize :: X
    ..}

    -- -- | Content identifiers array size.
    -- sizeA :: Array c -> (X, Y)
    -- {-# INLINE sizeA #-}
    -- sizeA Array{..} = (axsize, aysize)

    -- | Fold right over an array.
    foldrA :: UnboxRepClass c => (c -> a -> a) -> a -> Array c -> a
    {-# INLINE foldrA #-}
    foldrA :: forall c a. UnboxRepClass c => (c -> a -> a) -> a -> Array c -> a
    foldrA c -> a -> a
    f a
    z0 Array{X
    Vector (UnboxRep c)
    axsize :: forall c. Array c -> X
    aysize :: forall c. Array c -> X
    avector :: forall c. Array c -> Vector (UnboxRep c)
    axsize :: X
    aysize :: X
    avector :: Vector (UnboxRep c)
    ..} = (UnboxRep c -> a -> a) -> a -> Vector (UnboxRep c) -> a
    forall a b. Unbox a => (a -> b -> b) -> b -> Vector a -> b
    U.foldr (c -> a -> a
    f (c -> a -> a) -> (UnboxRep c -> c) -> UnboxRep c -> a -> a
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . UnboxRep c -> c
    forall c. UnboxRepClass c => UnboxRep c -> c
    fromUnboxRep) a
    z0 Vector (UnboxRep c)
    avector

    -- | Fold right strictly over an array.
    foldrA' :: UnboxRepClass c => (c -> a -> a) -> a -> Array c -> a
    {-# INLINE foldrA' #-}
    foldrA' :: forall c a. UnboxRepClass c => (c -> a -> a) -> a -> Array c -> a
    foldrA' c -> a -> a
    f a
    z0 Array{X
    Vector (UnboxRep c)
    axsize :: forall c. Array c -> X
    aysize :: forall c. Array c -> X
    avector :: forall c. Array c -> Vector (UnboxRep c)
    axsize :: X
    aysize :: X
    avector :: Vector (UnboxRep c)
    ..} = (UnboxRep c -> a -> a) -> a -> Vector (UnboxRep c) -> a
    forall a b. Unbox a => (a -> b -> b) -> b -> Vector a -> b
    U.foldr' (c -> a -> a
    f (c -> a -> a) -> (UnboxRep c -> c) -> UnboxRep c -> a -> a
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . UnboxRep c -> c
    forall c. UnboxRepClass c => UnboxRep c -> c
    fromUnboxRep) a
    z0 Vector (UnboxRep c)
    avector

    -- | Fold left strictly over an array.
    foldlA' :: UnboxRepClass c => (a -> c -> a) -> a -> Array c -> a
    {-# INLINE foldlA' #-}
    foldlA' :: forall c a. UnboxRepClass c => (a -> c -> a) -> a -> Array c -> a
    foldlA' a -> c -> a
    f a
    z0 Array{X
    Vector (UnboxRep c)
    axsize :: forall c. Array c -> X
    aysize :: forall c. Array c -> X
    avector :: forall c. Array c -> Vector (UnboxRep c)
    axsize :: X
    aysize :: X
    avector :: Vector (UnboxRep c)
    ..} =
      (a -> UnboxRep c -> a) -> a -> Vector (UnboxRep c) -> a
    forall b a. Unbox b => (a -> b -> a) -> a -> Vector b -> a
    U.foldl' (\a
    a UnboxRep c
    c -> a -> c -> a
    f a
    a (UnboxRep c -> c
    forall c. UnboxRepClass c => UnboxRep c -> c
    fromUnboxRep UnboxRep c
    c)) a
    z0 Vector (UnboxRep c)
    avector

    -- | Fold left strictly over an array
    -- (function applied to each element and its index).
    ifoldlA' :: UnboxRepClass c => (a -> Point -> c -> a) -> a -> Array c -> a
    {-# INLINE ifoldlA' #-}
    ifoldlA' :: forall c a.
    UnboxRepClass c =>
    (a -> Point -> c -> a) -> a -> Array c -> a
    ifoldlA' a -> Point -> c -> a
    f a
    z0 Array{X
    Vector (UnboxRep c)
    axsize :: forall c. Array c -> X
    aysize :: forall c. Array c -> X
    avector :: forall c. Array c -> Vector (UnboxRep c)
    axsize :: X
    aysize :: X
    avector :: Vector (UnboxRep c)
    ..} =
      (a -> X -> UnboxRep c -> a) -> a -> Vector (UnboxRep c) -> a
    forall b a. Unbox b => (a -> X -> b -> a) -> a -> Vector b -> a
    U.ifoldl' (\a
    a X
    n UnboxRep c
    c -> a -> Point -> c -> a
    f a
    a (X -> Point
    forall a. Enum a => X -> a
    toEnum X
    n) (UnboxRep c -> c
    forall c. UnboxRepClass c => UnboxRep c -> c
    fromUnboxRep UnboxRep c
    c)) a
    z0 Vector (UnboxRep c)
    avector

    -- -- | Fold right over an array
    -- -- (function applied to each element and its index).
    -- ifoldrA :: UnboxRepClass c => (Point -> c -> a -> a) -> a -> Array c -> a
    -- {-# INLINE ifoldrA #-}
    -- ifoldrA f z0 Array{..} =
    --   U.ifoldr (\n c a -> f (toEnum n) (fromUnboxRep c) a) z0 avector

    -- | Fold right strictly over an array
    -- (function applied to each element and its index).
    ifoldrA' :: UnboxRepClass c => (Point -> c -> a -> a) -> a -> Array c -> a
    {-# INLINE ifoldrA' #-}
    ifoldrA' :: forall c a.
    UnboxRepClass c =>
    (Point -> c -> a -> a) -> a -> Array c -> a
    ifoldrA' Point -> c -> a -> a
    f a
    z0 Array{X
    Vector (UnboxRep c)
    axsize :: forall c. Array c -> X
    aysize :: forall c. Array c -> X
    avector :: forall c. Array c -> Vector (UnboxRep c)
    axsize :: X
    aysize :: X
    avector :: Vector (UnboxRep c)
    ..} =
      (X -> UnboxRep c -> a -> a) -> a -> Vector (UnboxRep c) -> a
    forall a b. Unbox a => (X -> a -> b -> b) -> b -> Vector a -> b
    U.ifoldr' (\X
    n UnboxRep c
    c a
    a -> Point -> c -> a -> a
    f (X -> Point
    forall a. Enum a => X -> a
    toEnum X
    n) (UnboxRep c -> c
    forall c. UnboxRepClass c => UnboxRep c -> c
    fromUnboxRep UnboxRep c
    c) a
    a) a
    z0 Vector (UnboxRep c)
    avector

    -- | Fold monadically strictly over an array.
    foldMA' :: (Monad m, UnboxRepClass c) => (a -> c -> m a) -> a -> Array c -> m a
    {-# INLINE foldMA' #-}
    foldMA' :: forall (m :: * -> *) c a.
    (Monad m, UnboxRepClass c) =>
    (a -> c -> m a) -> a -> Array c -> m a
    foldMA' a -> c -> m a
    f a
    z0 Array{X
    Vector (UnboxRep c)
    axsize :: forall c. Array c -> X
    aysize :: forall c. Array c -> X
    avector :: forall c. Array c -> Vector (UnboxRep c)
    axsize :: X
    aysize :: X
    avector :: Vector (UnboxRep c)
    ..} =
      (a -> UnboxRep c -> m a) -> a -> Vector (UnboxRep c) -> m a
    forall (m :: * -> *) b a.
    (Monad m, Unbox b) =>
    (a -> b -> m a) -> a -> Vector b -> m a
    U.foldM' (\a
    a UnboxRep c
    c -> a -> c -> m a
    f a
    a (UnboxRep c -> c
    forall c. UnboxRepClass c => UnboxRep c -> c
    fromUnboxRep UnboxRep c
    c)) a
    z0 Vector (UnboxRep c)
    avector

    -- -- | Fold monadically strictly over an array
    -- -- (function applied to each element and its index).
    -- ifoldMA' :: (Monad m, UnboxRepClass c)
    --          => (a -> Point -> c -> m a) -> a -> Array c -> m a
    -- {-# INLINE ifoldMA' #-}
    -- ifoldMA' f z0 Array{..} =
    --   U.ifoldM' (\a n c -> f a (toEnum n) (fromUnboxRep c)) z0 avector

    -- | Map over an array.
    mapA :: (UnboxRepClass c, UnboxRepClass d) => (c -> d) -> Array c -> Array d
    {-# INLINE mapA #-}
    mapA :: forall c d.
    (UnboxRepClass c, UnboxRepClass d) =>
    (c -> d) -> Array c -> Array d
    mapA c -> d
    f Array{X
    Vector (UnboxRep c)
    axsize :: forall c. Array c -> X
    aysize :: forall c. Array c -> X
    avector :: forall c. Array c -> Vector (UnboxRep c)
    axsize :: X
    aysize :: X
    avector :: Vector (UnboxRep c)
    ..} =
      Array{avector :: Vector (UnboxRep d)
    avector = (UnboxRep c -> UnboxRep d)
    -> Vector (UnboxRep c) -> Vector (UnboxRep d)
    forall a b. (Unbox a, Unbox b) => (a -> b) -> Vector a -> Vector b
    U.map (d -> UnboxRep d
    forall c. UnboxRepClass c => c -> UnboxRep c
    toUnboxRep (d -> UnboxRep d) -> (UnboxRep c -> d) -> UnboxRep c -> UnboxRep d
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . c -> d
    f (c -> d) -> (UnboxRep c -> c) -> UnboxRep c -> d
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . UnboxRep c -> c
    forall c. UnboxRepClass c => UnboxRep c -> c
    fromUnboxRep) Vector (UnboxRep c)
    avector, X
    axsize :: X
    aysize :: X
    axsize :: X
    aysize :: X
    ..}

    -- | Map over an array (function applied to each element and its index).
    imapA :: (UnboxRepClass c, UnboxRepClass d)
          =>  (Point -> c -> d) -> Array c -> Array d
    {-# INLINE imapA #-}
    imapA :: forall c d.
    (UnboxRepClass c, UnboxRepClass d) =>
    (Point -> c -> d) -> Array c -> Array d
    imapA Point -> c -> d
    f Array{X
    Vector (UnboxRep c)
    axsize :: forall c. Array c -> X
    aysize :: forall c. Array c -> X
    avector :: forall c. Array c -> Vector (UnboxRep c)
    axsize :: X
    aysize :: X
    avector :: Vector (UnboxRep c)
    ..} =
      let v :: Vector (UnboxRep d)
    v = (X -> UnboxRep c -> UnboxRep d)
    -> Vector (UnboxRep c) -> Vector (UnboxRep d)
    forall a b.
    (Unbox a, Unbox b) =>
    (X -> a -> b) -> Vector a -> Vector b
    U.imap (\X
    n UnboxRep c
    c ->
                       d -> UnboxRep d
    forall c. UnboxRepClass c => c -> UnboxRep c
    toUnboxRep (d -> UnboxRep d) -> d -> UnboxRep d
    forall a b. (a -> b) -> a -> b
    $ Point -> c -> d
    f (X -> Point
    forall a. Enum a => X -> a
    toEnum X
    n) (UnboxRep c -> c
    forall c. UnboxRepClass c => UnboxRep c -> c
    fromUnboxRep UnboxRep c
    c)) Vector (UnboxRep c)
    avector
      in Array{avector :: Vector (UnboxRep d)
    avector = Vector (UnboxRep d)
    v, X
    axsize :: X
    aysize :: X
    axsize :: X
    aysize :: X
    ..}

    -- | Map monadically over an array (function applied to each element
    -- and its index) and ignore the results.
    imapMA_ :: (Monad m, UnboxRepClass c) => (Point -> c -> m ()) -> Array c -> m ()
    {-# INLINE imapMA_ #-}
    imapMA_ :: forall (m :: * -> *) c.
    (Monad m, UnboxRepClass c) =>
    (Point -> c -> m ()) -> Array c -> m ()
    imapMA_ Point -> c -> m ()
    f Array{X
    Vector (UnboxRep c)
    axsize :: forall c. Array c -> X
    aysize :: forall c. Array c -> X
    avector :: forall c. Array c -> Vector (UnboxRep c)
    axsize :: X
    aysize :: X
    avector :: Vector (UnboxRep c)
    ..} =
      (X -> UnboxRep c -> m ()) -> Vector (UnboxRep c) -> m ()
    forall (m :: * -> *) a b.
    (Monad m, Unbox a) =>
    (X -> a -> m b) -> Vector a -> m ()
    U.imapM_ (\X
    n UnboxRep c
    c -> Point -> c -> m ()
    f (X -> Point
    forall a. Enum a => X -> a
    toEnum X
    n) (UnboxRep c -> c
    forall c. UnboxRepClass c => UnboxRep c -> c
    fromUnboxRep UnboxRep c
    c)) Vector (UnboxRep c)
    avector

    -- -- | Set all elements to the given value, in place.
    -- unsafeSetA :: UnboxRepClass c => c -> Array c -> Array c
    -- {-# INLINE unsafeSetA #-}
    -- unsafeSetA c Array{..} = runST $ do
    --   vThawed <- U.unsafeThaw avector
    --   VM.set vThawed (toUnboxRep c)
    --   vFrozen <- U.unsafeFreeze vThawed
    --   return $! Array{avector = vFrozen, ..}

    -- -- | Set all elements to the given value, in place, if possible.
    -- safeSetA :: UnboxRepClass c => c -> Array c -> Array c
    -- {-# INLINE safeSetA #-}
    -- safeSetA c Array{..} =
    --   Array{avector = U.modify (\v -> VM.set v (toUnboxRep c)) avector, ..}

    -- -- | Yield the point coordinates of a minimum element of the array.
    -- -- The array may not be empty.
    -- minIndexA :: UnboxRepClass c => Array c -> Point
    -- {-# INLINE minIndexA #-}
    -- minIndexA Array{..} = toEnum $ U.minIndex avector

    -- -- | Yield the point coordinates of the last minimum element of the array.
    -- -- The array may not be empty.
    -- minLastIndexA :: UnboxRepClass c => Array c -> Point
    -- {-# INLINE minLastIndexA #-}
    -- minLastIndexA Array{..} =
    --   toEnum
    --   $ fst . Bundle.foldl1' imin . Bundle.indexed . G.stream
    --   $ avector
    --  where
    --   imin (i, x) (j, y) = i `seq` j `seq` if x >= y then (j, y) else (i, x)

    -- | Yield the point coordinates of all the minimum elements of the array.
    -- The array may not be empty.
    minIndexesA :: UnboxRepClass c => Array c -> [Point]
    {-# INLINE minIndexesA #-}
    minIndexesA :: forall c. UnboxRepClass c => Array c -> [Point]
    minIndexesA Array{X
    Vector (UnboxRep c)
    axsize :: forall c. Array c -> X
    aysize :: forall c. Array c -> X
    avector :: forall c. Array c -> Vector (UnboxRep c)
    axsize :: X
    aysize :: X
    avector :: Vector (UnboxRep c)
    ..} =
      ((X, UnboxRep c) -> [Point] -> [Point])
    -> [Point] -> Bundle Vector (X, UnboxRep c) -> [Point]
    forall a b (v :: * -> *). (a -> b -> b) -> b -> Bundle v a -> b
    Bundle.foldr (X, UnboxRep c) -> [Point] -> [Point]
    imin [] (Bundle Vector (X, UnboxRep c) -> [Point])
    -> (Vector (UnboxRep c) -> Bundle Vector (X, UnboxRep c))
    -> Vector (UnboxRep c)
    -> [Point]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Bundle Vector (UnboxRep c) -> Bundle Vector (X, UnboxRep c)
    forall (v :: * -> *) a. Bundle v a -> Bundle v (X, a)
    Bundle.indexed (Bundle Vector (UnboxRep c) -> Bundle Vector (X, UnboxRep c))
    -> (Vector (UnboxRep c) -> Bundle Vector (UnboxRep c))
    -> Vector (UnboxRep c)
    -> Bundle Vector (X, UnboxRep c)
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Vector (UnboxRep c) -> Bundle Vector (UnboxRep c)
    forall (v :: * -> *) a. Vector v a => v a -> Bundle v a
    G.stream (Vector (UnboxRep c) -> [Point]) -> Vector (UnboxRep c) -> [Point]
    forall a b. (a -> b) -> a -> b
    $ Vector (UnboxRep c)
    avector
     where
      imin :: (X, UnboxRep c) -> [Point] -> [Point]
    imin (X
    i, UnboxRep c
    x) [Point]
    acc = if UnboxRep c
    x UnboxRep c -> UnboxRep c -> Bool
    forall a. Eq a => a -> a -> Bool
    == UnboxRep c
    minE
                        then let !j :: Point
    j = X -> Point
    forall a. Enum a => X -> a
    toEnum X
    i
                             in Point
    j Point -> [Point] -> [Point]
    forall a. a -> [a] -> [a]
    : [Point]
    acc
                        else [Point]
    acc
      !minE :: UnboxRep c
    minE = Vector (UnboxRep c) -> UnboxRep c
    forall a. (Unbox a, Ord a) => Vector a -> a
    U.minimum Vector (UnboxRep c)
    avector

    -- | Yield the point coordinates of the first maximum element of the array.
    -- The array may not be empty.
    maxIndexA :: UnboxRepClass c => Array c -> Point
    {-# INLINE maxIndexA #-}
    maxIndexA :: forall c. UnboxRepClass c => Array c -> Point
    maxIndexA Array{X
    Vector (UnboxRep c)
    axsize :: forall c. Array c -> X
    aysize :: forall c. Array c -> X
    avector :: forall c. Array c -> Vector (UnboxRep c)
    axsize :: X
    aysize :: X
    avector :: Vector (UnboxRep c)
    ..} = X -> Point
    forall a. Enum a => X -> a
    toEnum (X -> Point) -> X -> Point
    forall a b. (a -> b) -> a -> b
    $ Vector (UnboxRep c) -> X
    forall a. (Unbox a, Ord a) => Vector a -> X
    U.maxIndex Vector (UnboxRep c)
    avector

    -- | Yield the point coordinates of the first maximum element of the array.
    -- The array may not be empty.
    maxIndexByA :: UnboxRepClass c => (c -> c -> Ordering) -> Array c -> Point
    {-# INLINE maxIndexByA #-}
    maxIndexByA :: forall c.
    UnboxRepClass c =>
    (c -> c -> Ordering) -> Array c -> Point
    maxIndexByA c -> c -> Ordering
    f Array{X
    Vector (UnboxRep c)
    axsize :: forall c. Array c -> X
    aysize :: forall c. Array c -> X
    avector :: forall c. Array c -> Vector (UnboxRep c)
    axsize :: X
    aysize :: X
    avector :: Vector (UnboxRep c)
    ..} =
      let g :: UnboxRep c -> UnboxRep c -> Ordering
    g UnboxRep c
    a UnboxRep c
    b = c -> c -> Ordering
    f (UnboxRep c -> c
    forall c. UnboxRepClass c => UnboxRep c -> c
    fromUnboxRep UnboxRep c
    a) (UnboxRep c -> c
    forall c. UnboxRepClass c => UnboxRep c -> c
    fromUnboxRep UnboxRep c
    b)
      in X -> Point
    forall a. Enum a => X -> a
    toEnum (X -> Point) -> X -> Point
    forall a b. (a -> b) -> a -> b
    $ (UnboxRep c -> UnboxRep c -> Ordering) -> Vector (UnboxRep c) -> X
    forall a. Unbox a => (a -> a -> Ordering) -> Vector a -> X
    U.maxIndexBy UnboxRep c -> UnboxRep c -> Ordering
    g Vector (UnboxRep c)
    avector

    -- | Yield the point coordinates of the last maximum element of the array.
    -- The array may not be empty.
    maxLastIndexA :: UnboxRepClass c => Array c -> Point
    {-# INLINE maxLastIndexA #-}
    maxLastIndexA :: forall c. UnboxRepClass c => Array c -> Point
    maxLastIndexA Array{X
    Vector (UnboxRep c)
    axsize :: forall c. Array c -> X
    aysize :: forall c. Array c -> X
    avector :: forall c. Array c -> Vector (UnboxRep c)
    axsize :: X
    aysize :: X
    avector :: Vector (UnboxRep c)
    ..} =
      X -> Point
    forall a. Enum a => X -> a
    toEnum
      (X -> Point) -> X -> Point
    forall a b. (a -> b) -> a -> b
    $ (X, UnboxRep c) -> X
    forall a b. (a, b) -> a
    fst ((X, UnboxRep c) -> X)
    -> (Vector (UnboxRep c) -> (X, UnboxRep c))
    -> Vector (UnboxRep c)
    -> X
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . ((X, UnboxRep c) -> (X, UnboxRep c) -> (X, UnboxRep c))
    -> Bundle Vector (X, UnboxRep c) -> (X, UnboxRep c)
    forall a (v :: * -> *). (a -> a -> a) -> Bundle v a -> a
    Bundle.foldl1' (X, UnboxRep c) -> (X, UnboxRep c) -> (X, UnboxRep c)
    forall {b} {a}. Ord b => (a, b) -> (a, b) -> (a, b)
    imax (Bundle Vector (X, UnboxRep c) -> (X, UnboxRep c))
    -> (Vector (UnboxRep c) -> Bundle Vector (X, UnboxRep c))
    -> Vector (UnboxRep c)
    -> (X, UnboxRep c)
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Bundle Vector (UnboxRep c) -> Bundle Vector (X, UnboxRep c)
    forall (v :: * -> *) a. Bundle v a -> Bundle v (X, a)
    Bundle.indexed (Bundle Vector (UnboxRep c) -> Bundle Vector (X, UnboxRep c))
    -> (Vector (UnboxRep c) -> Bundle Vector (UnboxRep c))
    -> Vector (UnboxRep c)
    -> Bundle Vector (X, UnboxRep c)
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Vector (UnboxRep c) -> Bundle Vector (UnboxRep c)
    forall (v :: * -> *) a. Vector v a => v a -> Bundle v a
    G.stream
      (Vector (UnboxRep c) -> X) -> Vector (UnboxRep c) -> X
    forall a b. (a -> b) -> a -> b
    $ Vector (UnboxRep c)
    avector
     where
      imax :: (a, b) -> (a, b) -> (a, b)
    imax (a
    i, b
    x) (a
    j, b
    y) = a
    i a -> (a, b) -> (a, b)
    forall a b. a -> b -> b
    `seq` a
    j a -> (a, b) -> (a, b)
    forall a b. a -> b -> b
    `seq` if b
    x b -> b -> Bool
    forall a. Ord a => a -> a -> Bool
    <= b
    y then (a
    j, b
    y) else (a
    i, b
    x)

    -- -- | Force the array not to retain any extra memory.
    -- forceA :: UnboxRepClass c => Array c -> Array c
    -- {-# INLINE forceA #-}
    -- forceA Array{..} = Array{avector = U.force avector, ..}

    -- fromListA :: UnboxRepClass c => X -> Y -> [c] -> Array c
    -- {-# INLINE fromListA #-}
    -- fromListA axsize aysize l =
    --   Array{avector = U.fromListN (axsize * aysize) $ map toUnboxRep l, ..}

    toListA :: UnboxRepClass c => Array c -> [c]
    {-# INLINE toListA #-}
    toListA :: forall c. UnboxRepClass c => Array c -> [c]
    toListA Array{X
    Vector (UnboxRep c)
    axsize :: forall c. Array c -> X
    aysize :: forall c. Array c -> X
    avector :: forall c. Array c -> Vector (UnboxRep c)
    axsize :: X
    aysize :: X
    avector :: Vector (UnboxRep c)
    ..} = (UnboxRep c -> c) -> [UnboxRep c] -> [c]
    forall a b. (a -> b) -> [a] -> [b]
    map UnboxRep c -> c
    forall c. UnboxRepClass c => UnboxRep c -> c
    fromUnboxRep ([UnboxRep c] -> [c]) -> [UnboxRep c] -> [c]
    forall a b. (a -> b) -> a -> b
    $ Vector (UnboxRep c) -> [UnboxRep c]
    forall a. Unbox a => Vector a -> [a]
    U.toList Vector (UnboxRep c)
    avector