/testing/introDeepSeq/Data/Array/Diff.hs

https://github.com/huiqing/HaRe · Haskell · 423 lines · 244 code · 76 blank · 103 comment · 6 complexity · d9f1c862a52c6e5c31d723b90f6ee836 MD5 · raw file

  1. -----------------------------------------------------------------------------
  2. -- |
  3. -- Module : Data.Array.Diff
  4. -- Copyright : (c) The University of Glasgow 2001
  5. -- License : BSD-style (see the file libraries/base/LICENSE)
  6. --
  7. -- Maintainer : libraries@haskell.org
  8. -- Stability : experimental
  9. -- Portability : non-portable (uses Data.Array.IArray)
  10. --
  11. -- Functional arrays with constant-time update.
  12. --
  13. -----------------------------------------------------------------------------
  14. module Data.Array.Diff (
  15. -- * Diff array types
  16. -- | Diff arrays have an immutable interface, but rely on internal
  17. -- updates in place to provide fast functional update operator
  18. -- '//'.
  19. --
  20. -- When the '//' operator is applied to a diff array, its contents
  21. -- are physically updated in place. The old array silently changes
  22. -- its representation without changing the visible behavior:
  23. -- it stores a link to the new current array along with the
  24. -- difference to be applied to get the old contents.
  25. --
  26. -- So if a diff array is used in a single-threaded style,
  27. -- i.e. after '//' application the old version is no longer used,
  28. -- @a'!'i@ takes O(1) time and @a '//' d@ takes O(@length d@).
  29. -- Accessing elements of older versions gradually becomes slower.
  30. --
  31. -- Updating an array which is not current makes a physical copy.
  32. -- The resulting array is unlinked from the old family. So you
  33. -- can obtain a version which is guaranteed to be current and
  34. -- thus have fast element access by @a '//' []@.
  35. -- Possible improvement for the future (not implemented now):
  36. -- make it possible to say "I will make an update now, but when
  37. -- I later return to the old version, I want it to mutate back
  38. -- instead of being copied".
  39. IOToDiffArray, -- data IOToDiffArray
  40. -- (a :: * -> * -> *) -- internal mutable array
  41. -- (i :: *) -- indices
  42. -- (e :: *) -- elements
  43. -- | Type synonyms for the two most important IO array types.
  44. -- Two most important diff array types are fully polymorphic
  45. -- lazy boxed DiffArray:
  46. DiffArray, -- = IOToDiffArray IOArray
  47. -- ...and strict unboxed DiffUArray, working only for elements
  48. -- of primitive types but more compact and usually faster:
  49. DiffUArray, -- = IOToDiffArray IOUArray
  50. -- * Overloaded immutable array interface
  51. -- | Module "Data.Array.IArray" provides the interface of diff arrays.
  52. -- They are instances of class 'IArray'.
  53. module Data.Array.IArray,
  54. -- * Low-level interface
  55. -- | These are really internal functions, but you will need them
  56. -- to make further 'IArray' instances of various diff array types
  57. -- (for either more 'MArray' types or more unboxed element types).
  58. newDiffArray, readDiffArray, replaceDiffArray
  59. )
  60. where
  61. ------------------------------------------------------------------------
  62. -- Imports.
  63. import Prelude
  64. import Data.Ix
  65. import Data.Array.Base
  66. import Data.Array.IArray
  67. import Data.Array.IO
  68. import Foreign.Ptr ( Ptr, FunPtr )
  69. import Foreign.StablePtr ( StablePtr )
  70. import Data.Int ( Int8, Int16, Int32, Int64 )
  71. import Data.Word ( Word, Word8, Word16, Word32, Word64 )
  72. import System.IO.Unsafe ( unsafePerformIO )
  73. import Control.Exception ( evaluate )
  74. import Control.Concurrent.MVar ( MVar, newMVar, takeMVar, putMVar, readMVar )
  75. ------------------------------------------------------------------------
  76. -- Diff array types.
  77. -- | An arbitrary 'MArray' type living in the 'IO' monad can be converted
  78. -- to a diff array.
  79. newtype IOToDiffArray a i e =
  80. DiffArray {varDiffArray :: MVar (DiffArrayData a i e)}
  81. -- Internal representation: either a mutable array, or a link to
  82. -- another diff array patched with a list of index+element pairs.
  83. data DiffArrayData a i e = Current (a i e)
  84. | Diff (IOToDiffArray a i e) [(Int, e)]
  85. -- | Fully polymorphic lazy boxed diff array.
  86. type DiffArray = IOToDiffArray IOArray
  87. -- | Strict unboxed diff array, working only for elements
  88. -- of primitive types but more compact and usually faster than 'DiffArray'.
  89. type DiffUArray = IOToDiffArray IOUArray
  90. -- Having 'MArray a e IO' in instance context would require
  91. -- -fallow-undecidable-instances, so each instance is separate here.
  92. ------------------------------------------------------------------------
  93. -- Showing DiffArrays
  94. instance (Ix ix, Show ix, Show e) => Show (DiffArray ix e) where
  95. showsPrec = showsIArray
  96. instance (Ix ix, Show ix) => Show (DiffUArray ix Char) where
  97. showsPrec = showsIArray
  98. instance (Ix ix, Show ix) => Show (DiffUArray ix Int) where
  99. showsPrec = showsIArray
  100. instance (Ix ix, Show ix) => Show (DiffUArray ix Word) where
  101. showsPrec = showsIArray
  102. instance (Ix ix, Show ix) => Show (DiffUArray ix Float) where
  103. showsPrec = showsIArray
  104. instance (Ix ix, Show ix) => Show (DiffUArray ix Double) where
  105. showsPrec = showsIArray
  106. instance (Ix ix, Show ix) => Show (DiffUArray ix Int8) where
  107. showsPrec = showsIArray
  108. instance (Ix ix, Show ix) => Show (DiffUArray ix Int16) where
  109. showsPrec = showsIArray
  110. instance (Ix ix, Show ix) => Show (DiffUArray ix Int32) where
  111. showsPrec = showsIArray
  112. instance (Ix ix, Show ix) => Show (DiffUArray ix Int64) where
  113. showsPrec = showsIArray
  114. instance (Ix ix, Show ix) => Show (DiffUArray ix Word8) where
  115. showsPrec = showsIArray
  116. instance (Ix ix, Show ix) => Show (DiffUArray ix Word16) where
  117. showsPrec = showsIArray
  118. instance (Ix ix, Show ix) => Show (DiffUArray ix Word32) where
  119. showsPrec = showsIArray
  120. instance (Ix ix, Show ix) => Show (DiffUArray ix Word64) where
  121. showsPrec = showsIArray
  122. ------------------------------------------------------------------------
  123. -- Boring instances.
  124. instance IArray (IOToDiffArray IOArray) e where
  125. bounds a = unsafePerformIO $ boundsDiffArray a
  126. unsafeArray lu ies = unsafePerformIO $ newDiffArray lu ies
  127. unsafeAt a i = unsafePerformIO $ a `readDiffArray` i
  128. unsafeReplace a ies = unsafePerformIO $ a `replaceDiffArray1` ies
  129. instance IArray (IOToDiffArray IOUArray) Char where
  130. bounds a = unsafePerformIO $ boundsDiffArray a
  131. unsafeArray lu ies = unsafePerformIO $ newDiffArray lu ies
  132. unsafeAt a i = unsafePerformIO $ a `readDiffArray` i
  133. unsafeReplace a ies = unsafePerformIO $ a `replaceDiffArray2` ies
  134. instance IArray (IOToDiffArray IOUArray) Int where
  135. bounds a = unsafePerformIO $ boundsDiffArray a
  136. unsafeArray lu ies = unsafePerformIO $ newDiffArray lu ies
  137. unsafeAt a i = unsafePerformIO $ a `readDiffArray` i
  138. unsafeReplace a ies = unsafePerformIO $ a `replaceDiffArray2` ies
  139. instance IArray (IOToDiffArray IOUArray) Word where
  140. bounds a = unsafePerformIO $ boundsDiffArray a
  141. unsafeArray lu ies = unsafePerformIO $ newDiffArray lu ies
  142. unsafeAt a i = unsafePerformIO $ a `readDiffArray` i
  143. unsafeReplace a ies = unsafePerformIO $ a `replaceDiffArray2` ies
  144. instance IArray (IOToDiffArray IOUArray) (Ptr a) where
  145. bounds a = unsafePerformIO $ boundsDiffArray a
  146. unsafeArray lu ies = unsafePerformIO $ newDiffArray lu ies
  147. unsafeAt a i = unsafePerformIO $ a `readDiffArray` i
  148. unsafeReplace a ies = unsafePerformIO $ a `replaceDiffArray2` ies
  149. instance IArray (IOToDiffArray IOUArray) (FunPtr a) where
  150. bounds a = unsafePerformIO $ boundsDiffArray a
  151. unsafeArray lu ies = unsafePerformIO $ newDiffArray lu ies
  152. unsafeAt a i = unsafePerformIO $ a `readDiffArray` i
  153. unsafeReplace a ies = unsafePerformIO $ a `replaceDiffArray2` ies
  154. instance IArray (IOToDiffArray IOUArray) Float where
  155. bounds a = unsafePerformIO $ boundsDiffArray a
  156. unsafeArray lu ies = unsafePerformIO $ newDiffArray lu ies
  157. unsafeAt a i = unsafePerformIO $ a `readDiffArray` i
  158. unsafeReplace a ies = unsafePerformIO $ a `replaceDiffArray2` ies
  159. instance IArray (IOToDiffArray IOUArray) Double where
  160. bounds a = unsafePerformIO $ boundsDiffArray a
  161. unsafeArray lu ies = unsafePerformIO $ newDiffArray lu ies
  162. unsafeAt a i = unsafePerformIO $ a `readDiffArray` i
  163. unsafeReplace a ies = unsafePerformIO $ a `replaceDiffArray2` ies
  164. instance IArray (IOToDiffArray IOUArray) (StablePtr a) where
  165. bounds a = unsafePerformIO $ boundsDiffArray a
  166. unsafeArray lu ies = unsafePerformIO $ newDiffArray lu ies
  167. unsafeAt a i = unsafePerformIO $ a `readDiffArray` i
  168. unsafeReplace a ies = unsafePerformIO $ a `replaceDiffArray2` ies
  169. instance IArray (IOToDiffArray IOUArray) Int8 where
  170. bounds a = unsafePerformIO $ boundsDiffArray a
  171. unsafeArray lu ies = unsafePerformIO $ newDiffArray lu ies
  172. unsafeAt a i = unsafePerformIO $ a `readDiffArray` i
  173. unsafeReplace a ies = unsafePerformIO $ a `replaceDiffArray2` ies
  174. instance IArray (IOToDiffArray IOUArray) Int16 where
  175. bounds a = unsafePerformIO $ boundsDiffArray a
  176. unsafeArray lu ies = unsafePerformIO $ newDiffArray lu ies
  177. unsafeAt a i = unsafePerformIO $ a `readDiffArray` i
  178. unsafeReplace a ies = unsafePerformIO $ a `replaceDiffArray2` ies
  179. instance IArray (IOToDiffArray IOUArray) Int32 where
  180. bounds a = unsafePerformIO $ boundsDiffArray a
  181. unsafeArray lu ies = unsafePerformIO $ newDiffArray lu ies
  182. unsafeAt a i = unsafePerformIO $ a `readDiffArray` i
  183. unsafeReplace a ies = unsafePerformIO $ a `replaceDiffArray2` ies
  184. instance IArray (IOToDiffArray IOUArray) Int64 where
  185. bounds a = unsafePerformIO $ boundsDiffArray a
  186. unsafeArray lu ies = unsafePerformIO $ newDiffArray lu ies
  187. unsafeAt a i = unsafePerformIO $ a `readDiffArray` i
  188. unsafeReplace a ies = unsafePerformIO $ a `replaceDiffArray2` ies
  189. instance IArray (IOToDiffArray IOUArray) Word8 where
  190. bounds a = unsafePerformIO $ boundsDiffArray a
  191. unsafeArray lu ies = unsafePerformIO $ newDiffArray lu ies
  192. unsafeAt a i = unsafePerformIO $ a `readDiffArray` i
  193. unsafeReplace a ies = unsafePerformIO $ a `replaceDiffArray2` ies
  194. instance IArray (IOToDiffArray IOUArray) Word16 where
  195. bounds a = unsafePerformIO $ boundsDiffArray a
  196. unsafeArray lu ies = unsafePerformIO $ newDiffArray lu ies
  197. unsafeAt a i = unsafePerformIO $ a `readDiffArray` i
  198. unsafeReplace a ies = unsafePerformIO $ a `replaceDiffArray2` ies
  199. instance IArray (IOToDiffArray IOUArray) Word32 where
  200. bounds a = unsafePerformIO $ boundsDiffArray a
  201. unsafeArray lu ies = unsafePerformIO $ newDiffArray lu ies
  202. unsafeAt a i = unsafePerformIO $ a `readDiffArray` i
  203. unsafeReplace a ies = unsafePerformIO $ a `replaceDiffArray2` ies
  204. instance IArray (IOToDiffArray IOUArray) Word64 where
  205. bounds a = unsafePerformIO $ boundsDiffArray a
  206. unsafeArray lu ies = unsafePerformIO $ newDiffArray lu ies
  207. unsafeAt a i = unsafePerformIO $ a `readDiffArray` i
  208. unsafeReplace a ies = unsafePerformIO $ a `replaceDiffArray2` ies
  209. ------------------------------------------------------------------------
  210. -- The important stuff.
  211. newDiffArray :: (MArray a e IO, Ix i)
  212. => (i,i)
  213. -> [(Int, e)]
  214. -> IO (IOToDiffArray a i e)
  215. newDiffArray (l,u) ies = do
  216. a <- newArray_ (l,u)
  217. sequence_ [unsafeWrite a i e | (i, e) <- ies]
  218. var <- newMVar (Current a)
  219. return (DiffArray var)
  220. readDiffArray :: (MArray a e IO, Ix i)
  221. => IOToDiffArray a i e
  222. -> Int
  223. -> IO e
  224. a `readDiffArray` i = do
  225. d <- readMVar (varDiffArray a)
  226. case d of
  227. Current a' -> unsafeRead a' i
  228. Diff a' ies -> maybe (readDiffArray a' i) return (lookup i ies)
  229. replaceDiffArray :: (MArray a e IO, Ix i)
  230. => IOToDiffArray a i e
  231. -> [(Int, e)]
  232. -> IO (IOToDiffArray a i e)
  233. a `replaceDiffArray` ies = do
  234. d <- takeMVar (varDiffArray a)
  235. case d of
  236. Current a' -> case ies of
  237. [] -> do
  238. -- We don't do the copy when there is nothing to change
  239. -- and this is the current version. But see below.
  240. putMVar (varDiffArray a) d
  241. return a
  242. _:_ -> do
  243. diff <- sequence [do e <- unsafeRead a' i; return (i, e)
  244. | (i, _) <- ies]
  245. sequence_ [unsafeWrite a' i e | (i, e) <- ies]
  246. var' <- newMVar (Current a')
  247. putMVar (varDiffArray a) (Diff (DiffArray var') diff)
  248. return (DiffArray var')
  249. Diff _ _ -> do
  250. -- We still do the copy when there is nothing to change
  251. -- but this is not the current version. So you can use
  252. -- 'a // []' to make sure that the resulting array has
  253. -- fast element access.
  254. putMVar (varDiffArray a) d
  255. a' <- thawDiffArray a
  256. -- thawDiffArray gives a fresh array which we can
  257. -- safely mutate.
  258. sequence_ [unsafeWrite a' i e | (i, e) <- ies]
  259. var' <- newMVar (Current a')
  260. return (DiffArray var')
  261. -- The elements of the diff list might recursively reference the
  262. -- array, so we must seq them before taking the MVar to avoid
  263. -- deadlock.
  264. replaceDiffArray1 :: (MArray a e IO, Ix i)
  265. => IOToDiffArray a i e
  266. -> [(Int, e)]
  267. -> IO (IOToDiffArray a i e)
  268. a `replaceDiffArray1` ies = do
  269. mapM_ (evaluate . fst) ies
  270. a `replaceDiffArray` ies
  271. -- If the array contains unboxed elements, then the elements of the
  272. -- diff list may also recursively reference the array from inside
  273. -- replaceDiffArray, so we must seq them too.
  274. replaceDiffArray2 :: (MArray a e IO, Ix i)
  275. => IOToDiffArray a i e
  276. -> [(Int, e)]
  277. -> IO (IOToDiffArray a i e)
  278. a `replaceDiffArray2` ies = do
  279. mapM_ (\(a,b) -> do evaluate a; evaluate b) ies
  280. a `replaceDiffArray` ies
  281. boundsDiffArray :: (MArray a e IO, Ix ix)
  282. => IOToDiffArray a ix e
  283. -> IO (ix,ix)
  284. boundsDiffArray a = do
  285. d <- readMVar (varDiffArray a)
  286. case d of
  287. Current a' -> getBounds a'
  288. Diff a' _ -> boundsDiffArray a'
  289. freezeDiffArray :: (MArray a e IO, Ix ix)
  290. => a ix e
  291. -> IO (IOToDiffArray a ix e)
  292. freezeDiffArray a = do
  293. (l,u) <- getBounds a
  294. a' <- newArray_ (l,u)
  295. sequence_ [unsafeRead a i >>= unsafeWrite a' i | i <- [0 .. rangeSize (l,u) - 1]]
  296. var <- newMVar (Current a')
  297. return (DiffArray var)
  298. {-# RULES
  299. "freeze/DiffArray" freeze = freezeDiffArray
  300. #-}
  301. -- unsafeFreezeDiffArray is really unsafe. Better don't use the old
  302. -- array at all after freezing. The contents of the source array will
  303. -- be changed when '//' is applied to the resulting array.
  304. unsafeFreezeDiffArray :: (MArray a e IO, Ix ix)
  305. => a ix e
  306. -> IO (IOToDiffArray a ix e)
  307. unsafeFreezeDiffArray a = do
  308. var <- newMVar (Current a)
  309. return (DiffArray var)
  310. {-# RULES
  311. "unsafeFreeze/DiffArray" unsafeFreeze = unsafeFreezeDiffArray
  312. #-}
  313. thawDiffArray :: (MArray a e IO, Ix ix)
  314. => IOToDiffArray a ix e
  315. -> IO (a ix e)
  316. thawDiffArray a = do
  317. d <- readMVar (varDiffArray a)
  318. case d of
  319. Current a' -> do
  320. (l,u) <- getBounds a'
  321. a'' <- newArray_ (l,u)
  322. sequence_ [unsafeRead a' i >>= unsafeWrite a'' i | i <- [0 .. rangeSize (l,u) - 1]]
  323. return a''
  324. Diff a' ies -> do
  325. a'' <- thawDiffArray a'
  326. sequence_ [unsafeWrite a'' i e | (i, e) <- ies]
  327. return a''
  328. {-# RULES
  329. "thaw/DiffArray" thaw = thawDiffArray
  330. #-}
  331. -- unsafeThawDiffArray is really unsafe. Better don't use the old
  332. -- array at all after thawing. The contents of the resulting array
  333. -- will be changed when '//' is applied to the source array.
  334. unsafeThawDiffArray :: (MArray a e IO, Ix ix)
  335. => IOToDiffArray a ix e
  336. -> IO (a ix e)
  337. unsafeThawDiffArray a = do
  338. d <- readMVar (varDiffArray a)
  339. case d of
  340. Current a' -> return a'
  341. Diff a' ies -> do
  342. a'' <- unsafeThawDiffArray a'
  343. sequence_ [unsafeWrite a'' i e | (i, e) <- ies]
  344. return a''
  345. {-# RULES
  346. "unsafeThaw/DiffArray" unsafeThaw = unsafeThawDiffArray
  347. #-}