diff --git a/Data/Array/Util.hs b/Data/Array/Util.hs
new file mode 100644
--- /dev/null
+++ b/Data/Array/Util.hs
@@ -0,0 +1,360 @@
+{-# LANGUAGE BangPatterns, CPP #-}
+module Data.Array.Util
+    ( 
+    -- $intro
+
+    -- * Updating all elements
+      updateElems
+    , updateElemsIx
+    -- ** Monadic versions
+    , updateElemsM
+    , updateElemsIxM
+    -- * Updating certain elements
+    , updateElemsOn
+    , updateElemsIxOn
+    -- ** Monadic versions
+    , updateElemsOnM
+    , updateElemsIxOnM
+    -- * Updating within a bounded area
+    , updateElemsWithin
+    , updateElemsWithinIx
+    -- ** Monadic versions
+    , updateElemsWithinM
+    , updateElemsWithinIxM
+    -- * Updating slices
+    -- $Slice
+    , updateElemsSlice
+    -- ** Monadic versions
+    , updateElemsSliceM
+    ) where
+
+import GHC.Arr
+import Data.Array.Base
+import Control.Monad
+import Control.Exception
+
+#ifdef __GLASGOW_HASKELL__
+#if __GLASGOW_HASKELL__ >= 700
+#define INLINE(x) {-# INLINABLE x #-}
+#else -- 700
+#define INLINE(x) {-# INLINE x #-}
+#endif -- 700
+#else
+#define INLINE(x) {- not inlined -}
+#endif -- __GLASGOW_HASKELL__
+
+-- $intro
+-- This module contains some primitive operations for working with
+-- mutable 'Arrays'. They all try to avoid bounds checking as much
+-- as possible, and should be quite fast.
+-- 
+-- Some functions throw 'IndexOutOfBounds' exceptions. If an exception
+-- is thrown, the array will be left untouched.
+-- 
+-- This library relies on some of the primitives in "GHC.Arr", so is
+-- probably not portable.
+
+
+-- ================
+-- = updateElems* =
+-- ================
+
+{-|
+updateElems mutates every element in an array while avoiding all bounds checks. /O(size of arr)/
+
+>>> arr <- newArray (1,10) 0 :: IO (IOArray Int Int)
+    -- Produces a 1 based array with 10 elements all set to 0.
+>>> updateElems arr (+ 10)
+    -- Updates all elements to 10
+
+-}
+INLINE(updateElems)
+updateElems :: (MArray a e m, Ix i)
+    => (e -> e) -- ^ Update function
+    -> a i e    -- ^ The array
+    -> m ()
+updateElems f arr = do
+    bnds@(_ , end') <- getBounds arr
+    let !end = unsafeIndex bnds end'
+    forM_ [0..end] (update arr f)
+
+
+-- | The same as updateElems but taking a monadic function. /O(size of arr)/
+INLINE(updateElemsM)
+updateElemsM :: (MArray a e m, Ix i) => (e -> m e) -> a i e -> m ()
+updateElemsM f arr = do
+    bnds@(_ , end') <- getBounds arr
+    let !end = unsafeIndex bnds end'
+    forM_ [0..end] (updateM arr f)
+
+
+-- | The same as updateElems, but also providing the index to the
+-- mapping function. /O(size of arr)/
+INLINE(updateElemsIx)
+updateElemsIx :: (MArray a e m, Ix i) => (i -> e -> e) -> a i e -> m ()
+updateElemsIx f arr = do
+    bnds@(_ , end') <- getBounds arr
+    let !end                    = unsafeIndex bnds end'
+
+        -- Should be guaranteed that xs will be null when i = end+1
+        go !i (x:xs) | i <= end = updateIx arr f i x >> go (i+1) xs
+        go _ _                  = return ()
+    go 0 (range bnds)
+
+
+-- | The same updateElemsIx but taking a monadic function. /O(size of arr)/
+INLINE(updateElemsIxM)
+updateElemsIxM :: (MArray a e m, Ix i) => (i -> e -> m e) -> a i e -> m ()
+updateElemsIxM f arr = do
+    bnds@(_ , end') <- getBounds arr
+    let !end                     = unsafeIndex bnds end'
+
+        -- Should be guaranteed that xs will be null when i = end+1
+        go !i (x:xs) | i <= end = updateIxM arr f i x >> go (i+1) xs
+        go _ _                  = return ()
+    go 0 (range bnds)
+
+-- ======================
+-- = updateElemsWithin* =
+-- ======================
+
+{-|
+Takes an update function 'f' and a tuple of indicies '(start, finish)',
+and applies the function to all elements returned by 'range (start, finish)'.
+
+If this is a 2D array, then the area updated will be the box bounded by these elements,
+and the rectangular prism area for a 3D array etc.
+
+Throws an 'IndexOutOfBounds' exception if either of the indicies are out of bounds.
+-}
+INLINE(updateElemsWithin)
+updateElemsWithin :: (MArray a e m, Ix i)
+    => (e -> e) -- ^ Update function
+    -> (i,i)    -- ^ The bounds within which to apply f. 
+    -> a i e    -- ^ The array
+    -> m ()
+updateElemsWithin f (start, finish) arr = do
+    bnds <- getBounds arr
+    let !ok      = inRange bnds start && inRange bnds finish
+        indicies = map (unsafeIndex bnds) $ range (start, finish)
+
+    when (not ok) $ throw $ IndexOutOfBounds $ "Data.Array.Util updateElemsWithin"
+    forM_ indicies (update arr f)
+
+
+-- | The same as 'updateElemsWithin' but taking a monadic function.
+-- 
+-- Throws an 'IndexOutOfBounds' exception if either of the indicies are out of bounds.
+INLINE(updateElemsWithinM)
+updateElemsWithinM :: (MArray a e m, Ix i) => (e -> m e) -> (i,i) -> a i e -> m ()
+updateElemsWithinM f (start, finish) arr = do
+    bnds <- getBounds arr
+    let !ok      = inRange bnds start && inRange bnds finish
+        indicies = map (unsafeIndex bnds) $ range (start, finish)
+
+    when (not ok) $ throw $ IndexOutOfBounds $ "Data.Array.Util updateElemsWithin"
+    forM_ indicies (updateM arr f)
+
+
+-- | Takes an update function 'f' and a tuple of indicies '(start, finish)'
+-- , and applies the function to all elements returned by range (start, finish).
+-- 
+-- Throws an 'IndexOutOfBounds' exception if either of the indicies are out of bounds.
+INLINE(updateElemsWithinIx)
+updateElemsWithinIx :: (MArray a e m, Ix i, Show i) => (i -> e -> e) -> (i,i) -> a i e -> m ()
+updateElemsWithinIx f (start, finish) arr = do
+    bnds <- getBounds arr
+    let !ok                = inRange bnds start && inRange bnds finish
+        rnge              = range (start, finish)
+        indicies          = map (unsafeIndex bnds) rnge
+
+        go (!i:is) (x:xs) = updateIx arr f i x >> go is xs
+        go _ _            = return ()
+
+    when (not ok) $ throw $ IndexOutOfBounds $ "Data.Array.Util updateElemsWithinIx"
+    go indicies rnge
+
+
+-- | The same as 'updateElemsWithinIx' but taking a monadic function.
+-- 
+-- Throws an 'IndexOutOfBounds' exception if either of the indicies are out of bounds.
+INLINE(updateElemsWithinIxM)
+updateElemsWithinIxM :: (MArray a e m, Ix i, Show i) => (i -> e -> m e) -> (i,i) -> a i e -> m ()
+updateElemsWithinIxM f (start, finish) arr = do
+    bnds <- getBounds arr
+    let !ok                = inRange bnds start && inRange bnds finish
+        rnge              = range (start, finish)
+        indicies          = map (unsafeIndex bnds) rnge
+
+        go (!i:is) (x:xs) = updateIxM arr f i x >> go is xs
+        go _ _            = return ()
+
+    when (not ok) $ throw $ IndexOutOfBounds $ "Data.Array.Util updateElemsWithinIx"
+    go indicies rnge
+
+-- ==================
+-- = updateElemsOn* =
+-- ==================
+
+{-|
+Takes a mapping function, and a list of indicies to mutate.
+
+Throws an 'IndexOutOfBounds' exception if any of the indicies are
+out of bounds. In this case the array will be left unmutated.
+/O(length xs)/
+-}
+INLINE(updateElemsOn)
+updateElemsOn :: (MArray a e m, Ix i)
+    => (e -> e) -- ^ Update function
+    -> [i]      -- ^ A list of indicies to update
+    -> a i e    -- ^ The array
+    -> m ()
+updateElemsOn f xs arr = do
+    bnds <- getBounds arr
+    let !ok      = all (inRange bnds) xs
+        toOffset = unsafeIndex bnds
+
+    when (not ok) $ throw (IndexOutOfBounds $ "Data.Array.Util updateElems'")
+    forM_ (map toOffset xs) (update arr f)
+
+
+-- | Takes a mapping function, and a list of indicies to mutate.
+-- Throws an 'IndexOutOfBounds' exception if any of the indicies are
+-- out of bounds. In this case the array will be left unmutated.
+-- /O(length xs)/
+INLINE(updateElemsOnM)
+updateElemsOnM :: (MArray a e m, Ix i) => (e -> m e) -> [i] -> a i e -> m ()
+updateElemsOnM f xs arr = do
+    bnds <- getBounds arr
+    let !ok      = all (inRange bnds) xs
+        toOffset = unsafeIndex bnds
+
+    when (not ok) $ throw (IndexOutOfBounds $ "Data.Array.Util updateElems'")
+    forM_ (map toOffset xs) (updateM arr f)
+
+
+-- | Takes a mapping function which takes an index, and a list of indicies
+-- to mutate. Throws 'IndexOutOfBounds' exception as 'updateElems'' does.
+-- /O(length xs)/
+INLINE(updateElemsIxOn)
+updateElemsIxOn :: (MArray a e m, Ix i) => (i -> e -> e) -> [i] -> a i e -> m ()
+updateElemsIxOn f indexes arr = do
+    bnds@(_, hi) <- getBounds arr
+    let toOffset           = unsafeIndex bnds
+        ixs                = map toOffset indexes
+        end                = toOffset hi
+        !ok                = all (\x -> x >= 0 && x <= end) ixs
+
+        go (!i:is) (x:xs)  = updateIx arr f i x >> go is xs
+        go _ _             = return ()
+
+    when (not ok) $ throw (IndexOutOfBounds $ "Data.Array.Util updateElemsIx'")
+    go ixs indexes
+
+
+-- | Takes a mapping function which takes an index, and a list of indicies
+-- to mutate. /O(length xs)/
+-- 
+-- Throws 'IndexOutOfBounds' exception as 'updateElems'' does.
+INLINE(updateElemsIxOnM)
+updateElemsIxOnM :: (MArray a e m, Ix i) => (i -> e -> m e) -> [i] -> a i e -> m ()
+updateElemsIxOnM f indexes arr = do
+    bnds@(_ , hi) <- getBounds arr
+    let toOffset           = unsafeIndex bnds
+        !end               = toOffset hi
+        ixs                = map toOffset indexes
+        !ok                = all (\x -> x >= 0 && x <= end) ixs
+
+        go (!i:is) (x:xs)  = updateIxM arr f i x >> go is xs
+        go _ _             = return ()
+
+    when (not ok) $ throw (IndexOutOfBounds $ "Data.Array.Util updateElemsIx'")
+    go ixs indexes
+
+
+-- ======================
+-- = updateElemsSlice* =
+-- ======================
+
+{- $Slice
+/Note the difference between these functions and updateElemsWithin./
+These functions will update every element whose index holds this property:
+
+> f x = index (start,end) start <= ix && ix <= index (start,end) end
+>   where ix = index (start, end) x
+
+For example:
+
+>>> arr <- newArray ((1,1),(5,5)) 0 :: IO (IOArray Int Int)
+    -- Produces aa 2D array with 25 elements all set to 0.
+>>> updateElemsSlice arr ((2,4),(3,5)) (+ 10)
+    -- Updates elements at indexes [(2,4),(2,5),(3,1),(3,2),(3,3),(3,4),(3,5)] to 10
+
+\*Ix versions are not included, because there's no easy way to map from
+an Int to an element in a particular bounds.
+
+All of these functions may throw 'IndexOutOfBounds' exceptions.
+-}
+
+{-|
+updateElemsSlice mutates every element in an array between a start
+index and an end index. /O(size of arr)/
+
+
+>>> arr <- newArray (1,10) 0 :: IO (IOArray Int Int)
+    -- Produces a 1 based array with 10 elements all set to 0.
+>>> updateElemsSlice arr (2,4) (+ 10)
+    -- Updates elements at indexes 2, 3 and 4 to 10
+
+
+-}
+INLINE(updateElemsSlice)
+updateElemsSlice :: (MArray a e m, Ix i)
+    => (e -> e) -- ^ Update function
+    -> (i,i)    -- ^ The start and end of the region to update
+    -> a i e    -- ^ The array
+    -> m ()
+updateElemsSlice f (start', finish') arr = do
+    bnds@(_ , end') <- getBounds arr
+    let !end    = unsafeIndex bnds end'
+        !start  = unsafeIndex bnds start'
+        !finish = unsafeIndex bnds finish'
+        !ok     = start >= 0 && start <= end && finish >= 0 && finish <= end
+
+    when (not ok) $ throw (IndexOutOfBounds $ "Data.Array.Util updateElemsSlice")
+    forM_ [start..finish] (update arr f)
+
+
+-- | The same as updateElems but taking a monadic function. /O(size of arr)/
+INLINE(updateElemsSliceM)
+updateElemsSliceM :: (MArray a e m, Ix i) => (e -> m e) -> (i,i) -> a i e -> m ()
+updateElemsSliceM f (start', finish') arr = do
+    bnds@(_ , end') <- getBounds arr
+    let !end    = unsafeIndex bnds end'
+        !start  = unsafeIndex bnds start'
+        !finish = unsafeIndex bnds finish'
+        !ok     = start >= 0 && start <= end && finish >= 0 && finish <= end
+
+    when (not ok) $ throw (IndexOutOfBounds $ "Data.Array.Util updateElemsSlice")
+    forM_ [start..finish] (updateM arr f)
+
+
+-- =====================
+-- = Utility functions =
+-- =====================
+
+{-# INLINE update #-}
+{-# INLINE updateIx #-}
+{-# INLINE updateM #-}
+{-# INLINE updateIxM #-}
+update :: (MArray a e m, Ix i) => a i e -> (e -> e) -> Int -> m ()
+update arr f i = unsafeRead arr i >>= unsafeWrite arr i . f
+
+updateIx :: (MArray a e m, Ix i) => a i e -> (i -> e -> e) -> Int -> i -> m ()
+updateIx arr f i x = unsafeRead arr i >>= unsafeWrite arr i . f x
+
+updateM :: (MArray a e m, Ix i) => a i e -> (e -> m e) -> Int -> m ()
+updateM arr f i = unsafeRead arr i >>= f >>= unsafeWrite arr i
+
+updateIxM :: (MArray a e m, Ix i) => a i e -> (i -> e -> m e) -> Int -> i -> m ()
+updateIxM arr f i x = unsafeRead arr i >>= f x >>= unsafeWrite arr i
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,29 @@
+Copyright 2011 Alex Mason. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are
+permitted provided that the following conditions are met:
+
+   1. Redistributions of source code must retain the above copyright notice, this list of
+      conditions and the following disclaimer.
+
+   2. Redistributions in binary form must reproduce the above copyright notice, this list
+      of conditions and the following disclaimer in the documentation and/or other materials
+      provided with the distribution.
+
+   3. Neither the name of Alex Mason nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY Alex Mason ``AS IS'' AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Alex Mason OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+The views and conclusions contained in the software and documentation are those of the
+authors and should not be interpreted as representing official policies, either expressed
+or implied, of Alex Mason.
diff --git a/Setup.lhs b/Setup.lhs
new file mode 100644
--- /dev/null
+++ b/Setup.lhs
@@ -0,0 +1,4 @@
+#! /usr/bin/env runhaskell
+
+> import Distribution.Simple
+> main = defaultMain
diff --git a/array-utils.cabal b/array-utils.cabal
new file mode 100644
--- /dev/null
+++ b/array-utils.cabal
@@ -0,0 +1,15 @@
+Name:                array-utils
+Version:             0.1
+category:            Data, Data Structures
+Synopsis:            Primitive functions for updating many elements in mutable arrays at once
+Description:         An collection of functions for working with multiple elements in
+                     mutable arrays. It is hoped some or all of these functions will be
+                     included in the array package for GHC 7.2.
+License:             BSD3
+License-file:        LICENSE
+Author:              Alex Mason
+Maintainer:          Alex Mason <axman6@gmail.com>
+
+build-type:          Simple
+Build-Depends:       base > 3.2 && < 5, array > 0.3.0.1
+Exposed-modules:     Data.Array.Util
