{-# OPTIONS -cpp #-} -- | Compatiblity for ByteStrings module Happstack.Util.ByteStringCompat (breakChar, breakCharEnd, dropSpace, dropSpaceEnd, rechunkLazy ) where import Data.ByteString(ByteString) import qualified Data.ByteString as B import qualified Data.ByteString.Internal as B import qualified Data.ByteString.Char8 as C import qualified Data.ByteString.Lazy as L import Data.Char(isSpace) import Foreign #define STRICT2(f) f a b | a `seq` b `seq` False = undefined -- | Semantically equivalent to break on strings {-# INLINE breakChar #-} breakChar :: Char -> ByteString -> (ByteString, ByteString) breakChar ch = B.break ((==) x) where x = B.c2w ch -- | 'breakCharEnd' behaves like breakChar, but from the end of the -- ByteString. -- -- > breakCharEnd ('b') (pack "aabbcc") == ("aab","cc") -- -- and the following are equivalent: -- -- > breakCharEnd 'c' "abcdef" -- > let (x,y) = break (=='c') (reverse "abcdef") -- > in (reverse (drop 1 y), reverse x) -- {-# INLINE breakCharEnd #-} breakCharEnd :: Char -> ByteString -> (ByteString, ByteString) breakCharEnd c p = B.breakEnd ((==) x) p where x = B.c2w c -- | Drops leading spaces in the ByteString {-# INLINE dropSpace #-} dropSpace :: ByteString -> ByteString dropSpace = C.dropWhile isSpace -- | Drops trailing spaces in the ByteString {-# INLINE dropSpaceEnd #-} dropSpaceEnd :: ByteString -> ByteString dropSpaceEnd (B.PS x s l) = B.inlinePerformIO $ withForeignPtr x $ \p -> do i <- lastnonspace (p `plusPtr` s) (l-1) return $! if i == (-1) then B.empty else B.PS x s (i+1) lastnonspace :: Ptr Word8 -> Int -> IO Int STRICT2(lastnonspace) lastnonspace ptr n | n < 0 = return n | otherwise = do w <- peekElemOff ptr n if B.isSpaceWord8 w then lastnonspace ptr (n-1) else return n -- | Chunk a lazy bytestring into reasonable chunks - is id from outside. -- This is useful to make bytestring chunks reasonable sized for e.g. -- compression. rechunkLazy :: L.ByteString -> L.ByteString rechunkLazy = L.fromChunks . norm . foldr w ([],[],0) . L.toChunks where norm (acc, [], _) = acc norm (acc, cur, _) = B.concat cur : acc w chunk (acc,cur,len) = let bl = len + B.length chunk in if bl > 0x100 then (B.concat (chunk : cur) : acc, [], 0) else (acc, chunk : cur, bl)