1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
|
%
% (c) The GRASP/AQUA Project, Glasgow University, 1997-1998
%
\section{Basic ops on packed representations}
Some basic operations for working on packed representations of series
of bytes (character strings). Used by the interface lexer input
subsystem, mostly.
\begin{code}
module PrimPacked
(
strLength, -- :: _Addr -> Int
copyPrefixStr, -- :: _Addr -> Int -> ByteArray Int
copySubStr, -- :: _Addr -> Int -> Int -> ByteArray Int
copySubStrFO, -- :: ForeignObj -> Int -> Int -> ByteArray Int
copySubStrBA, -- :: ByteArray Int -> Int -> Int -> ByteArray Int
eqStrPrefix, -- :: Addr# -> ByteArray# -> Int# -> Bool
eqCharStrPrefix, -- :: Addr# -> Addr# -> Int# -> Bool
eqStrPrefixBA, -- :: ByteArray# -> ByteArray# -> Int# -> Int# -> Bool
eqCharStrPrefixBA, -- :: Addr# -> ByteArray# -> Int# -> Int# -> Bool
eqStrPrefixFO, -- :: ForeignObj# -> ByteArray# -> Int# -> Int# -> Bool
addrOffset# -- :: Addr# -> Int# -> Addr#
) where
-- This #define suppresses the "import FastString" that
-- HsVersions otherwise produces
#define COMPILING_FAST_STRING
#include "HsVersions.h"
import GlaExts
import PrelAddr ( Addr(..) )
import ST
import Foreign
-- ForeignObj is now exported abstractly.
#if __GLASGOW_HASKELL__ >= 303
import PrelForeign ( ForeignObj(..) )
#endif
#if __GLASGOW_HASKELL__ < 301
import ArrBase ( StateAndMutableByteArray#(..),
StateAndByteArray#(..) )
import STBase
#elif __GLASGOW_HASKELL__ < 400
import PrelArr ( StateAndMutableByteArray#(..),
StateAndByteArray#(..) )
import PrelST
#else
import PrelST
#endif
\end{code}
Return the length of a @\\NUL@ terminated character string:
\begin{code}
strLength :: Addr -> Int
strLength a =
unsafePerformIO (
_ccall_ strlen a >>= \ len@(I# _) ->
return len
)
{-# NOINLINE strLength #-}
\end{code}
Copying a char string prefix into a byte array,
{\em assuming} the prefix does not contain any
NULs.
\begin{code}
copyPrefixStr :: Addr -> Int -> ByteArray Int
copyPrefixStr (A# a) len@(I# length#) =
runST (
{- allocate an array that will hold the string
(not forgetting the NUL at the end)
-}
(new_ps_array (length# +# 1#)) >>= \ ch_array ->
{- Revert back to Haskell-only solution for the moment.
_ccall_ memcpy ch_array (A# a) len >>= \ () ->
write_ps_array ch_array length# (chr# 0#) >>
-}
-- fill in packed string from "addr"
fill_in ch_array 0# >>
-- freeze the puppy:
freeze_ps_array ch_array length# `thenStrictlyST` \ barr ->
returnStrictlyST barr )
where
fill_in :: MutableByteArray s Int -> Int# -> ST s ()
fill_in arr_in# idx
| idx ==# length#
= write_ps_array arr_in# idx (chr# 0#) `seqStrictlyST`
returnStrictlyST ()
| otherwise
= case (indexCharOffAddr# a idx) of { ch ->
write_ps_array arr_in# idx ch `seqStrictlyST`
fill_in arr_in# (idx +# 1#) }
\end{code}
Copying out a substring, assume a 0-indexed string:
(and positive lengths, thank you).
\begin{code}
copySubStr :: Addr -> Int -> Int -> ByteArray Int
copySubStr a start length =
unsafePerformIO (
_casm_ `` %r= (char *)((char *)%0 + (int)%1); '' a start
>>= \ a_start ->
return (copyPrefixStr a_start length))
\end{code}
pCopying a sub-string out of a ForeignObj
\begin{code}
copySubStrFO :: ForeignObj -> Int -> Int -> ByteArray Int
copySubStrFO (ForeignObj fo) (I# start#) len@(I# length#) =
runST (
{- allocate an array that will hold the string
(not forgetting the NUL at the end)
-}
new_ps_array (length# +# 1#) `thenStrictlyST` \ ch_array ->
-- fill in packed string from "addr"
fill_in ch_array 0# `seqStrictlyST`
-- freeze the puppy:
freeze_ps_array ch_array length#)
where
fill_in :: MutableByteArray s Int -> Int# -> ST s ()
fill_in arr_in# idx
| idx ==# length#
= write_ps_array arr_in# idx (chr# 0#) `seqStrictlyST`
returnStrictlyST ()
| otherwise
= case (indexCharOffForeignObj# fo (idx +# start#)) of { ch ->
write_ps_array arr_in# idx ch `seqStrictlyST`
fill_in arr_in# (idx +# 1#) }
-- step on (char *) pointer by x units.
addrOffset# :: Addr# -> Int# -> Addr#
addrOffset# a# i# =
case unsafePerformIO (_casm_ ``%r=(char *)((char *)%0 + (int)%1); '' (A# a#) (I# i#)) of
A# a -> a
copySubStrBA :: ByteArray Int -> Int -> Int -> ByteArray Int
#if __GLASGOW_HASKELL__ >= 405
copySubStrBA (ByteArray _ _ barr#) (I# start#) len@(I# length#) =
#else
copySubStrBA (ByteArray _ barr#) (I# start#) len@(I# length#) =
#endif
runST (
{- allocate an array that will hold the string
(not forgetting the NUL at the end)
-}
new_ps_array (length# +# 1#) `thenStrictlyST` \ ch_array ->
-- fill in packed string from "addr"
fill_in ch_array 0# `seqStrictlyST`
-- freeze the puppy:
freeze_ps_array ch_array length#)
where
fill_in :: MutableByteArray s Int -> Int# -> ST s ()
fill_in arr_in# idx
| idx ==# length#
= write_ps_array arr_in# idx (chr# 0#) `seqStrictlyST`
returnStrictlyST ()
| otherwise
= case (indexCharArray# barr# (start# +# idx)) of { ch ->
write_ps_array arr_in# idx ch `seqStrictlyST`
fill_in arr_in# (idx +# 1#) }
\end{code}
(Very :-) ``Specialised'' versions of some CharArray things...
[Copied from PackBase; no real reason -- UGH]
\begin{code}
new_ps_array :: Int# -> ST s (MutableByteArray s Int)
write_ps_array :: MutableByteArray s Int -> Int# -> Char# -> ST s ()
freeze_ps_array :: MutableByteArray s Int -> Int# -> ST s (ByteArray Int)
new_ps_array size = ST $ \ s ->
#if __GLASGOW_HASKELL__ < 400
case (newCharArray# size s) of { StateAndMutableByteArray# s2# barr# ->
STret s2# (MutableByteArray bot barr#) }
#elif __GLASGOW_HASKELL__ < 405
case (newCharArray# size s) of { (# s2#, barr# #) ->
(# s2#, MutableByteArray bot barr# #) }
#else
case (newCharArray# size s) of { (# s2#, barr# #) ->
(# s2#, MutableByteArray bot bot barr# #) }
#endif
where
bot = error "new_ps_array"
#if __GLASGOW_HASKELL__ < 400
write_ps_array (MutableByteArray _ barr#) n ch = ST $ \ s# ->
case writeCharArray# barr# n ch s# of { s2# ->
STret s2# () }
#elif __GLASGOW_HASKELL__ < 405
write_ps_array (MutableByteArray _ barr#) n ch = ST $ \ s# ->
case writeCharArray# barr# n ch s# of { s2# ->
(# s2#, () #) }
#else
write_ps_array (MutableByteArray _ _ barr#) n ch = ST $ \ s# ->
case writeCharArray# barr# n ch s# of { s2# ->
(# s2#, () #) }
#endif
-- same as unsafeFreezeByteArray
#if __GLASGOW_HASKELL__ < 400
freeze_ps_array (MutableByteArray _ arr#) len# = ST $ \ s# ->
case unsafeFreezeByteArray# arr# s# of { StateAndByteArray# s2# frozen# ->
STret s2# (ByteArray (0,I# len#) frozen#) }
#elif __GLASGOW_HASKELL__ < 405
freeze_ps_array (MutableByteArray _ arr#) len# = ST $ \ s# ->
case unsafeFreezeByteArray# arr# s# of { (# s2#, frozen# #) ->
(# s2#, ByteArray (0,I# len#) frozen# #) }
#else
freeze_ps_array (MutableByteArray _ _ arr#) len# = ST $ \ s# ->
case unsafeFreezeByteArray# arr# s# of { (# s2#, frozen# #) ->
(# s2#, ByteArray 0 (I# len#) frozen# #) }
#endif
\end{code}
Compare two equal-length strings for equality:
\begin{code}
eqStrPrefix :: Addr# -> ByteArray# -> Int# -> Bool
eqStrPrefix a# barr# len# =
unsafePerformIO (
#if __GLASGOW_HASKELL__ < 405
_ccall_ strncmp (A# a#) (ByteArray bot barr#) (I# len#) >>= \ (I# x#) ->
#else
_ccall_ strncmp (A# a#) (ByteArray bot bot barr#) (I# len#) >>= \ (I# x#) ->
#endif
return (x# ==# 0#))
where
#if __GLASGOW_HASKELL__ < 405
bot :: (Int,Int)
#else
bot :: Int
#endif
bot = error "eqStrPrefix"
eqCharStrPrefix :: Addr# -> Addr# -> Int# -> Bool
eqCharStrPrefix a1# a2# len# =
unsafePerformIO (
_ccall_ strncmp (A# a1#) (A# a2#) (I# len#) >>= \ (I# x#) ->
return (x# ==# 0#))
eqStrPrefixBA :: ByteArray# -> ByteArray# -> Int# -> Int# -> Bool
eqStrPrefixBA b1# b2# start# len# =
unsafePerformIO (
_casm_ ``%r=(int)strncmp((char *)%0+(int)%1,%2,%3); ''
#if __GLASGOW_HASKELL__ < 405
(ByteArray bot b2#)
#else
(ByteArray bot bot b2#)
#endif
(I# start#)
#if __GLASGOW_HASKELL__ < 405
(ByteArray bot b1#)
#else
(ByteArray bot bot b1#)
#endif
(I# len#) >>= \ (I# x#) ->
return (x# ==# 0#))
where
#if __GLASGOW_HASKELL__ < 405
bot :: (Int,Int)
#else
bot :: Int
#endif
bot = error "eqStrPrefixBA"
eqCharStrPrefixBA :: Addr# -> ByteArray# -> Int# -> Int# -> Bool
eqCharStrPrefixBA a# b2# start# len# =
unsafePerformIO (
_casm_ ``%r=(int)strncmp((char *)%0+(int)%1,%2,%3); ''
#if __GLASGOW_HASKELL__ < 405
(ByteArray bot b2#)
#else
(ByteArray bot bot b2#)
#endif
(I# start#)
(A# a#)
(I# len#) >>= \ (I# x#) ->
return (x# ==# 0#))
where
#if __GLASGOW_HASKELL__ < 405
bot :: (Int,Int)
#else
bot :: Int
#endif
bot = error "eqCharStrPrefixBA"
eqStrPrefixFO :: ForeignObj# -> ByteArray# -> Int# -> Int# -> Bool
eqStrPrefixFO fo# barr# start# len# =
unsafePerformIO (
_casm_ ``%r=(int)strncmp((char *)%0+(int)%1,%2,%3); ''
(ForeignObj fo#)
(I# start#)
#if __GLASGOW_HASKELL__ < 405
(ByteArray bot barr#)
#else
(ByteArray bot bot barr#)
#endif
(I# len#) >>= \ (I# x#) ->
return (x# ==# 0#))
where
#if __GLASGOW_HASKELL__ < 405
bot :: (Int,Int)
#else
bot :: Int
#endif
bot = error "eqStrPrefixFO"
\end{code}
|