26
26
module Data.Text.Array
47
#define BOUNDS_CHECKING
48
50
-- This fugly hack is brought by GHC's apparent reluctance to deal
49
51
-- with MagicHash and UnboxedTuples when inferring types. Eek!
50
#define CHECK_BOUNDS(_func_,_len_,_k_) \
52
# define CHECK_BOUNDS(_func_,_len_,_k_) \
51
53
if (_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_)
55
# define CHECK_BOUNDS(_func_,_len_,_k_)
56
#if defined(__GLASGOW_HASKELL__)
57
58
#include "MachDeps.h"
61
import Control.Exception (assert)
63
import Data.Bits ((.&.), xor)
64
import Data.Text.UnsafeShift (shiftL, shiftR)
59
65
import GHC.Base (ByteArray#, MutableByteArray#, Int(..),
60
indexWord16Array#, newByteArray#,
61
readWord16Array#, unsafeCoerce#,
62
writeWord16Array#, (*#))
63
import GHC.Prim (Int#)
66
indexWord16Array#, indexWordArray#, newByteArray#,
67
readWord16Array#, readWordArray#, unsafeCoerce#,
68
writeWord16Array#, writeWordArray#)
64
69
import GHC.ST (ST(..), runST)
65
import GHC.Word (Word16(..))
67
#elif defined(__HUGS__)
69
import Hugs.ByteArray (ByteArray, MutableByteArray, readByteArray,
70
newMutableByteArray, readMutableByteArray,
71
unsafeFreezeMutableByteArray, writeMutableByteArray)
72
import Foreign.Storable (Storable, sizeOf)
73
import Hugs.ST (ST(..), runST)
76
# error not implemented for this compiler
79
import Control.Exception (assert)
80
import Data.Typeable (Typeable1(..), Typeable2(..), TyCon, mkTyCon, mkTyConApp)
70
import GHC.Word (Word16(..), Word(..))
81
71
import Prelude hiding (length, read)
85
73
-- | Immutable array type.
87
{-# UNPACK #-} !Int -- length (in units of e, not bytes)
88
#if defined(__GLASGOW_HASKELL__)
90
#elif defined(__HUGS__)
77
, aLen :: {-# UNPACK #-} !Int -- length (in units of Word16, not bytes)
94
INSTANCE_TYPEABLE1(Array,arrayTc,"Array")
96
81
-- | Mutable array type, for use in the ST monad.
97
data 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)
82
data MArray s = MArray {
83
maBA :: MutableByteArray# s
85
, maLen :: {-# UNPACK #-} !Int -- length (in units of Word16, not bytes)
105
INSTANCE_TYPEABLE2(MArray,mArrayTc,"MArray")
107
90
-- | Operations supported by all arrays.
108
91
class IArray a where
109
92
-- | Return the length of an array.
110
93
length :: a -> Int
112
instance IArray (Array e) where
113
length (Array len _ba) = len
114
{-# INLINE length #-}
116
instance (Elt e, Show e) => Show (Array e) where
119
instance IArray (MArray s e) where
120
length (MArray len _ba) = len
121
{-# INLINE length #-}
123
check :: 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")
130
-- | Indicate how many bytes would be used for an array of the
132
bytesInArray :: Int -> e -> Int
133
-- | Unchecked read of an immutable array. May return garbage or
134
-- crash on an out-of-bounds access.
135
unsafeIndex :: Array e -> Int -> e
136
-- | Unchecked read of a mutable array. May return garbage or
137
-- crash on an out-of-bounds access.
138
unsafeRead :: MArray s e -> Int -> ST s e
139
-- | Unchecked write of a mutable array. May return garbage or
140
-- crash on an out-of-bounds access.
141
unsafeWrite :: MArray s e -> Int -> e -> ST s ()
143
-- | Read an immutable array. An invalid index results in a
145
index :: Array e -> Int -> e
146
index ary i = check "index" ary i unsafeIndex
149
-- | Read a mutable array. An invalid index results in a runtime
151
read :: Array e -> Int -> ST s e
152
read ary i = check "read" ary i read
155
-- | Write a mutable array. An invalid index results in a runtime
157
write :: Array e -> Int -> ST s e
158
write ary i = check "write" ary i write
95
instance IArray Array where
99
instance IArray (MArray s) where
101
{-# INLINE length #-}
104
-- | Create an uninitialized mutable array.
105
new :: forall s. Int -> ST s (MArray s)
107
| n < 0 || n .&. highBit /= 0 = error $ "Data.Text.Array.new: size overflow"
108
| otherwise = ST $ \s1# ->
109
case newByteArray# len# s1# of
110
(# s2#, marr# #) -> (# s2#, MArray marr#
115
where !(I# len#) = bytesInArray n
116
highBit = maxBound `xor` (maxBound `shiftR` 1)
161
119
-- | Freeze a mutable array. Do not mutate the 'MArray' afterwards!
162
unsafeFreeze :: MArray s e -> ST s (Array e)
164
#if defined(__GLASGOW_HASKELL__)
166
wORD16_SCALE :: Int# -> Int#
167
wORD16_SCALE n# = scale# *# n# where !(I# scale#) = SIZEOF_WORD16
169
unsafeNew :: forall s e. Elt e => Int -> ST s (MArray s e)
170
unsafeNew n = assert (n >= 0) . ST $ \s1# ->
171
case bytesInArray n (undefined :: e) of
173
#if defined(BOUNDS_CHECKING)
174
if len < 0 then error (show ("unsafeNew",len)) else
120
unsafeFreeze :: MArray s -> ST s Array
121
unsafeFreeze MArray{..} = ST $ \s# ->
122
(# s#, Array (unsafeCoerce# maBA)
176
case newByteArray# len# s1# of
177
(# s2#, marr# #) -> (# s2#, MArray n marr# #)
178
{-# INLINE unsafeNew #-}
180
unsafeFreeze (MArray len mba#) = ST $ \s# ->
181
(# s#, Array len (unsafeCoerce# mba#) #)
182
127
{-# INLINE unsafeFreeze #-}
184
new :: forall s e. Elt e => Int -> e -> ST s (MArray s e)
186
#elif defined(__HUGS__)
188
unsafeIndexArray :: Storable e => Array e -> Int -> e
189
unsafeIndexArray (Array off len arr) i =
190
assert (i >= 0 && i < len) $ readByteArray arr (off + i)
192
unsafeReadMArray :: Storable e => MArray s e -> Int -> ST s e
193
unsafeReadMArray (MArray _len marr) i =
194
assert (i >= 0 && i < len) $ readMutableByteArray marr
196
unsafeWriteMArray :: Storable e => MArray s e -> Int -> e -> ST s ()
197
unsafeWriteMArray (MArray len marr) i =
198
assert (i >= 0 && i < len) $ writeMutableByteArray marr
200
unsafeNew :: (Storable e) => Int -> ST s (MArray s e)
201
unsafeNew n = new undefined
202
where new :: (Storable e) => e -> ST s (MArray s e)
204
marr <- newMutableByteArray (n * sizeOf unused)
205
return (MArray n marr)
207
unsafeFreeze (MArray len mba) = do
208
ba <- unsafeFreezeMutableByteArray mba
209
return (Array 0 len ba)
211
new :: (Storable e) => Int -> e -> ST s (MArray s e)
215
marr <- unsafeNew len
216
sequence_ [unsafeWrite marr i initVal | i <- [0..len-1]]
219
instance Elt Word16 where
220
#if defined(__GLASGOW_HASKELL__)
222
bytesInArray (I# i#) _ = I# (wORD16_SCALE i#)
223
{-# INLINE bytesInArray #-}
225
unsafeIndex (Array len ba#) i@(I# i#) =
226
CHECK_BOUNDS("unsafeIndex",len,i)
227
case indexWord16Array# ba# i# of r# -> (W16# r#)
228
{-# INLINE unsafeIndex #-}
230
unsafeRead (MArray len mba#) i@(I# i#) = ST $ \s# ->
231
CHECK_BOUNDS("unsafeRead",len,i)
232
case readWord16Array# mba# i# s# of
233
(# s2#, r# #) -> (# s2#, W16# r# #)
234
{-# INLINE unsafeRead #-}
236
unsafeWrite (MArray len marr#) i@(I# i#) (W16# e#) = ST $ \s1# ->
237
CHECK_BOUNDS("unsafeWrite",len,i)
238
case writeWord16Array# marr# i# e# s1# of
240
{-# INLINE unsafeWrite #-}
242
#elif defined(__HUGS__)
244
bytesInArray n w = sizeOf w * n
245
unsafeIndex = unsafeIndexArray
246
unsafeRead = unsafeReadMArray
247
unsafeWrite = unsafeWriteMArray
129
-- | Indicate how many bytes would be used for an array of the given
131
bytesInArray :: Int -> Int
132
bytesInArray n = n `shiftL` 1
133
{-# INLINE bytesInArray #-}
135
-- | Unchecked read of an immutable array. May return garbage or
136
-- crash on an out-of-bounds access.
137
unsafeIndex :: Array -> Int -> Word16
138
unsafeIndex Array{..} i@(I# i#) =
139
CHECK_BOUNDS("unsafeIndex",aLen,i)
140
case indexWord16Array# aBA i# of r# -> (W16# r#)
141
{-# INLINE unsafeIndex #-}
143
-- | Unchecked read of an immutable array. May return garbage or
144
-- crash on an out-of-bounds access.
145
unsafeIndexWord :: Array -> Int -> Word
146
unsafeIndexWord Array{..} i@(I# i#) =
147
CHECK_BOUNDS("unsafeIndexWord",aLen`div`wordFactor,i)
148
case indexWordArray# aBA i# of r# -> (W# r#)
149
{-# INLINE unsafeIndexWord #-}
151
-- | Unchecked read of a mutable array. May return garbage or
152
-- crash on an out-of-bounds access.
153
unsafeRead :: MArray s -> Int -> ST s Word16
154
unsafeRead MArray{..} i@(I# i#) = ST $ \s# ->
155
CHECK_BOUNDS("unsafeRead",maLen,i)
156
case readWord16Array# maBA i# s# of
157
(# s2#, r# #) -> (# s2#, W16# r# #)
158
{-# INLINE unsafeRead #-}
160
-- | Unchecked write of a mutable array. May return garbage or crash
161
-- on an out-of-bounds access.
162
unsafeWrite :: MArray s -> Int -> Word16 -> ST s ()
163
unsafeWrite MArray{..} i@(I# i#) (W16# e#) = ST $ \s1# ->
164
CHECK_BOUNDS("unsafeWrite",maLen,i)
165
case writeWord16Array# maBA i# e# s1# of
167
{-# INLINE unsafeWrite #-}
169
-- | Unchecked read of a mutable array. May return garbage or
170
-- crash on an out-of-bounds access.
171
unsafeReadWord :: MArray s -> Int -> ST s Word
172
unsafeReadWord MArray{..} i@(I# i#) = ST $ \s# ->
173
CHECK_BOUNDS("unsafeRead64",maLen`div`wordFactor,i)
174
case readWordArray# maBA i# s# of
175
(# s2#, r# #) -> (# s2#, W# r# #)
176
{-# INLINE unsafeReadWord #-}
178
-- | Unchecked write of a mutable array. May return garbage or crash
179
-- on an out-of-bounds access.
180
unsafeWriteWord :: MArray s -> Int -> Word -> ST s ()
181
unsafeWriteWord MArray{..} i@(I# i#) (W# e#) = ST $ \s1# ->
182
CHECK_BOUNDS("unsafeWriteWord",maLen`div`wordFactor,i)
183
case writeWordArray# maBA i# e# s1# of
185
{-# INLINE unsafeWriteWord #-}
251
187
-- | Convert an immutable array to a list.
252
toList :: Elt e => Array e -> [e]
254
where loop i | i < len = unsafeIndex a i : loop (i+1)
188
toList :: Array -> Int -> Int -> [Word16]
189
toList ary off len = loop 0
190
where loop i | i < len = unsafeIndex ary (off+i) : loop (i+1)
258
193
-- | An empty immutable array.
259
empty :: Elt e => Array e
260
empty = runST (unsafeNew 0 >>= unsafeFreeze)
195
empty = runST (new 0 >>= unsafeFreeze)
262
197
-- | Run an action in the ST monad and return an immutable array of
264
run :: Elt e => (forall s. ST s (MArray s e)) -> Array e
199
run :: (forall s. ST s (MArray s)) -> Array
265
200
run k = runST (k >>= unsafeFreeze)
267
202
-- | Run an action in the ST monad and return an immutable array of
268
203
-- its result paired with whatever else the action returns.
269
run2 :: Elt e => (forall s. ST s (MArray s e, a)) -> (Array e, a)
204
run2 :: (forall s. ST s (MArray s, a)) -> (Array, a)
270
205
run2 k = runST (do
272
207
arr <- unsafeFreeze marr
275
copy :: Elt e => MArray s e -- ^ source array
276
-> MArray s e -- ^ destination array
279
| length dest >= length src = copy_loop 0
280
| otherwise = fail "Data.Text.Array.copy: array too small"
284
| i >= len = return ()
285
| otherwise = do unsafeRead src i >>= unsafeWrite dest i
289
unsafeCopy :: Elt e =>
290
MArray s e -> Int -> MArray s e -> Int -> Int -> ST s ()
291
unsafeCopy src sidx dest didx count =
210
-- | The amount to divide or multiply by to switch between units of
211
-- 'Word16' and units of 'Word'.
213
wordFactor = SIZEOF_HSWORD `shiftR` 1
215
-- | Indicate whether an offset is word-aligned.
216
wordAligned :: Int -> Bool
217
wordAligned i = i .&. (wordFactor - 1) == 0
219
-- | Copy some elements of a mutable array.
220
copyM :: MArray s -- ^ Destination
221
-> Int -- ^ Destination offset
222
-> MArray s -- ^ Source
223
-> Int -- ^ Source offset
226
copyM dest didx src sidx count =
292
228
assert (sidx + count <= length src) .
293
229
assert (didx + count <= length dest) $
294
copy_loop sidx didx 0
231
if srem == 0 && drem == 0
297
| c >= count = return ()
298
| otherwise = do unsafeRead src i >>= unsafeWrite dest j
299
copy_loop (i+1) (j+1) (c+1)
300
{-# INLINE unsafeCopy #-}
235
(swidx,srem) = sidx `divMod` wordFactor
236
(dwidx,drem) = didx `divMod` wordFactor
237
nwds = count `div` wordFactor
239
| i >= nwds = slow_loop (i * wordFactor)
240
| otherwise = do w <- unsafeReadWord src (swidx+i)
241
unsafeWriteWord dest (dwidx+i) w
244
| i >= count= return ()
245
| otherwise = do unsafeRead src (sidx+i) >>= unsafeWrite dest (didx+i)
248
-- | Copy some elements of an immutable array.
249
copyI :: MArray s -- ^ Destination
250
-> Int -- ^ Destination offset
252
-> Int -- ^ Source offset
253
-> Int -- ^ First offset in source /not/ to
254
-- copy (i.e. /not/ length)
256
copyI dest i0 src j0 top
257
| wordAligned i0 && wordAligned j0 = fast (i0 `div` wordFactor) (j0 `div` wordFactor)
258
| otherwise = slow i0 j0
260
topwds = top `div` wordFactor
262
| i >= topwds = slow (i * wordFactor) (j * wordFactor)
263
| otherwise = do unsafeWriteWord dest i (src `unsafeIndexWord` j)
266
| i >= top = return ()
267
| otherwise = do unsafeWrite dest i (src `unsafeIndex` j)
270
-- | Compare portions of two arrays for equality. No bounds checking
272
equal :: Array -- ^ First
273
-> Int -- ^ Offset into first
275
-> Int -- ^ Offset into second
278
equal arrA offA arrB offB count
279
| wordAligned offA && wordAligned offB = fast 0
282
countWords = count `div` wordFactor
284
| i >= countWords = slow (i * wordFactor)
286
| otherwise = fast (i+1)
287
where a = unsafeIndexWord arrA (offAW+i)
288
b = unsafeIndexWord arrB (offBW+i)
289
offAW = offA `div` wordFactor
290
offBW = offB `div` wordFactor
294
| otherwise = slow (i+1)
295
where a = unsafeIndex arrA (offA+i)
296
b = unsafeIndex arrB (offB+i)