1 -----------------------------------------------------------------------------
3 -- Module : Data.PackedString
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 : portable
11 -- The PackedString type, and associated operations.
13 -- Original GHC implementation by Bryan O'Sullivan,
14 -- rewritten to use UArray by Simon Marlow.
16 -----------------------------------------------------------------------------
18 module Data.PackedString (
19 PackedString, -- abstract, instances: Eq, Ord, Show, Typeable
21 -- Creating the beasts
22 packString, -- :: [Char] -> PackedString
23 unpackPS, -- :: PackedString -> [Char]
25 hPutPS, -- :: Handle -> PackedString -> IO ()
26 hGetPS, -- :: Handle -> Int -> IO PackedString
28 nilPS, -- :: PackedString
29 consPS, -- :: Char -> PackedString -> PackedString
30 headPS, -- :: PackedString -> Char
31 tailPS, -- :: PackedString -> PackedString
32 nullPS, -- :: PackedString -> Bool
33 appendPS, -- :: PackedString -> PackedString -> PackedString
34 lengthPS, -- :: PackedString -> Int
35 indexPS, -- :: PackedString -> Int -> Char
36 mapPS, -- :: (Char -> Char) -> PackedString -> PackedString
37 filterPS, -- :: (Char -> Bool) -> PackedString -> PackedString
38 reversePS, -- :: PackedString -> PackedString
39 concatPS, -- :: [PackedString] -> PackedString
40 elemPS, -- :: Char -> PackedString -> Bool
41 substrPS, -- :: PackedString -> Int -> Int -> PackedString
42 takePS, -- :: Int -> PackedString -> PackedString
43 dropPS, -- :: Int -> PackedString -> PackedString
44 splitAtPS, -- :: Int -> PackedString -> (PackedString, PackedString)
46 foldlPS, -- :: (a -> Char -> a) -> a -> PackedString -> a
47 foldrPS, -- :: (Char -> a -> a) -> a -> PackedString -> a
48 takeWhilePS, -- :: (Char -> Bool) -> PackedString -> PackedString
49 dropWhilePS, -- :: (Char -> Bool) -> PackedString -> PackedString
50 spanPS, -- :: (Char -> Bool) -> PackedString -> (PackedString, PackedString)
51 breakPS, -- :: (Char -> Bool) -> PackedString -> (PackedString, PackedString)
52 linesPS, -- :: PackedString -> [PackedString]
54 wordsPS, -- :: PackedString -> [PackedString]
55 splitPS, -- :: Char -> PackedString -> [PackedString]
56 splitWithPS, -- :: (Char -> Bool) -> PackedString -> [PackedString]
58 -- joinPS, -- :: PackedString -> [PackedString] -> PackedString
64 import Data.Array.Unboxed
71 -- -----------------------------------------------------------------------------
72 -- PackedString type declaration
74 newtype PackedString = PS (UArray Int Char)
76 instance Eq PackedString where
77 (PS x) == (PS y) = x == y
79 instance Ord PackedString where
80 compare (PS x) (PS y) = compare x y
82 --instance Read PackedString: ToDo
84 instance Show PackedString where
85 showsPrec p ps r = showsPrec p (unpackPS ps) r
88 INSTANCE_TYPEABLE0(PackedString,packedStringTc,"PackedString")
90 -- -----------------------------------------------------------------------------
91 -- Constructor functions
94 nilPS = PS (array (0,-1) [])
96 consPS :: Char -> PackedString -> PackedString
97 consPS c cs = packString (c : (unpackPS cs)) -- ToDo:better
99 packString :: [Char] -> PackedString
100 packString str = packNChars (length str) str
102 packNChars :: Int -> [Char] -> PackedString
103 packNChars len str = PS (array (0,len-1) (zip [0..] str))
105 -- -----------------------------------------------------------------------------
106 -- Destructor functions (taking PackedStrings apart)
108 unpackPS :: PackedString -> [Char]
109 unpackPS (PS ps) = elems ps
111 -- -----------------------------------------------------------------------------
112 -- List-mimicking functions for PackedStrings
114 lengthPS :: PackedString -> Int
115 lengthPS (PS ps) = rangeSize (bounds ps)
117 indexPS :: PackedString -> Int -> Char
118 indexPS (PS ps) i = ps ! i
120 headPS :: PackedString -> Char
122 | nullPS ps = error "Data.PackedString.headPS: head []"
123 | otherwise = indexPS ps 0
125 tailPS :: PackedString -> PackedString
127 | len <= 0 = error "Data.PackedString.tailPS: tail []"
129 | otherwise = substrPS ps 1 (len - 1)
133 nullPS :: PackedString -> Bool
134 nullPS (PS ps) = rangeSize (bounds ps) == 0
136 appendPS :: PackedString -> PackedString -> PackedString
140 | otherwise = concatPS [xs,ys]
142 mapPS :: (Char -> Char) -> PackedString -> PackedString
143 mapPS f (PS ps) = PS (amap f ps)
145 filterPS :: (Char -> Bool) -> PackedString -> PackedString {-or String?-}
146 filterPS pred ps = packString (filter pred (unpackPS ps))
148 foldlPS :: (a -> Char -> a) -> a -> PackedString -> a
149 foldlPS f b ps = foldl f b (unpackPS ps)
151 foldrPS :: (Char -> a -> a) -> a -> PackedString -> a
152 foldrPS f v ps = foldr f v (unpackPS ps)
154 takePS :: Int -> PackedString -> PackedString
155 takePS n ps = substrPS ps 0 (n-1)
157 dropPS :: Int -> PackedString -> PackedString
158 dropPS n ps = substrPS ps n (lengthPS ps - 1)
160 splitAtPS :: Int -> PackedString -> (PackedString, PackedString)
161 splitAtPS n ps = (takePS n ps, dropPS n ps)
163 takeWhilePS :: (Char -> Bool) -> PackedString -> PackedString
164 takeWhilePS pred ps = packString (takeWhile pred (unpackPS ps))
166 dropWhilePS :: (Char -> Bool) -> PackedString -> PackedString
167 dropWhilePS pred ps = packString (dropWhile pred (unpackPS ps))
169 elemPS :: Char -> PackedString -> Bool
170 elemPS c ps = c `elem` unpackPS ps
172 spanPS :: (Char -> Bool) -> PackedString -> (PackedString, PackedString)
173 spanPS p ps = (takeWhilePS p ps, dropWhilePS p ps)
175 breakPS :: (Char -> Bool) -> PackedString -> (PackedString, PackedString)
176 breakPS p ps = spanPS (not . p) ps
178 linesPS :: PackedString -> [PackedString]
179 linesPS ps = splitPS '\n' ps
181 wordsPS :: PackedString -> [PackedString]
182 wordsPS ps = splitWithPS isSpace ps
184 reversePS :: PackedString -> PackedString
185 reversePS ps = packString (reverse (unpackPS ps))
187 concatPS :: [PackedString] -> PackedString
188 concatPS pss = packString (concat (map unpackPS pss))
190 ------------------------------------------------------------
192 joinPS :: PackedString -> [PackedString] -> PackedString
193 joinPS filler pss = concatPS (splice pss)
197 splice (x:y:xs) = x:filler:splice (y:xs)
199 -- ToDo: the obvious generalisation
201 Some properties that hold:
204 where False = any (map (x `elemPS`) ls')
205 False = any (map (nullPS) ls')
207 * all x's have been chopped out.
208 * no empty PackedStrings in returned list. A conseq.
213 * joinPS (packString [x]) (_splitPS x ls) = ls
218 splitPS :: Char -> PackedString -> [PackedString]
219 splitPS c = splitWithPS (== c)
221 splitWithPS :: (Char -> Bool) -> PackedString -> [PackedString]
222 splitWithPS pred (PS ps) =
225 len = lengthPS (PS ps)
231 break_pt = first_pos_that_satisfies pred ps len n
233 if break_pt == n then -- immediate match, no substring to cut out.
234 splitify (break_pt + 1)
236 substrPS (PS ps) n (break_pt - 1) -- leave out the matching character
237 : splitify (break_pt + 1)
239 first_pos_that_satisfies pred ps len n =
240 case [ m | m <- [n..len], pred (ps ! m) ] of
244 -- -----------------------------------------------------------------------------
245 -- Local utility functions
247 -- The definition of @_substrPS@ is essentially:
248 -- @take (end - begin + 1) (drop begin str)@.
250 substrPS :: PackedString -> Int -> Int -> PackedString
251 substrPS (PS ps) begin end = packString [ ps ! i | i <- [begin..end] ]
253 -- -----------------------------------------------------------------------------
256 hPutPS :: Handle -> PackedString -> IO ()
257 hPutPS h (PS ps) = do
258 let l = lengthPS (PS ps)
259 arr <- newArray_ (0, l-1)
260 sequence_ [ writeArray arr i (fromIntegral (ord (ps ! i))) | i <- [0..l-1] ]
263 -- -----------------------------------------------------------------------------
266 hGetPS :: Handle -> Int -> IO PackedString
268 arr <- newArray_ (0, i-1)
269 l <- hGetArray h arr i
270 chars <- mapM (\i -> readArray arr i >>= return.chr.fromIntegral) [0..l-1]
271 return (packString chars)