1{-# LANGUAGE BangPatterns, CPP, ExistentialQuantification, MagicHash,
2 Rank2Types, ScopedTypeVariables, UnboxedTuples #-}
3{-# OPTIONS_GHC -fno-warn-unused-matches #-}
5-- Module : Data.Text.Array
6-- Copyright : (c) Bryan O'Sullivan 2009
9-- Maintainer : bos@serpentine.com, rtharper@aftereternity.co.uk,
11-- Stability : experimental
12-- Portability : portable
14-- Packed, unboxed, heap-resident arrays. Suitable for performance
15-- critical use, both in terms of large data quantities and high
18-- This module is intended to be imported @qualified@, to avoid name
19-- clashes with "Prelude" functions, e.g.
21-- > import qualified Data.Text.Array as A
23-- The names in this module resemble those in the 'Data.Array' family
24-- of modules, but are shorter due to the assumption of qualifid
47#define BOUNDS_CHECKING
48-- This fugly hack is brought by GHC's apparent reluctance to deal
49-- with MagicHash and UnboxedTuples when inferring types. Eek!
50#define CHECK_BOUNDS(_func_,_len_,_k_) \
51if (_k_) < 0 || (_k_) >= (_len_) then error ("Data.Text.Array." ++ (_func_) ++ ": bounds error, offset " ++ show (_k_) ++ ", length " ++ show (_len_)) else
53#define CHECK_BOUNDS(_func_,_len_,_k_)
56#if defined(__GLASGOW_HASKELL__)
59import GHC.Base (ByteArray#, MutableByteArray#, Int(..),
60 indexWord16Array#, newByteArray#,
61 readWord16Array#, unsafeCoerce#,
62 writeWord16Array#, (*#))
64import GHC.ST (ST(..), runST)
65import GHC.Word (Word16(..))
67#elif defined(__HUGS__)
69import Hugs.ByteArray (ByteArray, MutableByteArray, readByteArray,
70 newMutableByteArray, readMutableByteArray,
71 unsafeFreezeMutableByteArray, writeMutableByteArray)
72import Foreign.Storable (Storable, sizeOf)
73import Hugs.ST (ST(..), runST)
76# error not implemented for this compiler
79import Control.Exception (assert)
80import Data.Typeable (Typeable1(..), Typeable2(..), TyCon, mkTyCon, mkTyConApp)
81import Prelude hiding (length, read)
85-- | Immutable array type.
87 {-# UNPACK #-} !Int -- length (in units of e, not bytes)
88#if defined(__GLASGOW_HASKELL__)
90#elif defined(__HUGS__)
94INSTANCE_TYPEABLE1(Array,arrayTc,"Array")
96-- | Mutable array type, for use in the ST monad.
97data MArray s e = MArray
98 {-# UNPACK #-} !Int -- length (in units of e, not bytes)
99#if defined(__GLASGOW_HASKELL__)
100 (MutableByteArray# s)
101#elif defined(__HUGS__)
102 !(MutableByteArray s)
105INSTANCE_TYPEABLE2(MArray,mArrayTc,"MArray")
107-- | Operations supported by all arrays.
109 -- | Return the length of an array.
112instance IArray (Array e) where
113 length (Array len _ba) = len
114 {-# INLINE length #-}
116instance (Elt e, Show e) => Show (Array e) where
119instance IArray (MArray s e) where
120 length (MArray len _ba) = len
121 {-# INLINE length #-}
123check :: IArray a => String -> a -> Int -> (a -> Int -> b) -> b
125 | i >= 0 && i < length ary = f ary i
126 | otherwise = error ("Data.Array.Flat." ++ func ++ ": index out of bounds")
129-- | Operations supported by all elements that can be stored in
132 -- | Indicate how many bytes would be used for an array of the
134 bytesInArray :: Int -> e -> Int
135 -- | Unchecked read of an immutable array. May return garbage or
136 -- crash on an out-of-bounds access.
137 unsafeIndex :: Array e -> Int -> e
138 -- | Unchecked read of a mutable array. May return garbage or
139 -- crash on an out-of-bounds access.
140 unsafeRead :: MArray s e -> Int -> ST s e
141 -- | Unchecked write of a mutable array. May return garbage or
142 -- crash on an out-of-bounds access.
143 unsafeWrite :: MArray s e -> Int -> e -> ST s ()
145 -- | Read an immutable array. An invalid index results in a
147 index :: Array e -> Int -> e
148 index ary i = check "index" ary i unsafeIndex
151 -- | Read a mutable array. An invalid index results in a runtime
153 read :: Array e -> Int -> ST s e
154 read ary i = check "read" ary i read
157 -- | Write a mutable array. An invalid index results in a runtime
159 write :: Array e -> Int -> ST s e
160 write ary i = check "write" ary i write
163-- | Freeze a mutable array. Do not mutate the 'MArray' afterwards!
164unsafeFreeze :: MArray s e -> ST s (Array e)
166#if defined(__GLASGOW_HASKELL__)
168wORD16_SCALE :: Int# -> Int#
169wORD16_SCALE n# = scale# *# n# where !(I# scale#) = SIZEOF_WORD16
171-- | Create an uninitialized mutable array.
172unsafeNew :: forall s e. Elt e => Int -> ST s (MArray s e)
173unsafeNew n = assert (n >= 0) . ST $ \s1# ->
174 case bytesInArray n (undefined :: e) of
176#if defined(BOUNDS_CHECKING)
177 if len < 0 then error (show ("unsafeNew",len)) else
179 case newByteArray# len# s1# of
180 (# s2#, marr# #) -> (# s2#, MArray n marr# #)
181{-# INLINE unsafeNew #-}
183unsafeFreeze (MArray len mba#) = ST $ \s# ->
184 (# s#, Array len (unsafeCoerce# mba#) #)
185{-# INLINE unsafeFreeze #-}
187-- | Create a mutable array, with its elements initialized with the
189new :: forall s e. Elt e => Int -> e -> ST s (MArray s e)
191#elif defined(__HUGS__)
193unsafeIndexArray :: Storable e => Array e -> Int -> e
194unsafeIndexArray (Array off len arr) i =
195 assert (i >= 0 && i < len) $ readByteArray arr (off + i)
197unsafeReadMArray :: Storable e => MArray s e -> Int -> ST s e
198unsafeReadMArray (MArray _len marr) i =
199 assert (i >= 0 && i < len) $ readMutableByteArray marr
201unsafeWriteMArray :: Storable e => MArray s e -> Int -> e -> ST s ()
202unsafeWriteMArray (MArray len marr) i =
203 assert (i >= 0 && i < len) $ writeMutableByteArray marr
205-- | Create an uninitialized mutable array.
206unsafeNew :: (Storable e) => Int -> ST s (MArray s e)
207unsafeNew n = new undefined
208 where new :: (Storable e) => e -> ST s (MArray s e)
210 marr <- newMutableByteArray (n * sizeOf unused)
211 return (MArray n marr)
213unsafeFreeze (MArray len mba) = do
214 ba <- unsafeFreezeMutableByteArray mba
215 return (Array 0 len ba)
217-- | Create a mutable array, with its elements initialized with the
219new :: (Storable e) => Int -> e -> ST s (MArray s e)
223 marr <- unsafeNew len
224 sequence_ [unsafeWrite marr i initVal | i <- [0..len-1]]
227instance Elt Word16 where
228#if defined(__GLASGOW_HASKELL__)
230 bytesInArray (I# i#) _ = I# (wORD16_SCALE i#)
231 {-# INLINE bytesInArray #-}
233 unsafeIndex (Array len ba#) i@(I# i#) =
234 CHECK_BOUNDS("unsafeIndex",len,i)
235 case indexWord16Array# ba# i# of r# -> (W16# r#)
236 {-# INLINE unsafeIndex #-}
238 unsafeRead (MArray len mba#) i@(I# i#) = ST $ \s# ->
239 CHECK_BOUNDS("unsafeRead",len,i)
240 case readWord16Array# mba# i# s# of
241 (# s2#, r# #) -> (# s2#, W16# r# #)
242 {-# INLINE unsafeRead #-}
244 unsafeWrite (MArray len marr#) i@(I# i#) (W16# e#) = ST $ \s1# ->
245 CHECK_BOUNDS("unsafeWrite",len,i)
246 case writeWord16Array# marr# i# e# s1# of
248 {-# INLINE unsafeWrite #-}
250#elif defined(__HUGS__)
252 bytesInArray n w = sizeOf w * n
253 unsafeIndex = unsafeIndexArray
254 unsafeRead = unsafeReadMArray
255 unsafeWrite = unsafeWriteMArray
259-- | Convert an immutable array to a list.
260toList :: Elt e => Array e -> [e]
262 where loop i | i < len = unsafeIndex a i : loop (i+1)
266-- | An empty immutable array.
267empty :: Elt e => Array e
268empty = runST (unsafeNew 0 >>= unsafeFreeze)
270-- | Run an action in the ST monad and return an immutable array of
272run :: Elt e => (forall s. ST s (MArray s e)) -> Array e
273run k = runST (k >>= unsafeFreeze)
275-- | Run an action in the ST monad and return an immutable array of
276-- its result paired with whatever else the action returns.
277run2 :: Elt e => (forall s. ST s (MArray s e, a)) -> (Array e, a)
280 arr <- unsafeFreeze marr
283-- | Copy an array in its entirety. The destination array must be at
284-- least as big as the source.
285copy :: Elt e => MArray s e -- ^ source array
286 -> MArray s e -- ^ destination array
289 | length dest >= length src = copy_loop 0
290 | otherwise = fail "Data.Text.Array.copy: array too small"
294 | i >= len = return ()
295 | otherwise = do unsafeRead src i >>= unsafeWrite dest i
299-- | Unsafely copy the elements of an array.
300unsafeCopy :: Elt e =>
301 MArray s e -> Int -> MArray s e -> Int -> Int -> ST s ()
302unsafeCopy src sidx dest didx count =
303 assert (sidx + count <= length src) .
304 assert (didx + count <= length dest) $
305 copy_loop sidx didx 0
308 | c >= count = return ()
309 | otherwise = do unsafeRead src i >>= unsafeWrite dest j
310 copy_loop (i+1) (j+1) (c+1)
311{-# INLINE unsafeCopy #-}
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list