-- | Zero-indexed dynamic arrays, optimised for lookup. -- Modification is slow. Uninitialised indices have a default value. {-# LANGUAGE CPP #-} module Data.DynamicArray where #ifdef BOUNDS_CHECKS import qualified Data.Primitive.SmallArray.Checked as P #else import qualified Data.Primitive.SmallArray as P #endif import Control.Monad.ST import Data.List -- | A type which has a default value. class Default a where -- | The default value. def :: a -- | An array. data Array a = Array { -- | The size of the array. arraySize :: {-# UNPACK #-} !Int, -- | The contents of the array. arrayContents :: {-# UNPACK #-} !(P.SmallArray a) } -- | Convert an array to a list of (index, value) pairs. {-# INLINE toList #-} toList :: Array a -> [(Int, a)] toList arr = [ (i, x) | i <- [0..arraySize arr-1], let x = P.indexSmallArray (arrayContents arr) i ] instance Show a => Show (Array a) where show arr = "{" ++ intercalate ", " [ show i ++ "->" ++ show x | (i, x) <- toList arr ] ++ "}" -- | Create an empty array. newArray :: Default a => Array a newArray = runST $ do marr <- P.newSmallArray 0 def arr <- P.unsafeFreezeSmallArray marr return (Array 0 arr) -- | Index into an array. O(1) time. {-# INLINE (!) #-} (!) :: Default a => Array a -> Int -> a arr ! n | 0 <= n && n < arraySize arr = P.indexSmallArray (arrayContents arr) n | otherwise = def -- | Update the array. O(n) time. {-# INLINEABLE update #-} update :: Default a => Int -> a -> Array a -> Array a update n x arr = runST $ do let size = arraySize arr `max` (n+1) marr <- P.newSmallArray size def P.copySmallArray marr 0 (arrayContents arr) 0 (arraySize arr) P.writeSmallArray marr n $! x arr' <- P.unsafeFreezeSmallArray marr return (Array size arr')