\begin{code}
module GHC.Arr (
        Ix(..), Array(..), STArray(..),
        indexError, hopelessIndexError,
        arrEleBottom, array, listArray,
        (!), safeRangeSize, negRange, safeIndex, badSafeIndex,
        bounds, numElements, numElementsSTArray, indices, elems,
        assocs, accumArray, adjust, (//), accum,
        amap, ixmap,
        eqArray, cmpArray, cmpIntArray,
        newSTArray, boundsSTArray,
        readSTArray, writeSTArray,
        freezeSTArray, thawSTArray,
        
        fill, done,
        unsafeArray, unsafeArray',
        lessSafeIndex, unsafeAt, unsafeReplace,
        unsafeAccumArray, unsafeAccumArray', unsafeAccum,
        unsafeReadSTArray, unsafeWriteSTArray,
        unsafeFreezeSTArray, unsafeThawSTArray,
    ) where
import GHC.Enum
import GHC.Num
import GHC.ST
import GHC.Base
import GHC.List
import GHC.Real( fromIntegral )
import GHC.Show
infixl 9  !, //
default ()
\end{code}
%*********************************************************
%*                                                      *
\subsection{The @Ix@ class}
%*                                                      *
%*********************************************************
\begin{code}
class (Ord a) => Ix a where
    
    range               :: (a,a) -> [a]
    
    index               :: (a,a) -> a -> Int
    
    unsafeIndex         :: (a,a) -> a -> Int
    
    
    inRange             :: (a,a) -> a -> Bool
    
    rangeSize           :: (a,a) -> Int
    
    
    unsafeRangeSize     :: (a,a) -> Int
        
	
	
	
      
    index b i | inRange b i = unsafeIndex b i   
              | otherwise   = hopelessIndexError
    unsafeIndex b i = index b i
    rangeSize b@(_l,h) | inRange b h = unsafeIndex b h + 1
                       | otherwise   = 0        
                                                
        
        
    unsafeRangeSize b@(_l,h) = unsafeIndex b h + 1
\end{code}
Note that the following is NOT right
        rangeSize (l,h) | l <= h    = index b h + 1
                        | otherwise = 0
Because it might be the case that l
indexError :: Show a => (a,a) -> a -> String -> b
indexError rng i tp
  = error (showString "Ix{" . showString tp . showString "}.index: Index " .
           showParen True (showsPrec 0 i) .
           showString " out of range " $
           showParen True (showsPrec 0 rng) "")
hopelessIndexError :: Int 
hopelessIndexError = error "Error in array index"
instance  Ix Char  where
    
    range (m,n) = [m..n]
    
    unsafeIndex (m,_n) i = fromEnum i  fromEnum m
      
                          
    index b i | inRange b i =  unsafeIndex b i
              | otherwise   =  indexError b i "Char"
    inRange (m,n) i     =  m <= i && i <= n
instance  Ix Int  where
    
        
        
    range (m,n) = [m..n]
    
    unsafeIndex (m,_n) i = i  m
      
                          
    index b i | inRange b i =  unsafeIndex b i
              | otherwise   =  indexError b i "Int"
    
    inRange (I# m,I# n) (I# i) =  m <=# i && i <=# n
instance Ix Word where
    range (m,n)         = [m..n]
    unsafeIndex (m,_) i = fromIntegral (i  m)
    inRange (m,n) i     = m <= i && i <= n
instance  Ix Integer  where
    
    range (m,n) = [m..n]
    
    unsafeIndex (m,_n) i   = fromInteger (i  m)
      
                          
    index b i | inRange b i =  unsafeIndex b i
              | otherwise   =  indexError b i "Integer"
    inRange (m,n) i     =  m <= i && i <= n
instance Ix Bool where 
    
    range (m,n) = [m..n]
    
    unsafeIndex (l,_) i = fromEnum i  fromEnum l
      
                          
    index b i | inRange b i =  unsafeIndex b i
              | otherwise   =  indexError b i "Bool"
    inRange (l,u) i = fromEnum i >= fromEnum l && fromEnum i <= fromEnum u
instance Ix Ordering where 
    
    range (m,n) = [m..n]
    
    unsafeIndex (l,_) i = fromEnum i  fromEnum l
      
                          
    index b i | inRange b i =  unsafeIndex b i
              | otherwise   =  indexError b i "Ordering"
    inRange (l,u) i = fromEnum i >= fromEnum l && fromEnum i <= fromEnum u
instance Ix () where
    
    range   ((), ())    = [()]
    
    unsafeIndex   ((), ()) () = 0
    
    inRange ((), ()) () = True
      
    index b i = unsafeIndex b i
instance (Ix a, Ix b) => Ix (a, b) where 
    
    
    range ((l1,l2),(u1,u2)) =
      [ (i1,i2) | i1 <- range (l1,u1), i2 <- range (l2,u2) ]
    
    unsafeIndex ((l1,l2),(u1,u2)) (i1,i2) =
      unsafeIndex (l1,u1) i1 * unsafeRangeSize (l2,u2) + unsafeIndex (l2,u2) i2
    
    inRange ((l1,l2),(u1,u2)) (i1,i2) =
      inRange (l1,u1) i1 && inRange (l2,u2) i2
    
instance  (Ix a1, Ix a2, Ix a3) => Ix (a1,a2,a3)  where
    
    range ((l1,l2,l3),(u1,u2,u3)) =
        [(i1,i2,i3) | i1 <- range (l1,u1),
                      i2 <- range (l2,u2),
                      i3 <- range (l3,u3)]
    unsafeIndex ((l1,l2,l3),(u1,u2,u3)) (i1,i2,i3) =
      unsafeIndex (l3,u3) i3 + unsafeRangeSize (l3,u3) * (
      unsafeIndex (l2,u2) i2 + unsafeRangeSize (l2,u2) * (
      unsafeIndex (l1,u1) i1))
    inRange ((l1,l2,l3),(u1,u2,u3)) (i1,i2,i3) =
      inRange (l1,u1) i1 && inRange (l2,u2) i2 &&
      inRange (l3,u3) i3
    
instance  (Ix a1, Ix a2, Ix a3, Ix a4) => Ix (a1,a2,a3,a4)  where
    range ((l1,l2,l3,l4),(u1,u2,u3,u4)) =
      [(i1,i2,i3,i4) | i1 <- range (l1,u1),
                       i2 <- range (l2,u2),
                       i3 <- range (l3,u3),
                       i4 <- range (l4,u4)]
    unsafeIndex ((l1,l2,l3,l4),(u1,u2,u3,u4)) (i1,i2,i3,i4) =
      unsafeIndex (l4,u4) i4 + unsafeRangeSize (l4,u4) * (
      unsafeIndex (l3,u3) i3 + unsafeRangeSize (l3,u3) * (
      unsafeIndex (l2,u2) i2 + unsafeRangeSize (l2,u2) * (
      unsafeIndex (l1,u1) i1)))
    inRange ((l1,l2,l3,l4),(u1,u2,u3,u4)) (i1,i2,i3,i4) =
      inRange (l1,u1) i1 && inRange (l2,u2) i2 &&
      inRange (l3,u3) i3 && inRange (l4,u4) i4
    
instance  (Ix a1, Ix a2, Ix a3, Ix a4, Ix a5) => Ix (a1,a2,a3,a4,a5)  where
    range ((l1,l2,l3,l4,l5),(u1,u2,u3,u4,u5)) =
      [(i1,i2,i3,i4,i5) | i1 <- range (l1,u1),
                          i2 <- range (l2,u2),
                          i3 <- range (l3,u3),
                          i4 <- range (l4,u4),
                          i5 <- range (l5,u5)]
    unsafeIndex ((l1,l2,l3,l4,l5),(u1,u2,u3,u4,u5)) (i1,i2,i3,i4,i5) =
      unsafeIndex (l5,u5) i5 + unsafeRangeSize (l5,u5) * (
      unsafeIndex (l4,u4) i4 + unsafeRangeSize (l4,u4) * (
      unsafeIndex (l3,u3) i3 + unsafeRangeSize (l3,u3) * (
      unsafeIndex (l2,u2) i2 + unsafeRangeSize (l2,u2) * (
      unsafeIndex (l1,u1) i1))))
    inRange ((l1,l2,l3,l4,l5),(u1,u2,u3,u4,u5)) (i1,i2,i3,i4,i5) =
      inRange (l1,u1) i1 && inRange (l2,u2) i2 &&
      inRange (l3,u3) i3 && inRange (l4,u4) i4 && 
      inRange (l5,u5) i5
    
\end{code}
%*********************************************************
%*                                                      *
\subsection{The @Array@ types}
%*                                                      *
%*********************************************************
\begin{code}
data Array i e
         = Array !i         
                 !i         
                 !Int       
                            
                            
                 (Array# e) 
data STArray s i e
         = STArray !i                  
                   !i                  
                   !Int                
                                       
                                       
                   (MutableArray# s e) 
        
        
instance Eq (STArray s i e) where
    STArray _ _ _ arr1# == STArray _ _ _ arr2# =
        sameMutableArray arr1# arr2#
\end{code}
%*********************************************************
%*                                                      *
\subsection{Operations on immutable arrays}
%*                                                      *
%*********************************************************
\begin{code}
arrEleBottom :: a
arrEleBottom = error "(Array.!): undefined array element"
array :: Ix i
        => (i,i)        
                        
                        
                        
                        
                        
        -> [(i, e)]     
                        
                        
                        
                        
        -> Array i e
array (l,u) ies
    = let n = safeRangeSize (l,u)
      in unsafeArray' (l,u) n
                      [(safeIndex (l,u) n i, e) | (i, e) <- ies]
unsafeArray :: Ix i => (i,i) -> [(Int, e)] -> Array i e
unsafeArray b ies = unsafeArray' b (rangeSize b) ies
unsafeArray' :: Ix i => (i,i) -> Int -> [(Int, e)] -> Array i e
unsafeArray' (l,u) n@(I# n#) ies = runST (ST $ \s1# ->
    case newArray# n# arrEleBottom s1# of
        (# s2#, marr# #) ->
            foldr (fill marr#) (done l u n marr#) ies s2#)
fill :: MutableArray# s e -> (Int, e) -> STRep s a -> STRep s a
fill marr# (I# i#, e) next 
 = \s1# -> case writeArray# marr# i# e s1# of 
             s2# -> next s2# 
done :: Ix i => i -> i -> Int -> MutableArray# s e -> STRep s (Array i e)
done l u n marr# 
  = \s1# -> case unsafeFreezeArray# marr# s1# of
              (# s2#, arr# #) -> (# s2#, Array l u n arr# #)
listArray :: Ix i => (i,i) -> [e] -> Array i e
listArray (l,u) es = runST (ST $ \s1# ->
    case safeRangeSize (l,u)            of { n@(I# n#) ->
    case newArray# n# arrEleBottom s1#  of { (# s2#, marr# #) ->
    let fillFromList i# xs s3# | i# ==# n# = s3#
                               | otherwise = case xs of
            []   -> s3#
            y:ys -> case writeArray# marr# i# y s3# of { s4# ->
                    fillFromList (i# +# 1#) ys s4# } in
    case fillFromList 0# es s2#         of { s3# ->
    done l u n marr# s3# }}})
(!) :: Ix i => Array i e -> i -> e
arr@(Array l u n _) ! i = unsafeAt arr $ safeIndex (l,u) n i
safeRangeSize :: Ix i => (i, i) -> Int
safeRangeSize (l,u) = let r = rangeSize (l, u)
                      in if r < 0 then negRange
                                  else r
negRange :: Int	  
negRange = error "Negative range size"
safeIndex :: Ix i => (i, i) -> Int -> i -> Int
safeIndex (l,u) n i = let i' = index (l,u) i
                      in if (0 <= i') && (i' < n)
                         then i'
                         else badSafeIndex i' n
lessSafeIndex :: Ix i => (i, i) -> Int -> i -> Int
lessSafeIndex (l,u) _ i = index (l,u) i  
badSafeIndex :: Int -> Int -> Int
badSafeIndex i' n = error ("Error in array index; " ++ show i' ++
                        " not in range [0.." ++ show n ++ ")")
unsafeAt :: Ix i => Array i e -> Int -> e
unsafeAt (Array _ _ _ arr#) (I# i#) =
    case indexArray# arr# i# of (# e #) -> e
bounds :: Ix i => Array i e -> (i,i)
bounds (Array l u _ _) = (l,u)
numElements :: Ix i => Array i e -> Int
numElements (Array _ _ n _) = n
indices :: Ix i => Array i e -> [i]
indices (Array l u _ _) = range (l,u)
elems :: Ix i => Array i e -> [e]
elems arr@(Array _ _ n _) =
    [unsafeAt arr i | i <- [0 .. n  1]]
assocs :: Ix i => Array i e -> [(i, e)]
assocs arr@(Array l u _ _) =
    [(i, arr ! i) | i <- range (l,u)]
accumArray :: Ix i
        => (e -> a -> e)        
        -> e                    
        -> (i,i)                
        -> [(i, a)]             
        -> Array i e
accumArray f initial (l,u) ies =
    let n = safeRangeSize (l,u)
    in unsafeAccumArray' f initial (l,u) n
                         [(safeIndex (l,u) n i, e) | (i, e) <- ies]
unsafeAccumArray :: Ix i => (e -> a -> e) -> e -> (i,i) -> [(Int, a)] -> Array i e
unsafeAccumArray f initial b ies = unsafeAccumArray' f initial b (rangeSize b) ies
unsafeAccumArray' :: Ix i => (e -> a -> e) -> e -> (i,i) -> Int -> [(Int, a)] -> Array i e
unsafeAccumArray' f initial (l,u) n@(I# n#) ies = runST (ST $ \s1# ->
    case newArray# n# initial s1#          of { (# s2#, marr# #) ->
    foldr (adjust f marr#) (done l u n marr#) ies s2# })
adjust :: (e -> a -> e) -> MutableArray# s e -> (Int, a) -> STRep s b -> STRep s b
adjust f marr# (I# i#, new) next
  = \s1# -> case readArray# marr# i# s1# of
        	(# s2#, old #) ->
        	    case writeArray# marr# i# (f old new) s2# of
        	        s3# -> next s3#
(//) :: Ix i => Array i e -> [(i, e)] -> Array i e
arr@(Array l u n _) // ies =
    unsafeReplace arr [(safeIndex (l,u) n i, e) | (i, e) <- ies]
unsafeReplace :: Ix i => Array i e -> [(Int, e)] -> Array i e
unsafeReplace arr ies = runST (do
    STArray l u n marr# <- thawSTArray arr
    ST (foldr (fill marr#) (done l u n marr#) ies))
accum :: Ix i => (e -> a -> e) -> Array i e -> [(i, a)] -> Array i e
accum f arr@(Array l u n _) ies =
    unsafeAccum f arr [(safeIndex (l,u) n i, e) | (i, e) <- ies]
unsafeAccum :: Ix i => (e -> a -> e) -> Array i e -> [(Int, a)] -> Array i e
unsafeAccum f arr ies = runST (do
    STArray l u n marr# <- thawSTArray arr
    ST (foldr (adjust f marr#) (done l u n marr#) ies))
amap :: Ix i => (a -> b) -> Array i a -> Array i b
amap f arr@(Array l u n _) =
    unsafeArray' (l,u) n [(i, f (unsafeAt arr i)) | i <- [0 .. n  1]]
ixmap :: (Ix i, Ix j) => (i,i) -> (i -> j) -> Array j e -> Array i e
ixmap (l,u) f arr =
    array (l,u) [(i, arr ! f i) | i <- range (l,u)]
eqArray :: (Ix i, Eq e) => Array i e -> Array i e -> Bool
eqArray arr1@(Array l1 u1 n1 _) arr2@(Array l2 u2 n2 _) =
    if n1 == 0 then n2 == 0 else
    l1 == l2 && u1 == u2 &&
    and [unsafeAt arr1 i == unsafeAt arr2 i | i <- [0 .. n1  1]]
cmpArray :: (Ix i, Ord e) => Array i e -> Array i e -> Ordering
cmpArray arr1 arr2 = compare (assocs arr1) (assocs arr2)
cmpIntArray :: Ord e => Array Int e -> Array Int e -> Ordering
cmpIntArray arr1@(Array l1 u1 n1 _) arr2@(Array l2 u2 n2 _) =
    if n1 == 0 then
        if n2 == 0 then EQ else LT
    else if n2 == 0 then GT
    else case compare l1 l2 of
             EQ    -> foldr cmp (compare u1 u2) [0 .. (n1 `min` n2)  1]
             other -> other
  where
    cmp i rest = case compare (unsafeAt arr1 i) (unsafeAt arr2 i) of
        EQ    -> rest
        other -> other
\end{code}
%*********************************************************
%*                                                      *
\subsection{Array instances}
%*                                                      *
%*********************************************************
\begin{code}
instance Ix i => Functor (Array i) where
    fmap = amap
instance (Ix i, Eq e) => Eq (Array i e) where
    (==) = eqArray
instance (Ix i, Ord e) => Ord (Array i e) where
    compare = cmpArray
instance (Ix a, Show a, Show b) => Show (Array a b) where
    showsPrec p a =
        showParen (p > appPrec) $
        showString "array " .
        showsPrec appPrec1 (bounds a) .
        showChar ' ' .
        showsPrec appPrec1 (assocs a)
        
\end{code}
%*********************************************************
%*                                                      *
\subsection{Operations on mutable arrays}
%*                                                      *
%*********************************************************
Idle ADR question: What's the tradeoff here between flattening these
datatypes into @STArray ix ix (MutableArray# s elt)@ and using
it as is?  As I see it, the former uses slightly less heap and
provides faster access to the individual parts of the bounds while the
code used has the benefit of providing a ready-made @(lo, hi)@ pair as
required by many array-related functions.  Which wins? Is the
difference significant (probably not).
Idle AJG answer: When I looked at the outputted code (though it was 2
years ago) it seems like you often needed the tuple, and we build
it frequently. Now we've got the overloading specialiser things
might be different, though.
\begin{code}
newSTArray :: Ix i => (i,i) -> e -> ST s (STArray s i e)
newSTArray (l,u) initial = ST $ \s1# ->
    case safeRangeSize (l,u)            of { n@(I# n#) ->
    case newArray# n# initial s1#       of { (# s2#, marr# #) ->
    (# s2#, STArray l u n marr# #) }}
boundsSTArray :: STArray s i e -> (i,i)  
boundsSTArray (STArray l u _ _) = (l,u)
numElementsSTArray :: STArray s i e -> Int
numElementsSTArray (STArray _ _ n _) = n
readSTArray :: Ix i => STArray s i e -> i -> ST s e
readSTArray marr@(STArray l u n _) i =
    unsafeReadSTArray marr (safeIndex (l,u) n i)
unsafeReadSTArray :: Ix i => STArray s i e -> Int -> ST s e
unsafeReadSTArray (STArray _ _ _ marr#) (I# i#)
    = ST $ \s1# -> readArray# marr# i# s1#
writeSTArray :: Ix i => STArray s i e -> i -> e -> ST s () 
writeSTArray marr@(STArray l u n _) i e =
    unsafeWriteSTArray marr (safeIndex (l,u) n i) e
unsafeWriteSTArray :: Ix i => STArray s i e -> Int -> e -> ST s () 
unsafeWriteSTArray (STArray _ _ _ marr#) (I# i#) e = ST $ \s1# ->
    case writeArray# marr# i# e s1# of
        s2# -> (# s2#, () #)
\end{code}
%*********************************************************
%*                                                      *
\subsection{Moving between mutable and immutable}
%*                                                      *
%*********************************************************
\begin{code}
freezeSTArray :: Ix i => STArray s i e -> ST s (Array i e)
freezeSTArray (STArray l u n@(I# n#) marr#) = ST $ \s1# ->
    case newArray# n# arrEleBottom s1#  of { (# s2#, marr'# #) ->
    let copy i# s3# | i# ==# n# = s3#
                    | otherwise =
            case readArray# marr# i# s3# of { (# s4#, e #) ->
            case writeArray# marr'# i# e s4# of { s5# ->
            copy (i# +# 1#) s5# }} in
    case copy 0# s2#                    of { s3# ->
    case unsafeFreezeArray# marr'# s3#  of { (# s4#, arr# #) ->
    (# s4#, Array l u n arr# #) }}}
unsafeFreezeSTArray :: Ix i => STArray s i e -> ST s (Array i e)
unsafeFreezeSTArray (STArray l u n marr#) = ST $ \s1# ->
    case unsafeFreezeArray# marr# s1#   of { (# s2#, arr# #) ->
    (# s2#, Array l u n arr# #) }
thawSTArray :: Ix i => Array i e -> ST s (STArray s i e)
thawSTArray (Array l u n@(I# n#) arr#) = ST $ \s1# ->
    case newArray# n# arrEleBottom s1#  of { (# s2#, marr# #) ->
    let copy i# s3# | i# ==# n# = s3#
                    | otherwise =
            case indexArray# arr# i#    of { (# e #) ->
            case writeArray# marr# i# e s3# of { s4# ->
            copy (i# +# 1#) s4# }} in
    case copy 0# s2#                    of { s3# ->
    (# s3#, STArray l u n marr# #) }}
unsafeThawSTArray :: Ix i => Array i e -> ST s (STArray s i e)
unsafeThawSTArray (Array l u n arr#) = ST $ \s1# ->
    case unsafeThawArray# arr# s1#      of { (# s2#, marr# #) ->
    (# s2#, STArray l u n marr# #) }
\end{code}