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 -- $Id: PackedString.hs,v 1.3 2001/09/14 11:25:23 simonmar Exp $
13 -- The PackedString type, and associated operations.
15 -- Original GHC implementation by Bryan O'Sullivan,
16 -- rewritten to use UArray by Simon Marlow.
18 -----------------------------------------------------------------------------
20 module Data.PackedString (
21 PackedString, -- abstract, instances: Eq, Ord, Show, Typeable
23 -- Creating the beasts
24 packString, -- :: [Char] -> PackedString
25 unpackPS, -- :: PackedString -> [Char]
27 hPutPS, -- :: Handle -> PackedString -> IO ()
28 hGetPS, -- :: Handle -> Int -> IO PackedString
30 nilPS, -- :: PackedString
31 consPS, -- :: Char -> PackedString -> PackedString
32 headPS, -- :: PackedString -> Char
33 tailPS, -- :: PackedString -> PackedString
34 nullPS, -- :: PackedString -> Bool
35 appendPS, -- :: PackedString -> PackedString -> PackedString
36 lengthPS, -- :: PackedString -> Int
37 indexPS, -- :: PackedString -> Int -> Char
38 mapPS, -- :: (Char -> Char) -> PackedString -> PackedString
39 filterPS, -- :: (Char -> Bool) -> PackedString -> PackedString
40 reversePS, -- :: PackedString -> PackedString
41 concatPS, -- :: [PackedString] -> PackedString
42 elemPS, -- :: Char -> PackedString -> Bool
43 substrPS, -- :: PackedString -> Int -> Int -> PackedString
44 takePS, -- :: Int -> PackedString -> PackedString
45 dropPS, -- :: Int -> PackedString -> PackedString
46 splitAtPS, -- :: Int -> PackedString -> (PackedString, PackedString)
48 foldlPS, -- :: (a -> Char -> a) -> a -> PackedString -> a
49 foldrPS, -- :: (Char -> a -> a) -> a -> PackedString -> a
50 takeWhilePS, -- :: (Char -> Bool) -> PackedString -> PackedString
51 dropWhilePS, -- :: (Char -> Bool) -> PackedString -> PackedString
52 spanPS, -- :: (Char -> Bool) -> PackedString -> (PackedString, PackedString)
53 breakPS, -- :: (Char -> Bool) -> PackedString -> (PackedString, PackedString)
54 linesPS, -- :: PackedString -> [PackedString]
56 wordsPS, -- :: PackedString -> [PackedString]
57 splitPS, -- :: Char -> PackedString -> [PackedString]
58 splitWithPS, -- :: (Char -> Bool) -> PackedString -> [PackedString]
60 -- joinPS, -- :: PackedString -> [PackedString] -> PackedString
66 import Data.Array.Unboxed
73 -- -----------------------------------------------------------------------------
74 -- PackedString type declaration
76 newtype PackedString = PS (UArray Int Char)
78 instance Eq PackedString where
79 (PS x) == (PS y) = x == y
81 instance Ord PackedString where
82 compare (PS x) (PS y) = compare x y
84 --instance Read PackedString: ToDo
86 instance Show PackedString where
87 showsPrec p ps r = showsPrec p (unpackPS ps) r
90 INSTANCE_TYPEABLE0(PackedString,packedStringTc,"PackedString")
92 -- -----------------------------------------------------------------------------
93 -- Constructor functions
96 nilPS = PS (array (0,-1) [])
98 consPS :: Char -> PackedString -> PackedString
99 consPS c cs = packString (c : (unpackPS cs)) -- ToDo:better
101 packString :: [Char] -> PackedString
102 packString str = packNChars (length str) str
104 packNChars :: Int -> [Char] -> PackedString
105 packNChars len str = PS (array (0,len-1) (zip [0..] str))
107 -- -----------------------------------------------------------------------------
108 -- Destructor functions (taking PackedStrings apart)
110 unpackPS :: PackedString -> [Char]
111 unpackPS (PS ps) = elems ps
113 -- -----------------------------------------------------------------------------
114 -- List-mimicking functions for PackedStrings
116 lengthPS :: PackedString -> Int
117 lengthPS (PS ps) = rangeSize (bounds ps)
119 indexPS :: PackedString -> Int -> Char
120 indexPS (PS ps) i = ps ! i
122 headPS :: PackedString -> Char
124 | nullPS ps = error "Data.PackedString.headPS: head []"
125 | otherwise = indexPS ps 0
127 tailPS :: PackedString -> PackedString
129 | len <= 0 = error "Data.PackedString.tailPS: tail []"
131 | otherwise = substrPS ps 1 (len - 1)
135 nullPS :: PackedString -> Bool
136 nullPS (PS ps) = rangeSize (bounds ps) == 0
138 appendPS :: PackedString -> PackedString -> PackedString
142 | otherwise = concatPS [xs,ys]
144 mapPS :: (Char -> Char) -> PackedString -> PackedString
145 mapPS f (PS ps) = PS (amap f ps)
147 filterPS :: (Char -> Bool) -> PackedString -> PackedString {-or String?-}
148 filterPS pred ps = packString (filter pred (unpackPS ps))
150 foldlPS :: (a -> Char -> a) -> a -> PackedString -> a
151 foldlPS f b ps = foldl f b (unpackPS ps)
153 foldrPS :: (Char -> a -> a) -> a -> PackedString -> a
154 foldrPS f v ps = foldr f v (unpackPS ps)
156 takePS :: Int -> PackedString -> PackedString
157 takePS n ps = substrPS ps 0 (n-1)
159 dropPS :: Int -> PackedString -> PackedString
160 dropPS n ps = substrPS ps n (lengthPS ps - 1)
162 splitAtPS :: Int -> PackedString -> (PackedString, PackedString)
163 splitAtPS n ps = (takePS n ps, dropPS n ps)
165 takeWhilePS :: (Char -> Bool) -> PackedString -> PackedString
166 takeWhilePS pred ps = packString (takeWhile pred (unpackPS ps))
168 dropWhilePS :: (Char -> Bool) -> PackedString -> PackedString
169 dropWhilePS pred ps = packString (dropWhile pred (unpackPS ps))
171 elemPS :: Char -> PackedString -> Bool
172 elemPS c ps = c `elem` unpackPS ps
174 spanPS :: (Char -> Bool) -> PackedString -> (PackedString, PackedString)
175 spanPS p ps = (takeWhilePS p ps, dropWhilePS p ps)
177 breakPS :: (Char -> Bool) -> PackedString -> (PackedString, PackedString)
178 breakPS p ps = spanPS (not . p) ps
180 linesPS :: PackedString -> [PackedString]
181 linesPS ps = splitPS '\n' ps
183 wordsPS :: PackedString -> [PackedString]
184 wordsPS ps = splitWithPS isSpace ps
186 reversePS :: PackedString -> PackedString
187 reversePS ps = packString (reverse (unpackPS ps))
189 concatPS :: [PackedString] -> PackedString
190 concatPS pss = packString (concat (map unpackPS pss))
192 ------------------------------------------------------------
194 joinPS :: PackedString -> [PackedString] -> PackedString
195 joinPS filler pss = concatPS (splice pss)
199 splice (x:y:xs) = x:filler:splice (y:xs)
201 -- ToDo: the obvious generalisation
203 Some properties that hold:
206 where False = any (map (x `elemPS`) ls')
207 False = any (map (nullPS) ls')
209 * all x's have been chopped out.
210 * no empty PackedStrings in returned list. A conseq.
215 * joinPS (packString [x]) (_splitPS x ls) = ls
220 splitPS :: Char -> PackedString -> [PackedString]
221 splitPS c = splitWithPS (== c)
223 splitWithPS :: (Char -> Bool) -> PackedString -> [PackedString]
224 splitWithPS pred (PS ps) =
227 len = lengthPS (PS ps)
233 break_pt = first_pos_that_satisfies pred ps len n
235 if break_pt == n then -- immediate match, no substring to cut out.
236 splitify (break_pt + 1)
238 substrPS (PS ps) n (break_pt - 1) -- leave out the matching character
239 : splitify (break_pt + 1)
241 first_pos_that_satisfies pred ps len n =
242 case [ m | m <- [n..len], pred (ps ! m) ] of
246 -- -----------------------------------------------------------------------------
247 -- Local utility functions
249 -- The definition of @_substrPS@ is essentially:
250 -- @take (end - begin + 1) (drop begin str)@.
252 substrPS :: PackedString -> Int -> Int -> PackedString
253 substrPS (PS ps) begin end = packString [ ps ! i | i <- [begin..end] ]
255 -- -----------------------------------------------------------------------------
258 hPutPS :: Handle -> PackedString -> IO ()
259 hPutPS h (PS ps) = do
260 let l = lengthPS (PS ps)
261 arr <- newArray_ (0, l-1)
262 sequence_ [ writeArray arr i (fromIntegral (ord (ps ! i))) | i <- [0..l-1] ]
265 -- -----------------------------------------------------------------------------
268 hGetPS :: Handle -> Int -> IO PackedString
270 arr <- newArray_ (0, i-1)
271 l <- hGetArray h arr i
272 chars <- mapM (\i -> readArray arr i >>= return.chr.fromIntegral) [0..l-1]
273 return (packString chars)