1 -----------------------------------------------------------------------------
3 -- Module : Data.Array.Diff
4 -- Copyright : (c) The University of Glasgow 2001
5 -- License : BSD-style (see the file libraries/base/LICENSE)
7 -- Maintainer : libraries@haskell.org
8 -- Stability : experimental
9 -- Portability : non-portable
11 -- Functional arrays with constant-time update.
13 -----------------------------------------------------------------------------
15 module Data.Array.Diff (
19 -- | Diff arrays have an immutable interface, but rely on internal
20 -- updates in place to provide fast functional update operator
23 -- When the '//' operator is applied to a diff array, its contents
24 -- are physically updated in place. The old array silently changes
25 -- its representation without changing the visible behavior:
26 -- it stores a link to the new current array along with the
27 -- difference to be applied to get the old contents.
29 -- So if a diff array is used in a single-threaded style,
30 -- i.e. after '//' application the old version is no longer used,
31 -- @a'!'i@ takes O(1) time and @a '//' d@ takes O(@length d@).
32 -- Accessing elements of older versions gradually becomes slower.
34 -- Updating an array which is not current makes a physical copy.
35 -- The resulting array is unlinked from the old family. So you
36 -- can obtain a version which is guaranteed to be current and
37 -- thus have fast element access by @a '//' []@.
39 -- Possible improvement for the future (not implemented now):
40 -- make it possible to say "I will make an update now, but when
41 -- I later return to the old version, I want it to mutate back
42 -- instead of being copied".
44 IOToDiffArray, -- data IOToDiffArray
45 -- (a :: * -> * -> *) -- internal mutable array
46 -- (i :: *) -- indices
47 -- (e :: *) -- elements
49 -- | Type synonyms for the two most important IO array types.
51 -- Two most important diff array types are fully polymorphic
52 -- lazy boxed DiffArray:
53 DiffArray, -- = IOToDiffArray IOArray
54 -- ...and strict unboxed DiffUArray, working only for elements
55 -- of primitive types but more compact and usually faster:
56 DiffUArray, -- = IOToDiffArray IOUArray
58 -- * Overloaded immutable array interface
60 -- | Module "Data.Array.IArray" provides the interface of diff arrays.
61 -- They are instances of class 'IArray'.
62 module Data.Array.IArray,
64 -- * Low-level interface
66 -- | These are really internal functions, but you will need them
67 -- to make further 'IArray' instances of various diff array types
68 -- (for either more 'MArray' types or more unboxed element types).
69 newDiffArray, readDiffArray, replaceDiffArray
73 ------------------------------------------------------------------------
79 import Data.Array.Base
80 import Data.Array.IArray
83 import Foreign.Ptr ( Ptr, FunPtr )
84 import Foreign.StablePtr ( StablePtr )
85 import Data.Int ( Int8, Int16, Int32, Int64 )
86 #ifdef __GLASGOW_HASKELL__
87 import Data.Word ( Word )
89 import Data.Word ( Word8, Word16, Word32, Word64 )
91 import System.IO.Unsafe ( unsafePerformIO )
92 import Control.Concurrent.MVar ( MVar, newMVar, takeMVar, putMVar, readMVar )
94 ------------------------------------------------------------------------
97 -- | An arbitrary 'MArray' type living in the 'IO' monad can be converted
100 newtype IOToDiffArray a i e =
101 DiffArray {varDiffArray :: MVar (DiffArrayData a i e)}
103 -- Internal representation: either a mutable array, or a link to
104 -- another diff array patched with a list of index+element pairs.
105 data DiffArrayData a i e = Current (a i e)
106 | Diff (IOToDiffArray a i e) [(Int, e)]
108 -- | Fully polymorphic lazy boxed diff array.
109 type DiffArray = IOToDiffArray IOArray
111 -- | Strict unboxed diff array, working only for elements
112 -- of primitive types but more compact and usually faster than 'DiffArray'.
113 type DiffUArray = IOToDiffArray IOUArray
115 -- Having 'MArray a e IO' in instance context would require
116 -- -fallow-undecidable-instances, so each instance is separate here.
118 ------------------------------------------------------------------------
119 -- Showing DiffArrays
121 instance (Ix ix, Show ix, Show e) => Show (DiffArray ix e) where
122 showsPrec = showsIArray
124 instance (Ix ix, Show ix) => Show (DiffUArray ix Char) where
125 showsPrec = showsIArray
127 instance (Ix ix, Show ix) => Show (DiffUArray ix Int) where
128 showsPrec = showsIArray
130 #ifdef __GLASGOW_HASKELL__
131 instance (Ix ix, Show ix) => Show (DiffUArray ix Word) where
132 showsPrec = showsIArray
135 instance (Ix ix, Show ix) => Show (DiffUArray ix Float) where
136 showsPrec = showsIArray
138 instance (Ix ix, Show ix) => Show (DiffUArray ix Double) where
139 showsPrec = showsIArray
141 instance (Ix ix, Show ix) => Show (DiffUArray ix Int8) where
142 showsPrec = showsIArray
144 instance (Ix ix, Show ix) => Show (DiffUArray ix Int16) where
145 showsPrec = showsIArray
147 instance (Ix ix, Show ix) => Show (DiffUArray ix Int32) where
148 showsPrec = showsIArray
150 instance (Ix ix, Show ix) => Show (DiffUArray ix Int64) where
151 showsPrec = showsIArray
153 instance (Ix ix, Show ix) => Show (DiffUArray ix Word8) where
154 showsPrec = showsIArray
156 instance (Ix ix, Show ix) => Show (DiffUArray ix Word16) where
157 showsPrec = showsIArray
159 instance (Ix ix, Show ix) => Show (DiffUArray ix Word32) where
160 showsPrec = showsIArray
162 instance (Ix ix, Show ix) => Show (DiffUArray ix Word64) where
163 showsPrec = showsIArray
165 ------------------------------------------------------------------------
168 instance HasBounds a => HasBounds (IOToDiffArray a) where
169 bounds a = unsafePerformIO $ boundsDiffArray a
171 instance IArray (IOToDiffArray IOArray) e where
172 unsafeArray lu ies = unsafePerformIO $ newDiffArray lu ies
173 unsafeAt a i = unsafePerformIO $ a `readDiffArray` i
174 unsafeReplace a ies = unsafePerformIO $ a `replaceDiffArray` ies
176 instance IArray (IOToDiffArray IOUArray) Char where
177 unsafeArray lu ies = unsafePerformIO $ newDiffArray lu ies
178 unsafeAt a i = unsafePerformIO $ a `readDiffArray` i
179 unsafeReplace a ies = unsafePerformIO $ a `replaceDiffArray` ies
181 instance IArray (IOToDiffArray IOUArray) Int where
182 unsafeArray lu ies = unsafePerformIO $ newDiffArray lu ies
183 unsafeAt a i = unsafePerformIO $ a `readDiffArray` i
184 unsafeReplace a ies = unsafePerformIO $ a `replaceDiffArray` ies
186 #ifdef __GLASGOW_HASKELL__
187 instance IArray (IOToDiffArray IOUArray) Word where
188 unsafeArray lu ies = unsafePerformIO $ newDiffArray lu ies
189 unsafeAt a i = unsafePerformIO $ a `readDiffArray` i
190 unsafeReplace a ies = unsafePerformIO $ a `replaceDiffArray` ies
193 instance IArray (IOToDiffArray IOUArray) (Ptr a) where
194 unsafeArray lu ies = unsafePerformIO $ newDiffArray lu ies
195 unsafeAt a i = unsafePerformIO $ a `readDiffArray` i
196 unsafeReplace a ies = unsafePerformIO $ a `replaceDiffArray` ies
198 instance IArray (IOToDiffArray IOUArray) (FunPtr a) where
199 unsafeArray lu ies = unsafePerformIO $ newDiffArray lu ies
200 unsafeAt a i = unsafePerformIO $ a `readDiffArray` i
201 unsafeReplace a ies = unsafePerformIO $ a `replaceDiffArray` ies
203 instance IArray (IOToDiffArray IOUArray) Float where
204 unsafeArray lu ies = unsafePerformIO $ newDiffArray lu ies
205 unsafeAt a i = unsafePerformIO $ a `readDiffArray` i
206 unsafeReplace a ies = unsafePerformIO $ a `replaceDiffArray` ies
208 instance IArray (IOToDiffArray IOUArray) Double where
209 unsafeArray lu ies = unsafePerformIO $ newDiffArray lu ies
210 unsafeAt a i = unsafePerformIO $ a `readDiffArray` i
211 unsafeReplace a ies = unsafePerformIO $ a `replaceDiffArray` ies
213 instance IArray (IOToDiffArray IOUArray) (StablePtr a) where
214 unsafeArray lu ies = unsafePerformIO $ newDiffArray lu ies
215 unsafeAt a i = unsafePerformIO $ a `readDiffArray` i
216 unsafeReplace a ies = unsafePerformIO $ a `replaceDiffArray` ies
218 instance IArray (IOToDiffArray IOUArray) Int8 where
219 unsafeArray lu ies = unsafePerformIO $ newDiffArray lu ies
220 unsafeAt a i = unsafePerformIO $ a `readDiffArray` i
221 unsafeReplace a ies = unsafePerformIO $ a `replaceDiffArray` ies
223 instance IArray (IOToDiffArray IOUArray) Int16 where
224 unsafeArray lu ies = unsafePerformIO $ newDiffArray lu ies
225 unsafeAt a i = unsafePerformIO $ a `readDiffArray` i
226 unsafeReplace a ies = unsafePerformIO $ a `replaceDiffArray` ies
228 instance IArray (IOToDiffArray IOUArray) Int32 where
229 unsafeArray lu ies = unsafePerformIO $ newDiffArray lu ies
230 unsafeAt a i = unsafePerformIO $ a `readDiffArray` i
231 unsafeReplace a ies = unsafePerformIO $ a `replaceDiffArray` ies
233 instance IArray (IOToDiffArray IOUArray) Int64 where
234 unsafeArray lu ies = unsafePerformIO $ newDiffArray lu ies
235 unsafeAt a i = unsafePerformIO $ a `readDiffArray` i
236 unsafeReplace a ies = unsafePerformIO $ a `replaceDiffArray` ies
238 instance IArray (IOToDiffArray IOUArray) Word8 where
239 unsafeArray lu ies = unsafePerformIO $ newDiffArray lu ies
240 unsafeAt a i = unsafePerformIO $ a `readDiffArray` i
241 unsafeReplace a ies = unsafePerformIO $ a `replaceDiffArray` ies
243 instance IArray (IOToDiffArray IOUArray) Word16 where
244 unsafeArray lu ies = unsafePerformIO $ newDiffArray lu ies
245 unsafeAt a i = unsafePerformIO $ a `readDiffArray` i
246 unsafeReplace a ies = unsafePerformIO $ a `replaceDiffArray` ies
248 instance IArray (IOToDiffArray IOUArray) Word32 where
249 unsafeArray lu ies = unsafePerformIO $ newDiffArray lu ies
250 unsafeAt a i = unsafePerformIO $ a `readDiffArray` i
251 unsafeReplace a ies = unsafePerformIO $ a `replaceDiffArray` ies
253 instance IArray (IOToDiffArray IOUArray) Word64 where
254 unsafeArray lu ies = unsafePerformIO $ newDiffArray lu ies
255 unsafeAt a i = unsafePerformIO $ a `readDiffArray` i
256 unsafeReplace a ies = unsafePerformIO $ a `replaceDiffArray` ies
260 ------------------------------------------------------------------------
261 -- The important stuff.
263 newDiffArray :: (MArray a e IO, Ix i)
266 -> IO (IOToDiffArray a i e)
267 newDiffArray (l,u) ies = do
269 sequence_ [unsafeWrite a i e | (i, e) <- ies]
270 var <- newMVar (Current a)
271 return (DiffArray var)
273 readDiffArray :: (MArray a e IO, Ix i)
274 => IOToDiffArray a i e
277 a `readDiffArray` i = do
278 d <- readMVar (varDiffArray a)
280 Current a' -> unsafeRead a' i
281 Diff a' ies -> maybe (readDiffArray a' i) return (lookup i ies)
283 replaceDiffArray :: (MArray a e IO, Ix i)
284 => IOToDiffArray a i e
286 -> IO (IOToDiffArray a i e)
287 a `replaceDiffArray` ies = do
288 d <- takeMVar (varDiffArray a)
290 Current a' -> case ies of
292 -- We don't do the copy when there is nothing to change
293 -- and this is the current version. But see below.
294 putMVar (varDiffArray a) d
297 diff <- sequence [do e <- unsafeRead a' i; return (i, e)
299 sequence_ [unsafeWrite a' i e | (i, e) <- ies]
300 var' <- newMVar (Current a')
301 putMVar (varDiffArray a) (Diff (DiffArray var') diff)
302 return (DiffArray var')
304 -- We still do the copy when there is nothing to change
305 -- but this is not the current version. So you can use
306 -- 'a // []' to make sure that the resulting array has
307 -- fast element access.
308 putMVar (varDiffArray a) d
309 a' <- thawDiffArray a
310 -- thawDiffArray gives a fresh array which we can
312 sequence_ [unsafeWrite a' i e | (i, e) <- ies]
313 var' <- newMVar (Current a')
314 return (DiffArray var')
316 boundsDiffArray :: (HasBounds a, Ix ix)
317 => IOToDiffArray a ix e
319 boundsDiffArray a = do
320 d <- readMVar (varDiffArray a)
322 Current a' -> return (bounds a')
323 Diff a' _ -> boundsDiffArray a'
325 freezeDiffArray :: (MArray a e IO, Ix ix)
327 -> IO (IOToDiffArray a ix e)
328 freezeDiffArray a = case bounds a of
330 a' <- newArray_ (l,u)
331 sequence_ [unsafeRead a i >>= unsafeWrite a' i | i <- [0 .. rangeSize (l,u) - 1]]
332 var <- newMVar (Current a')
333 return (DiffArray var)
336 "freeze/DiffArray" freeze = freezeDiffArray
339 -- unsafeFreezeDiffArray is really unsafe. Better don't use the old
340 -- array at all after freezing. The contents of the source array will
341 -- be changed when '//' is applied to the resulting array.
343 unsafeFreezeDiffArray :: (MArray a e IO, Ix ix)
345 -> IO (IOToDiffArray a ix e)
346 unsafeFreezeDiffArray a = do
347 var <- newMVar (Current a)
348 return (DiffArray var)
351 "unsafeFreeze/DiffArray" unsafeFreeze = unsafeFreezeDiffArray
354 thawDiffArray :: (MArray a e IO, Ix ix)
355 => IOToDiffArray a ix e
358 d <- readMVar (varDiffArray a)
360 Current a' -> case bounds a' of
362 a'' <- newArray_ (l,u)
363 sequence_ [unsafeRead a' i >>= unsafeWrite a'' i | i <- [0 .. rangeSize (l,u) - 1]]
366 a'' <- thawDiffArray a'
367 sequence_ [unsafeWrite a'' i e | (i, e) <- ies]
371 "thaw/DiffArray" thaw = thawDiffArray
374 -- unsafeThawDiffArray is really unsafe. Better don't use the old
375 -- array at all after thawing. The contents of the resulting array
376 -- will be changed when '//' is applied to the source array.
378 unsafeThawDiffArray :: (MArray a e IO, Ix ix)
379 => IOToDiffArray a ix e
381 unsafeThawDiffArray a = do
382 d <- readMVar (varDiffArray a)
384 Current a' -> return a'
386 a'' <- unsafeThawDiffArray a'
387 sequence_ [unsafeWrite a'' i e | (i, e) <- ies]
391 "unsafeThaw/DiffArray" unsafeThaw = unsafeThawDiffArray