1 -----------------------------------------------------------------------------
3 -- Module : Data.Array.Diff
4 -- Copyright : (c) The University of Glasgow 2001
5 -- License : BSD-style (see the file libraries/core/LICENSE)
7 -- Maintainer : libraries@haskell.org
8 -- Stability : experimental
9 -- Portability : non-portable
11 -- $Id: Diff.hs,v 1.1 2001/07/04 10:48:39 simonmar Exp $
13 -- Functional arrays with constant-time update.
15 -----------------------------------------------------------------------------
17 module Data.Array.Diff (
19 -- Diff arrays have 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). Accessing
32 -- 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 -- An arbitrary MArray type living in the IO monad can be converted
46 IOToDiffArray, -- data IOToDiffArray
47 -- (a :: * -> * -> *) -- internal mutable array
48 -- (i :: *) -- indices
49 -- (e :: *) -- elements
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 -- Module IArray provides the interface of diff arrays. They are
59 -- instances of class IArray.
60 module Data.Array.IArray,
62 -- These are really internal functions, but you will need them
63 -- to make further IArray instances of various DiffArrays (for
64 -- either more MArray types or more unboxed element types).
65 newDiffArray, readDiffArray, replaceDiffArray
69 ------------------------------------------------------------------------
75 import Data.Array.Base
76 import Data.Array.IArray
79 import Foreign.Ptr ( Ptr, FunPtr )
80 import Foreign.StablePtr ( StablePtr )
81 import Data.Int ( Int8, Int16, Int32, Int64 )
82 import Data.Word ( Word, Word8, Word16, Word32, Word64)
84 import System.IO.Unsafe ( unsafePerformIO )
85 import Control.Concurrent ( MVar, newMVar, takeMVar, putMVar, readMVar )
87 ------------------------------------------------------------------------
90 -- Convert an IO array type to a diff array.
91 newtype IOToDiffArray a i e =
92 DiffArray {varDiffArray :: MVar (DiffArrayData a i e)}
94 -- Internal representation: either a mutable array, or a link to
95 -- another diff array patched with a list of index+element pairs.
96 data DiffArrayData a i e = Current (a i e)
97 | Diff (IOToDiffArray a i e) [(Int, e)]
99 -- Type synonyms for two most important IO array types.
100 type DiffArray = IOToDiffArray IOArray
101 type DiffUArray = IOToDiffArray IOUArray
103 -- Having 'MArray a e IO' in instance context would require
104 -- -fallow-undecidable-instances, so each instance is separate here.
106 ------------------------------------------------------------------------
109 instance HasBounds a => HasBounds (IOToDiffArray a) where
110 bounds a = unsafePerformIO $ boundsDiffArray a
112 instance IArray (IOToDiffArray IOArray) e where
113 unsafeArray lu ies = unsafePerformIO $ newDiffArray lu ies
114 unsafeAt a i = unsafePerformIO $ a `readDiffArray` i
115 unsafeReplace a ies = unsafePerformIO $ a `replaceDiffArray` ies
117 instance IArray (IOToDiffArray IOUArray) Char where
118 unsafeArray lu ies = unsafePerformIO $ newDiffArray lu ies
119 unsafeAt a i = unsafePerformIO $ a `readDiffArray` i
120 unsafeReplace a ies = unsafePerformIO $ a `replaceDiffArray` ies
122 instance IArray (IOToDiffArray IOUArray) Int where
123 unsafeArray lu ies = unsafePerformIO $ newDiffArray lu ies
124 unsafeAt a i = unsafePerformIO $ a `readDiffArray` i
125 unsafeReplace a ies = unsafePerformIO $ a `replaceDiffArray` ies
127 instance IArray (IOToDiffArray IOUArray) Word where
128 unsafeArray lu ies = unsafePerformIO $ newDiffArray lu ies
129 unsafeAt a i = unsafePerformIO $ a `readDiffArray` i
130 unsafeReplace a ies = unsafePerformIO $ a `replaceDiffArray` ies
132 instance IArray (IOToDiffArray IOUArray) (Ptr a) where
133 unsafeArray lu ies = unsafePerformIO $ newDiffArray lu ies
134 unsafeAt a i = unsafePerformIO $ a `readDiffArray` i
135 unsafeReplace a ies = unsafePerformIO $ a `replaceDiffArray` ies
137 instance IArray (IOToDiffArray IOUArray) (FunPtr a) where
138 unsafeArray lu ies = unsafePerformIO $ newDiffArray lu ies
139 unsafeAt a i = unsafePerformIO $ a `readDiffArray` i
140 unsafeReplace a ies = unsafePerformIO $ a `replaceDiffArray` ies
142 instance IArray (IOToDiffArray IOUArray) Float where
143 unsafeArray lu ies = unsafePerformIO $ newDiffArray lu ies
144 unsafeAt a i = unsafePerformIO $ a `readDiffArray` i
145 unsafeReplace a ies = unsafePerformIO $ a `replaceDiffArray` ies
147 instance IArray (IOToDiffArray IOUArray) Double where
148 unsafeArray lu ies = unsafePerformIO $ newDiffArray lu ies
149 unsafeAt a i = unsafePerformIO $ a `readDiffArray` i
150 unsafeReplace a ies = unsafePerformIO $ a `replaceDiffArray` ies
152 instance IArray (IOToDiffArray IOUArray) (StablePtr a) where
153 unsafeArray lu ies = unsafePerformIO $ newDiffArray lu ies
154 unsafeAt a i = unsafePerformIO $ a `readDiffArray` i
155 unsafeReplace a ies = unsafePerformIO $ a `replaceDiffArray` ies
157 instance IArray (IOToDiffArray IOUArray) Int8 where
158 unsafeArray lu ies = unsafePerformIO $ newDiffArray lu ies
159 unsafeAt a i = unsafePerformIO $ a `readDiffArray` i
160 unsafeReplace a ies = unsafePerformIO $ a `replaceDiffArray` ies
162 instance IArray (IOToDiffArray IOUArray) Int16 where
163 unsafeArray lu ies = unsafePerformIO $ newDiffArray lu ies
164 unsafeAt a i = unsafePerformIO $ a `readDiffArray` i
165 unsafeReplace a ies = unsafePerformIO $ a `replaceDiffArray` ies
167 instance IArray (IOToDiffArray IOUArray) Int32 where
168 unsafeArray lu ies = unsafePerformIO $ newDiffArray lu ies
169 unsafeAt a i = unsafePerformIO $ a `readDiffArray` i
170 unsafeReplace a ies = unsafePerformIO $ a `replaceDiffArray` ies
172 instance IArray (IOToDiffArray IOUArray) Int64 where
173 unsafeArray lu ies = unsafePerformIO $ newDiffArray lu ies
174 unsafeAt a i = unsafePerformIO $ a `readDiffArray` i
175 unsafeReplace a ies = unsafePerformIO $ a `replaceDiffArray` ies
177 instance IArray (IOToDiffArray IOUArray) Word8 where
178 unsafeArray lu ies = unsafePerformIO $ newDiffArray lu ies
179 unsafeAt a i = unsafePerformIO $ a `readDiffArray` i
180 unsafeReplace a ies = unsafePerformIO $ a `replaceDiffArray` ies
182 instance IArray (IOToDiffArray IOUArray) Word16 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) Word32 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) Word64 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 ------------------------------------------------------------------------
198 -- The important stuff.
200 newDiffArray :: (MArray a e IO, Ix i)
203 -> IO (IOToDiffArray a i e)
204 newDiffArray (l,u) ies = do
206 sequence_ [unsafeWrite a i e | (i, e) <- ies]
207 var <- newMVar (Current a)
208 return (DiffArray var)
210 readDiffArray :: (MArray a e IO, Ix i)
211 => IOToDiffArray a i e
214 a `readDiffArray` i = do
215 d <- readMVar (varDiffArray a)
217 Current a' -> unsafeRead a' i
218 Diff a' ies -> maybe (readDiffArray a' i) return (lookup i ies)
220 replaceDiffArray :: (MArray a e IO, Ix i)
221 => IOToDiffArray a i e
223 -> IO (IOToDiffArray a i e)
224 a `replaceDiffArray` ies = do
225 d <- takeMVar (varDiffArray a)
227 Current a' -> case ies of
229 -- We don't do the copy when there is nothing to change
230 -- and this is the current version. But see below.
231 putMVar (varDiffArray a) d
234 diff <- sequence [do e <- unsafeRead a' i; return (i, e)
236 sequence_ [unsafeWrite a' i e | (i, e) <- ies]
237 var' <- newMVar (Current a')
238 putMVar (varDiffArray a) (Diff (DiffArray var') diff)
239 return (DiffArray var')
241 -- We still do the copy when there is nothing to change
242 -- but this is not the current version. So you can use
243 -- 'a // []' to make sure that the resulting array has
244 -- fast element access.
245 putMVar (varDiffArray a) d
246 a' <- thawDiffArray a
247 -- thawDiffArray gives a fresh array which we can
249 sequence_ [unsafeWrite a' i e | (i, e) <- ies]
250 var' <- newMVar (Current a')
251 return (DiffArray var')
253 boundsDiffArray :: (HasBounds a, Ix ix)
254 => IOToDiffArray a ix e
256 boundsDiffArray a = do
257 d <- readMVar (varDiffArray a)
259 Current a' -> return (bounds a')
260 Diff a' _ -> boundsDiffArray a'
262 freezeDiffArray :: (MArray a e IO, Ix ix)
264 -> IO (IOToDiffArray a ix e)
265 freezeDiffArray a | (l,u) <- bounds a = do
266 a' <- newArray_ (l,u)
267 sequence_ [unsafeRead a i >>= unsafeWrite a' i | i <- [0 .. rangeSize (l,u) - 1]]
268 var <- newMVar (Current a')
269 return (DiffArray var)
272 "freeze/DiffArray" freeze = freezeDiffArray
275 -- unsafeFreezeDiffArray is really unsafe. Better don't use the old
276 -- array at all after freezing. The contents of the source array will
277 -- be changed when '//' is applied to the resulting array.
279 unsafeFreezeDiffArray :: (MArray a e IO, Ix ix)
281 -> IO (IOToDiffArray a ix e)
282 unsafeFreezeDiffArray a = do
283 var <- newMVar (Current a)
284 return (DiffArray var)
287 "unsafeFreeze/DiffArray" unsafeFreeze = unsafeFreezeDiffArray
290 thawDiffArray :: (MArray a e IO, Ix ix)
291 => IOToDiffArray a ix e
294 d <- readMVar (varDiffArray a)
296 Current a' | (l,u) <- bounds a' -> do
297 a'' <- newArray_ (l,u)
298 sequence_ [unsafeRead a' i >>= unsafeWrite a'' i | i <- [0 .. rangeSize (l,u) - 1]]
301 a'' <- thawDiffArray a'
302 sequence_ [unsafeWrite a'' i e | (i, e) <- ies]
306 "thaw/DiffArray" thaw = thawDiffArray
309 -- unsafeThawDiffArray is really unsafe. Better don't use the old
310 -- array at all after thawing. The contents of the resulting array
311 -- will be changed when '//' is applied to the source array.
313 unsafeThawDiffArray :: (MArray a e IO, Ix ix)
314 => IOToDiffArray a ix e
316 unsafeThawDiffArray a = do
317 d <- readMVar (varDiffArray a)
319 Current a' -> return a'
321 a'' <- unsafeThawDiffArray a'
322 sequence_ [unsafeWrite a'' i e | (i, e) <- ies]
326 "unsafeThaw/DiffArray" unsafeThaw = unsafeThawDiffArray