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 (
17 -- Diff arrays have immutable interface, but rely on internal
18 -- updates in place to provide fast functional update operator
21 -- When the '//' operator is applied to a diff array, its contents
22 -- are physically updated in place. The old array silently changes
23 -- its representation without changing the visible behavior:
24 -- it stores a link to the new current array along with the
25 -- difference to be applied to get the old contents.
27 -- So if a diff array is used in a single-threaded style,
28 -- i.e. after '//' application the old version is no longer used,
29 -- 'a!i' takes O(1) time and 'a // d' takes O(length d). Accessing
30 -- elements of older versions gradually becomes slower.
32 -- Updating an array which is not current makes a physical copy.
33 -- The resulting array is unlinked from the old family. So you
34 -- can obtain a version which is guaranteed to be current and
35 -- thus have fast element access by 'a // []'.
37 -- Possible improvement for the future (not implemented now):
38 -- make it possible to say "I will make an update now, but when
39 -- I later return to the old version, I want it to mutate back
40 -- instead of being copied".
42 -- An arbitrary MArray type living in the IO monad can be converted
44 IOToDiffArray, -- data IOToDiffArray
45 -- (a :: * -> * -> *) -- internal mutable array
46 -- (i :: *) -- indices
47 -- (e :: *) -- elements
49 -- Two most important diff array types are fully polymorphic
50 -- lazy boxed DiffArray:
51 DiffArray, -- = IOToDiffArray IOArray
52 -- ...and strict unboxed DiffUArray, working only for elements
53 -- of primitive types but more compact and usually faster:
54 DiffUArray, -- = IOToDiffArray IOUArray
56 -- Module IArray provides the interface of diff arrays. They are
57 -- instances of class IArray.
58 module Data.Array.IArray,
60 -- These are really internal functions, but you will need them
61 -- to make further IArray instances of various DiffArrays (for
62 -- either more MArray types or more unboxed element types).
63 newDiffArray, readDiffArray, replaceDiffArray
67 ------------------------------------------------------------------------
73 import Data.Array.Base
74 import Data.Array.IArray
77 import Foreign.Ptr ( Ptr, FunPtr )
78 import Foreign.StablePtr ( StablePtr )
79 import Data.Int ( Int8, Int16, Int32, Int64 )
80 #ifdef __GLASGOW_HASKELL__
81 import Data.Word ( Word )
83 import Data.Word ( Word8, Word16, Word32, Word64 )
85 import System.IO.Unsafe ( unsafePerformIO )
86 import Control.Concurrent.MVar ( MVar, newMVar, takeMVar, putMVar, readMVar )
88 ------------------------------------------------------------------------
91 -- Convert an IO array type to a diff array.
92 newtype IOToDiffArray a i e =
93 DiffArray {varDiffArray :: MVar (DiffArrayData a i e)}
95 -- Internal representation: either a mutable array, or a link to
96 -- another diff array patched with a list of index+element pairs.
97 data DiffArrayData a i e = Current (a i e)
98 | Diff (IOToDiffArray a i e) [(Int, e)]
100 -- Type synonyms for two most important IO array types.
101 type DiffArray = IOToDiffArray IOArray
102 type DiffUArray = IOToDiffArray IOUArray
104 -- Having 'MArray a e IO' in instance context would require
105 -- -fallow-undecidable-instances, so each instance is separate here.
107 ------------------------------------------------------------------------
108 -- Showing DiffArrays
110 instance (Ix ix, Show ix, Show e) => Show (DiffArray ix e) where
111 showsPrec = showsIArray
113 instance (Ix ix, Show ix) => Show (DiffUArray ix Char) where
114 showsPrec = showsIArray
116 instance (Ix ix, Show ix) => Show (DiffUArray ix Int) where
117 showsPrec = showsIArray
119 #ifdef __GLASGOW_HASKELL__
120 instance (Ix ix, Show ix) => Show (DiffUArray ix Word) where
121 showsPrec = showsIArray
124 instance (Ix ix, Show ix) => Show (DiffUArray ix Float) where
125 showsPrec = showsIArray
127 instance (Ix ix, Show ix) => Show (DiffUArray ix Double) where
128 showsPrec = showsIArray
130 instance (Ix ix, Show ix) => Show (DiffUArray ix Int8) where
131 showsPrec = showsIArray
133 instance (Ix ix, Show ix) => Show (DiffUArray ix Int16) where
134 showsPrec = showsIArray
136 instance (Ix ix, Show ix) => Show (DiffUArray ix Int32) where
137 showsPrec = showsIArray
139 instance (Ix ix, Show ix) => Show (DiffUArray ix Int64) where
140 showsPrec = showsIArray
142 instance (Ix ix, Show ix) => Show (DiffUArray ix Word8) where
143 showsPrec = showsIArray
145 instance (Ix ix, Show ix) => Show (DiffUArray ix Word16) where
146 showsPrec = showsIArray
148 instance (Ix ix, Show ix) => Show (DiffUArray ix Word32) where
149 showsPrec = showsIArray
151 instance (Ix ix, Show ix) => Show (DiffUArray ix Word64) where
152 showsPrec = showsIArray
154 ------------------------------------------------------------------------
157 instance HasBounds a => HasBounds (IOToDiffArray a) where
158 bounds a = unsafePerformIO $ boundsDiffArray a
160 instance IArray (IOToDiffArray IOArray) e where
161 unsafeArray lu ies = unsafePerformIO $ newDiffArray lu ies
162 unsafeAt a i = unsafePerformIO $ a `readDiffArray` i
163 unsafeReplace a ies = unsafePerformIO $ a `replaceDiffArray` ies
165 instance IArray (IOToDiffArray IOUArray) Char where
166 unsafeArray lu ies = unsafePerformIO $ newDiffArray lu ies
167 unsafeAt a i = unsafePerformIO $ a `readDiffArray` i
168 unsafeReplace a ies = unsafePerformIO $ a `replaceDiffArray` ies
170 instance IArray (IOToDiffArray IOUArray) Int where
171 unsafeArray lu ies = unsafePerformIO $ newDiffArray lu ies
172 unsafeAt a i = unsafePerformIO $ a `readDiffArray` i
173 unsafeReplace a ies = unsafePerformIO $ a `replaceDiffArray` ies
175 #ifdef __GLASGOW_HASKELL__
176 instance IArray (IOToDiffArray IOUArray) Word 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
182 instance IArray (IOToDiffArray IOUArray) (Ptr a) where
183 unsafeArray lu ies = unsafePerformIO $ newDiffArray lu ies
184 unsafeAt a i = unsafePerformIO $ a `readDiffArray` i
185 unsafeReplace a ies = unsafePerformIO $ a `replaceDiffArray` ies
187 instance IArray (IOToDiffArray IOUArray) (FunPtr a) 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
192 instance IArray (IOToDiffArray IOUArray) Float where
193 unsafeArray lu ies = unsafePerformIO $ newDiffArray lu ies
194 unsafeAt a i = unsafePerformIO $ a `readDiffArray` i
195 unsafeReplace a ies = unsafePerformIO $ a `replaceDiffArray` ies
197 instance IArray (IOToDiffArray IOUArray) Double where
198 unsafeArray lu ies = unsafePerformIO $ newDiffArray lu ies
199 unsafeAt a i = unsafePerformIO $ a `readDiffArray` i
200 unsafeReplace a ies = unsafePerformIO $ a `replaceDiffArray` ies
202 instance IArray (IOToDiffArray IOUArray) (StablePtr a) where
203 unsafeArray lu ies = unsafePerformIO $ newDiffArray lu ies
204 unsafeAt a i = unsafePerformIO $ a `readDiffArray` i
205 unsafeReplace a ies = unsafePerformIO $ a `replaceDiffArray` ies
207 instance IArray (IOToDiffArray IOUArray) Int8 where
208 unsafeArray lu ies = unsafePerformIO $ newDiffArray lu ies
209 unsafeAt a i = unsafePerformIO $ a `readDiffArray` i
210 unsafeReplace a ies = unsafePerformIO $ a `replaceDiffArray` ies
212 instance IArray (IOToDiffArray IOUArray) Int16 where
213 unsafeArray lu ies = unsafePerformIO $ newDiffArray lu ies
214 unsafeAt a i = unsafePerformIO $ a `readDiffArray` i
215 unsafeReplace a ies = unsafePerformIO $ a `replaceDiffArray` ies
217 instance IArray (IOToDiffArray IOUArray) Int32 where
218 unsafeArray lu ies = unsafePerformIO $ newDiffArray lu ies
219 unsafeAt a i = unsafePerformIO $ a `readDiffArray` i
220 unsafeReplace a ies = unsafePerformIO $ a `replaceDiffArray` ies
222 instance IArray (IOToDiffArray IOUArray) Int64 where
223 unsafeArray lu ies = unsafePerformIO $ newDiffArray lu ies
224 unsafeAt a i = unsafePerformIO $ a `readDiffArray` i
225 unsafeReplace a ies = unsafePerformIO $ a `replaceDiffArray` ies
227 instance IArray (IOToDiffArray IOUArray) Word8 where
228 unsafeArray lu ies = unsafePerformIO $ newDiffArray lu ies
229 unsafeAt a i = unsafePerformIO $ a `readDiffArray` i
230 unsafeReplace a ies = unsafePerformIO $ a `replaceDiffArray` ies
232 instance IArray (IOToDiffArray IOUArray) Word16 where
233 unsafeArray lu ies = unsafePerformIO $ newDiffArray lu ies
234 unsafeAt a i = unsafePerformIO $ a `readDiffArray` i
235 unsafeReplace a ies = unsafePerformIO $ a `replaceDiffArray` ies
237 instance IArray (IOToDiffArray IOUArray) Word32 where
238 unsafeArray lu ies = unsafePerformIO $ newDiffArray lu ies
239 unsafeAt a i = unsafePerformIO $ a `readDiffArray` i
240 unsafeReplace a ies = unsafePerformIO $ a `replaceDiffArray` ies
242 instance IArray (IOToDiffArray IOUArray) Word64 where
243 unsafeArray lu ies = unsafePerformIO $ newDiffArray lu ies
244 unsafeAt a i = unsafePerformIO $ a `readDiffArray` i
245 unsafeReplace a ies = unsafePerformIO $ a `replaceDiffArray` ies
249 ------------------------------------------------------------------------
250 -- The important stuff.
252 newDiffArray :: (MArray a e IO, Ix i)
255 -> IO (IOToDiffArray a i e)
256 newDiffArray (l,u) ies = do
258 sequence_ [unsafeWrite a i e | (i, e) <- ies]
259 var <- newMVar (Current a)
260 return (DiffArray var)
262 readDiffArray :: (MArray a e IO, Ix i)
263 => IOToDiffArray a i e
266 a `readDiffArray` i = do
267 d <- readMVar (varDiffArray a)
269 Current a' -> unsafeRead a' i
270 Diff a' ies -> maybe (readDiffArray a' i) return (lookup i ies)
272 replaceDiffArray :: (MArray a e IO, Ix i)
273 => IOToDiffArray a i e
275 -> IO (IOToDiffArray a i e)
276 a `replaceDiffArray` ies = do
277 d <- takeMVar (varDiffArray a)
279 Current a' -> case ies of
281 -- We don't do the copy when there is nothing to change
282 -- and this is the current version. But see below.
283 putMVar (varDiffArray a) d
286 diff <- sequence [do e <- unsafeRead a' i; return (i, e)
288 sequence_ [unsafeWrite a' i e | (i, e) <- ies]
289 var' <- newMVar (Current a')
290 putMVar (varDiffArray a) (Diff (DiffArray var') diff)
291 return (DiffArray var')
293 -- We still do the copy when there is nothing to change
294 -- but this is not the current version. So you can use
295 -- 'a // []' to make sure that the resulting array has
296 -- fast element access.
297 putMVar (varDiffArray a) d
298 a' <- thawDiffArray a
299 -- thawDiffArray gives a fresh array which we can
301 sequence_ [unsafeWrite a' i e | (i, e) <- ies]
302 var' <- newMVar (Current a')
303 return (DiffArray var')
305 boundsDiffArray :: (HasBounds a, Ix ix)
306 => IOToDiffArray a ix e
308 boundsDiffArray a = do
309 d <- readMVar (varDiffArray a)
311 Current a' -> return (bounds a')
312 Diff a' _ -> boundsDiffArray a'
314 freezeDiffArray :: (MArray a e IO, Ix ix)
316 -> IO (IOToDiffArray a ix e)
317 freezeDiffArray a = case bounds a of
319 a' <- newArray_ (l,u)
320 sequence_ [unsafeRead a i >>= unsafeWrite a' i | i <- [0 .. rangeSize (l,u) - 1]]
321 var <- newMVar (Current a')
322 return (DiffArray var)
325 "freeze/DiffArray" freeze = freezeDiffArray
328 -- unsafeFreezeDiffArray is really unsafe. Better don't use the old
329 -- array at all after freezing. The contents of the source array will
330 -- be changed when '//' is applied to the resulting array.
332 unsafeFreezeDiffArray :: (MArray a e IO, Ix ix)
334 -> IO (IOToDiffArray a ix e)
335 unsafeFreezeDiffArray a = do
336 var <- newMVar (Current a)
337 return (DiffArray var)
340 "unsafeFreeze/DiffArray" unsafeFreeze = unsafeFreezeDiffArray
343 thawDiffArray :: (MArray a e IO, Ix ix)
344 => IOToDiffArray a ix e
347 d <- readMVar (varDiffArray a)
349 Current a' -> case bounds a' of
351 a'' <- newArray_ (l,u)
352 sequence_ [unsafeRead a' i >>= unsafeWrite a'' i | i <- [0 .. rangeSize (l,u) - 1]]
355 a'' <- thawDiffArray a'
356 sequence_ [unsafeWrite a'' i e | (i, e) <- ies]
360 "thaw/DiffArray" thaw = thawDiffArray
363 -- unsafeThawDiffArray is really unsafe. Better don't use the old
364 -- array at all after thawing. The contents of the resulting array
365 -- will be changed when '//' is applied to the source array.
367 unsafeThawDiffArray :: (MArray a e IO, Ix ix)
368 => IOToDiffArray a ix e
370 unsafeThawDiffArray a = do
371 d <- readMVar (varDiffArray a)
373 Current a' -> return a'
375 a'' <- unsafeThawDiffArray a'
376 sequence_ [unsafeWrite a'' i e | (i, e) <- ies]
380 "unsafeThaw/DiffArray" unsafeThaw = unsafeThawDiffArray