{- |
Module      : Antelude.Array
Description : Contains some functions for Arrays, and reexports the Data.Array module.
Maintainer  : dneavesdev@pm.me
-}
module Antelude.Array
    ( -- * Rexports
    module ArrayExport
    -- * New and Reconstructed for safety
    , atIndex
    , enumerate
    , fromList
    , fromNonEmpty
    , map
    , toList
    , toNonEmpty
    , update
    ) where

import safe           Antelude.Bool                  ( and )
import safe           Antelude.Function              ( flip, (|>) )
import safe           Antelude.Internal.TypesClasses
    ( Functor (fmap)
    , List
    , Maybe (..)
    , NonEmpty
    )
import safe qualified Antelude.List.NonEmpty         as NE ( fromList, toList )
import safe           Antelude.Tuple.Pair            ( first, second )

import safe           Data.Array                     as ArrayExport hiding
    ( assocs
    , elems
    , listArray
    , (//)
    , (!)
    )
import safe qualified Data.Array                     as Array

import safe           Prelude                        ( (<=), (>=) )


-- | This is here for parity with Data.List. The definition is just 'fmap' from 'Functor'.
map :: (e -> f) -> Array i e -> Array i f
map :: forall e f i. (e -> f) -> Array i e -> Array i f
map = (e -> f) -> Array i e -> Array i f
forall a b. (a -> b) -> Array i a -> Array i b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap


-- | Convert a 'List' to an 'Array' along with a pair of bounds.
fromList :: (Array.Ix i) => (i, i) -> List a -> Array i a
fromList :: forall i a. Ix i => (i, i) -> List a -> Array i a
fromList = (i, i) -> [a] -> Array i a
forall i a. Ix i => (i, i) -> List a -> Array i a
Array.listArray


-- | Convert an 'Array' to a 'List'.
toList :: Array i e -> List e
toList :: forall i e. Array i e -> List e
toList = Array i e -> [e]
forall i e. Array i e -> List e
Array.elems


-- | Enumerate an 'Array' into a 'List' of indices i and elements e.
enumerate :: (Array.Ix i) => Array i e -> List (i, e)
enumerate :: forall i e. Ix i => Array i e -> List (i, e)
enumerate = Array i e -> [(i, e)]
forall i e. Ix i => Array i e -> List (i, e)
Array.assocs


-- | Convert a 'NonEmpty' to an 'Array' along with a pair of bounds.
fromNonEmpty :: (Array.Ix i) => (i, i) -> NonEmpty a -> Array i a
fromNonEmpty :: forall i a. Ix i => (i, i) -> NonEmpty a -> Array i a
fromNonEmpty (i, i)
bound NonEmpty a
ne = NonEmpty a -> [a]
forall a. NonEmpty a -> [a]
NE.toList NonEmpty a
ne [a] -> ([a] -> Array i a) -> Array i a
forall a b. a -> (a -> b) -> b
|> (i, i) -> [a] -> Array i a
forall i a. Ix i => (i, i) -> List a -> Array i a
fromList (i, i)
bound

-- | Convert an 'Array' to a 'NonEmpty'.
toNonEmpty :: (Array.Ix i) => Array i a -> Maybe (NonEmpty a)
toNonEmpty :: forall i a. Ix i => Array i a -> Maybe (NonEmpty a)
toNonEmpty Array i a
arr = Array i a -> List a
forall i e. Array i e -> List e
toList Array i a
arr List a -> (List a -> Maybe (NonEmpty a)) -> Maybe (NonEmpty a)
forall a b. a -> (a -> b) -> b
|> List a -> Maybe (NonEmpty a)
forall a. List a -> Maybe (NonEmpty a)
NE.fromList


-- | Reconstruct an 'Array' with the given 'List' of indices i and elements e in their designated positions.
update :: (Array.Ix i) => List (i, e) -> Array i e -> Array i e
update :: forall i e. Ix i => List (i, e) -> Array i e -> Array i e
update = (Array i e -> List (i, e) -> Array i e)
-> List (i, e) -> Array i e -> Array i e
forall a b c. (a -> b -> c) -> b -> a -> c
flip Array i e -> List (i, e) -> Array i e
forall i e. Ix i => Array i e -> [(i, e)] -> Array i e
(Array.//)


-- | Obtain the element at the given index. 'Nothing' if the index is not valid.
atIndex :: (Array.Ix i) => i -> Array i e -> Maybe e
atIndex :: forall i e. Ix i => i -> Array i e -> Maybe e
atIndex i
idx Array i e
arr =
  if (i
idx i -> i -> Bool
forall a. Ord a => a -> a -> Bool
>= Pair i i -> i
forall a b. Pair a b -> a
first (Array i e -> Pair i i
forall i e. Array i e -> (i, i)
Array.bounds Array i e
arr)) Bool -> Bool -> Bool
`and` (i
idx i -> i -> Bool
forall a. Ord a => a -> a -> Bool
<= Pair i i -> i
forall a b. Pair a b -> b
second (Array i e -> Pair i i
forall i e. Array i e -> (i, i)
Array.bounds Array i e
arr))
    then
      Array i e -> i -> e
forall i e. Ix i => Array i e -> i -> e
(Array.!) Array i e
arr i
idx e -> (e -> Maybe e) -> Maybe e
forall a b. a -> (a -> b) -> b
|> e -> Maybe e
forall a. a -> Maybe a
Just
    else
      Maybe e
forall a. Maybe a
Nothing