{-# LANGUAGE CPP #-} {-# OPTIONS_GHC -XMagicHash -XUnboxedTuples -fno-warn-orphans #-} -- #prune -- | -- Module : Data.ByteString -- Copyright : (c) The University of Glasgow 2001, -- (c) David Roundy 2003-2005, -- (c) Simon Marlow 2005 -- (c) Bjorn Bringert 2006 -- (c) Don Stewart 2005-2008 -- -- Array fusion code: -- (c) 2001,2002 Manuel M T Chakravarty & Gabriele Keller -- (c) 2006 Manuel M T Chakravarty & Roman Leshchinskiy -- -- License : BSD-style -- -- Maintainer : dons@cse.unsw.edu.au -- Stability : experimental -- Portability : portable -- -- A time and space-efficient implementation of byte vectors using -- packed Word8 arrays, suitable for high performance use, both in terms -- of large data quantities, or high speed requirements. Byte vectors -- are encoded as strict 'Word8' arrays of bytes, held in a 'ForeignPtr', -- and can be passed between C and Haskell with little effort. -- -- This module is intended to be imported @qualified@, to avoid name -- clashes with "Prelude" functions. eg. -- -- > import qualified Data.ByteString as B -- -- Original GHC implementation by Bryan O\'Sullivan. -- Rewritten to use 'Data.Array.Unboxed.UArray' by Simon Marlow. -- Rewritten to support slices and use 'ForeignPtr' by David Roundy. -- Polished and extended by Don Stewart. -- module Data.ByteString ( -- * The @ByteString@ type ByteString, -- abstract, instances: Eq, Ord, Show, Read, Data, Typeable, Monoid -- * Introducing and eliminating 'ByteString's empty, -- :: ByteString singleton, -- :: Word8 -> ByteString pack, -- :: [Word8] -> ByteString unpack, -- :: ByteString -> [Word8] -- * Basic interface cons, -- :: Word8 -> ByteString -> ByteString snoc, -- :: ByteString -> Word8 -> ByteString append, -- :: ByteString -> ByteString -> ByteString head, -- :: ByteString -> Word8 uncons, -- :: ByteString -> Maybe (Word8, ByteString) last, -- :: ByteString -> Word8 tail, -- :: ByteString -> ByteString init, -- :: ByteString -> ByteString null, -- :: ByteString -> Bool length, -- :: ByteString -> Int -- * Transforming ByteStrings map, -- :: (Word8 -> Word8) -> ByteString -> ByteString reverse, -- :: ByteString -> ByteString intersperse, -- :: Word8 -> ByteString -> ByteString intercalate, -- :: ByteString -> [ByteString] -> ByteString transpose, -- :: [ByteString] -> [ByteString] -- * Reducing 'ByteString's (folds) foldl, -- :: (a -> Word8 -> a) -> a -> ByteString -> a foldl', -- :: (a -> Word8 -> a) -> a -> ByteString -> a foldl1, -- :: (Word8 -> Word8 -> Word8) -> ByteString -> Word8 foldl1', -- :: (Word8 -> Word8 -> Word8) -> ByteString -> Word8 foldr, -- :: (Word8 -> a -> a) -> a -> ByteString -> a foldr', -- :: (Word8 -> a -> a) -> a -> ByteString -> a foldr1, -- :: (Word8 -> Word8 -> Word8) -> ByteString -> Word8 foldr1', -- :: (Word8 -> Word8 -> Word8) -> ByteString -> Word8 -- ** Special folds concat, -- :: [ByteString] -> ByteString concatMap, -- :: (Word8 -> ByteString) -> ByteString -> ByteString any, -- :: (Word8 -> Bool) -> ByteString -> Bool all, -- :: (Word8 -> Bool) -> ByteString -> Bool maximum, -- :: ByteString -> Word8 minimum, -- :: ByteString -> Word8 -- * Building ByteStrings -- ** Scans scanl, -- :: (Word8 -> Word8 -> Word8) -> Word8 -> ByteString -> ByteString scanl1, -- :: (Word8 -> Word8 -> Word8) -> ByteString -> ByteString scanr, -- :: (Word8 -> Word8 -> Word8) -> Word8 -> ByteString -> ByteString scanr1, -- :: (Word8 -> Word8 -> Word8) -> ByteString -> ByteString -- ** Accumulating maps mapAccumL, -- :: (acc -> Word8 -> (acc, Word8)) -> acc -> ByteString -> (acc, ByteString) mapAccumR, -- :: (acc -> Word8 -> (acc, Word8)) -> acc -> ByteString -> (acc, ByteString) -- ** Generating and unfolding ByteStrings replicate, -- :: Int -> Word8 -> ByteString unfoldr, -- :: (a -> Maybe (Word8, a)) -> a -> ByteString unfoldrN, -- :: Int -> (a -> Maybe (Word8, a)) -> a -> (ByteString, Maybe a) -- * Substrings -- ** Breaking strings take, -- :: Int -> ByteString -> ByteString drop, -- :: Int -> ByteString -> ByteString splitAt, -- :: Int -> ByteString -> (ByteString, ByteString) takeWhile, -- :: (Word8 -> Bool) -> ByteString -> ByteString dropWhile, -- :: (Word8 -> Bool) -> ByteString -> ByteString span, -- :: (Word8 -> Bool) -> ByteString -> (ByteString, ByteString) spanEnd, -- :: (Word8 -> Bool) -> ByteString -> (ByteString, ByteString) break, -- :: (Word8 -> Bool) -> ByteString -> (ByteString, ByteString) breakEnd, -- :: (Word8 -> Bool) -> ByteString -> (ByteString, ByteString) group, -- :: ByteString -> [ByteString] groupBy, -- :: (Word8 -> Word8 -> Bool) -> ByteString -> [ByteString] inits, -- :: ByteString -> [ByteString] tails, -- :: ByteString -> [ByteString] -- ** Breaking into many substrings split, -- :: Word8 -> ByteString -> [ByteString] splitWith, -- :: (Word8 -> Bool) -> ByteString -> [ByteString] -- * Predicates isPrefixOf, -- :: ByteString -> ByteString -> Bool isSuffixOf, -- :: ByteString -> ByteString -> Bool isInfixOf, -- :: ByteString -> ByteString -> Bool -- ** Search for arbitrary substrings breakSubstring, -- :: ByteString -> ByteString -> (ByteString,ByteString) findSubstring, -- :: ByteString -> ByteString -> Maybe Int findSubstrings, -- :: ByteString -> ByteString -> [Int] -- * Searching ByteStrings -- ** Searching by equality elem, -- :: Word8 -> ByteString -> Bool notElem, -- :: Word8 -> ByteString -> Bool -- ** Searching with a predicate find, -- :: (Word8 -> Bool) -> ByteString -> Maybe Word8 filter, -- :: (Word8 -> Bool) -> ByteString -> ByteString partition, -- :: (Word8 -> Bool) -> ByteString -> (ByteString, ByteString) -- * Indexing ByteStrings index, -- :: ByteString -> Int -> Word8 elemIndex, -- :: Word8 -> ByteString -> Maybe Int elemIndices, -- :: Word8 -> ByteString -> [Int] elemIndexEnd, -- :: Word8 -> ByteString -> Maybe Int findIndex, -- :: (Word8 -> Bool) -> ByteString -> Maybe Int findIndices, -- :: (Word8 -> Bool) -> ByteString -> [Int] count, -- :: Word8 -> ByteString -> Int -- * Zipping and unzipping ByteStrings zip, -- :: ByteString -> ByteString -> [(Word8,Word8)] zipWith, -- :: (Word8 -> Word8 -> c) -> ByteString -> ByteString -> [c] unzip, -- :: [(Word8,Word8)] -> (ByteString,ByteString) -- * Ordered ByteStrings sort, -- :: ByteString -> ByteString -- * Low level conversions -- ** Copying ByteStrings copy, -- :: ByteString -> ByteString -- ** Packing 'CString's and pointers packCString, -- :: CString -> IO ByteString packCStringLen, -- :: CStringLen -> IO ByteString -- ** Using ByteStrings as 'CString's useAsCString, -- :: ByteString -> (CString -> IO a) -> IO a useAsCStringLen, -- :: ByteString -> (CStringLen -> IO a) -> IO a -- * I\/O with 'ByteString's -- ** Standard input and output getLine, -- :: IO ByteString getContents, -- :: IO ByteString putStr, -- :: ByteString -> IO () putStrLn, -- :: ByteString -> IO () interact, -- :: (ByteString -> ByteString) -> IO () -- ** Files readFile, -- :: FilePath -> IO ByteString writeFile, -- :: FilePath -> ByteString -> IO () appendFile, -- :: FilePath -> ByteString -> IO () -- ** I\/O with Handles hGetLine, -- :: Handle -> IO ByteString hGetContents, -- :: Handle -> IO ByteString hGet, -- :: Handle -> Int -> IO ByteString hGetNonBlocking, -- :: Handle -> Int -> IO ByteString hPut, -- :: Handle -> ByteString -> IO () hPutStr, -- :: Handle -> ByteString -> IO () hPutStrLn, -- :: Handle -> ByteString -> IO () breakByte ) where import qualified Prelude as P import Prelude hiding (reverse,head,tail,last,init,null ,length,map,lines,foldl,foldr,unlines ,concat,any,take,drop,splitAt,takeWhile ,dropWhile,span,break,elem,filter,maximum ,minimum,all,concatMap,foldl1,foldr1 ,scanl,scanl1,scanr,scanr1 ,readFile,writeFile,appendFile,replicate ,getContents,getLine,putStr,putStrLn,interact ,zip,zipWith,unzip,notElem) import Data.ByteString.Internal import Data.ByteString.Unsafe import qualified Data.List as List import Data.Word (Word8) import Data.Maybe (isJust, listToMaybe) -- Control.Exception.assert not available in yhc or nhc #ifndef __NHC__ import Control.Exception (finally, bracket, assert) #else import Control.Exception (bracket, finally) #endif import qualified Control.Exception as Exception import Control.Monad (when) import Foreign.C.String (CString, CStringLen) import Foreign.C.Types (CSize) import Foreign.ForeignPtr import Foreign.Marshal.Alloc (allocaBytes, mallocBytes, reallocBytes, finalizerFree) import Foreign.Marshal.Array (allocaArray) import Foreign.Ptr import Foreign.Storable (Storable(..)) -- hGetBuf and hPutBuf not available in yhc or nhc import System.IO (stdin,stdout,hClose,hFileSize ,hGetBuf,hPutBuf,openBinaryFile ,Handle,IOMode(..)) import Data.Monoid (Monoid, mempty, mappend, mconcat) #if !defined(__GLASGOW_HASKELL__) import System.IO.Unsafe import qualified System.Environment import qualified System.IO (hGetLine) #endif #if defined(__GLASGOW_HASKELL__) import System.IO (hGetBufNonBlocking) import System.IO.Error (isEOFError) import GHC.Handle import GHC.Prim (Word#, (+#), writeWord8OffAddr#) import GHC.Base (build) import GHC.Word hiding (Word8) import GHC.Ptr (Ptr(..)) import GHC.ST (ST(..)) import GHC.IOBase #endif -- An alternative to Control.Exception (assert) for nhc98 #ifdef __NHC__ #define assert assertS "__FILE__ : __LINE__" assertS :: String -> Bool -> a -> a assertS _ True = id assertS s False = error ("assertion failed at "++s) #endif -- ----------------------------------------------------------------------------- -- -- Useful macros, until we have bang patterns -- #define STRICT1(f) f a | a `seq` False = undefined #define STRICT2(f) f a b | a `seq` b `seq` False = undefined #define STRICT3(f) f a b c | a `seq` b `seq` c `seq` False = undefined #define STRICT4(f) f a b c d | a `seq` b `seq` c `seq` d `seq` False = undefined #define STRICT5(f) f a b c d e | a `seq` b `seq` c `seq` d `seq` e `seq` False = undefined -- ----------------------------------------------------------------------------- instance Eq ByteString where (==) = eq instance Ord ByteString where compare = compareBytes instance Monoid ByteString where mempty = empty mappend = append mconcat = concat -- | /O(n)/ Equality on the 'ByteString' type. eq :: ByteString -> ByteString -> Bool eq a@(PS p s l) b@(PS p' s' l') | l /= l' = False -- short cut on length | p == p' && s == s' = True -- short cut for the same string | otherwise = compareBytes a b == EQ {-# INLINE eq #-} -- ^ still needed -- | /O(n)/ 'compareBytes' provides an 'Ordering' for 'ByteStrings' supporting slices. compareBytes :: ByteString -> ByteString -> Ordering compareBytes (PS x1 s1 l1) (PS x2 s2 l2) | l1 == 0 && l2 == 0 = EQ -- short cut for empty strings | otherwise = inlinePerformIO $ withForeignPtr x1 $ \p1 -> withForeignPtr x2 $ \p2 -> do i <- memcmp (p1 `plusPtr` s1) (p2 `plusPtr` s2) (fromIntegral $ min l1 l2) return $! case i `compare` 0 of EQ -> l1 `compare` l2 x -> x {- -- Pure Haskell version compareBytes (PS fp1 off1 len1) (PS fp2 off2 len2) -- | len1 == 0 && len2 == 0 = EQ -- short cut for empty strings -- | fp1 == fp2 && off1 == off2 && len1 == len2 = EQ -- short cut for the same string | otherwise = inlinePerformIO $ withForeignPtr fp1 $ \p1 -> withForeignPtr fp2 $ \p2 -> cmp (p1 `plusPtr` off1) (p2 `plusPtr` off2) 0 len1 len2 -- XXX todo. cmp :: Ptr Word8 -> Ptr Word8 -> Int -> Int -> Int-> IO Ordering cmp p1 p2 n len1 len2 | n == len1 = if n == len2 then return EQ else return LT | n == len2 = return GT | otherwise = do a <- peekByteOff p1 n :: IO Word8 b <- peekByteOff p2 n case a `compare` b of EQ -> cmp p1 p2 (n+1) len1 len2 LT -> return LT GT -> return GT -} -- ----------------------------------------------------------------------------- -- Introducing and eliminating 'ByteString's -- | /O(1)/ The empty 'ByteString' empty :: ByteString empty = PS nullForeignPtr 0 0 -- | /O(1)/ Convert a 'Word8' into a 'ByteString' singleton :: Word8 -> ByteString singleton c = unsafeCreate 1 $ \p -> poke p c {-# INLINE [1] singleton #-} -- Inline [1] for intercalate rule -- -- XXX The use of unsafePerformIO in allocating functions (unsafeCreate) is critical! -- -- Otherwise: -- -- singleton 255 `compare` singleton 127 -- -- is compiled to: -- -- case mallocByteString 2 of -- ForeignPtr f internals -> -- case writeWord8OffAddr# f 0 255 of _ -> -- case writeWord8OffAddr# f 0 127 of _ -> -- case eqAddr# f f of -- False -> case compare (GHC.Prim.plusAddr# f 0) -- (GHC.Prim.plusAddr# f 0) -- -- -- | /O(n)/ Convert a '[Word8]' into a 'ByteString'. -- -- For applications with large numbers of string literals, pack can be a -- bottleneck. In such cases, consider using packAddress (GHC only). pack :: [Word8] -> ByteString #if !defined(__GLASGOW_HASKELL__) pack str = unsafeCreate (P.length str) $ \p -> go p str where go _ [] = return () go p (x:xs) = poke p x >> go (p `plusPtr` 1) xs -- less space than pokeElemOff #else /* hack away */ pack str = unsafeCreate (P.length str) $ \(Ptr p) -> stToIO (go p 0# str) where go _ _ [] = return () go p i (W8# c:cs) = writeByte p i c >> go p (i +# 1#) cs writeByte p i c = ST $ \s# -> case writeWord8OffAddr# p i c s# of s2# -> (# s2#, () #) #endif -- | /O(n)/ Converts a 'ByteString' to a '[Word8]'. unpack :: ByteString -> [Word8] #if !defined(__GLASGOW_HASKELL__) unpack (PS _ _ 0) = [] unpack (PS ps s l) = inlinePerformIO $ withForeignPtr ps $ \p -> go (p `plusPtr` s) (l - 1) [] where STRICT3(go) go p 0 acc = peek p >>= \e -> return (e : acc) go p n acc = peekByteOff p n >>= \e -> go p (n-1) (e : acc) {-# INLINE unpack #-} #else unpack ps = build (unpackFoldr ps) {-# INLINE unpack #-} -- -- Have unpack fuse with good list consumers -- -- critical this isn't strict in the acc -- as it will break in the presence of list fusion. this is a known -- issue with seq and build/foldr rewrite rules, which rely on lazy -- demanding to avoid bottoms in the list. -- unpackFoldr :: ByteString -> (Word8 -> a -> a) -> a -> a unpackFoldr (PS fp off len) f ch = withPtr fp $ \p -> do let loop q n _ | q `seq` n `seq` False = undefined -- n.b. loop _ (-1) acc = return acc loop q n acc = do a <- peekByteOff q n loop q (n-1) (a `f` acc) loop (p `plusPtr` off) (len-1) ch {-# INLINE [0] unpackFoldr #-} unpackList :: ByteString -> [Word8] unpackList (PS fp off len) = withPtr fp $ \p -> do let STRICT3(loop) loop _ (-1) acc = return acc loop q n acc = do a <- peekByteOff q n loop q (n-1) (a : acc) loop (p `plusPtr` off) (len-1) [] {-# RULES "ByteString unpack-list" [1] forall p . unpackFoldr p (:) [] = unpackList p #-} #endif -- --------------------------------------------------------------------- -- Basic interface -- | /O(1)/ Test whether a ByteString is empty. null :: ByteString -> Bool null (PS _ _ l) = assert (l >= 0) $ l <= 0 {-# INLINE null #-} -- --------------------------------------------------------------------- -- | /O(1)/ 'length' returns the length of a ByteString as an 'Int'. length :: ByteString -> Int length (PS _ _ l) = assert (l >= 0) $ l {-# INLINE length #-} ------------------------------------------------------------------------ -- | /O(n)/ 'cons' is analogous to (:) for lists, but of different -- complexity, as it requires a memcpy. cons :: Word8 -> ByteString -> ByteString cons c (PS x s l) = unsafeCreate (l+1) $ \p -> withForeignPtr x $ \f -> do poke p c memcpy (p `plusPtr` 1) (f `plusPtr` s) (fromIntegral l) {-# INLINE cons #-} -- | /O(n)/ Append a byte to the end of a 'ByteString' snoc :: ByteString -> Word8 -> ByteString snoc (PS x s l) c = unsafeCreate (l+1) $ \p -> withForeignPtr x $ \f -> do memcpy p (f `plusPtr` s) (fromIntegral l) poke (p `plusPtr` l) c {-# INLINE snoc #-} -- todo fuse -- | /O(1)/ Extract the first element of a ByteString, which must be non-empty. -- An exception will be thrown in the case of an empty ByteString. head :: ByteString -> Word8 head (PS x s l) | l <= 0 = errorEmptyList "head" | otherwise = inlinePerformIO $ withForeignPtr x $ \p -> peekByteOff p s {-# INLINE head #-} -- | /O(1)/ Extract the elements after the head of a ByteString, which must be non-empty. -- An exception will be thrown in the case of an empty ByteString. tail :: ByteString -> ByteString tail (PS p s l) | l <= 0 = errorEmptyList "tail" | otherwise = PS p (s+1) (l-1) {-# INLINE tail #-} -- | /O(1)/ Extract the head and tail of a ByteString, returning Nothing -- if it is empty. uncons :: ByteString -> Maybe (Word8, ByteString) uncons (PS x s l) | l <= 0 = Nothing | otherwise = Just (inlinePerformIO $ withForeignPtr x $ \p -> peekByteOff p s, PS x (s+1) (l-1)) {-# INLINE uncons #-} -- | /O(1)/ Extract the last element of a ByteString, which must be finite and non-empty. -- An exception will be thrown in the case of an empty ByteString. last :: ByteString -> Word8 last ps@(PS x s l) | null ps = errorEmptyList "last" | otherwise = inlinePerformIO $ withForeignPtr x $ \p -> peekByteOff p (s+l-1) {-# INLINE last #-} -- | /O(1)/ Return all the elements of a 'ByteString' except the last one. -- An exception will be thrown in the case of an empty ByteString. init :: ByteString -> ByteString init ps@(PS p s l) | null ps = errorEmptyList "init" | otherwise = PS p s (l-1) {-# INLINE init #-} -- | /O(n)/ Append two ByteStrings append :: ByteString -> ByteString -> ByteString append xs ys | null xs = ys | null ys = xs | otherwise = concat [xs,ys] {-# INLINE append #-} -- --------------------------------------------------------------------- -- Transformations -- | /O(n)/ 'map' @f xs@ is the ByteString obtained by applying @f@ to each -- element of @xs@. This function is subject to array fusion. map :: (Word8 -> Word8) -> ByteString -> ByteString map f (PS fp s len) = inlinePerformIO $ withForeignPtr fp $ \a -> create len $ map_ 0 (a `plusPtr` s) where map_ :: Int -> Ptr Word8 -> Ptr Word8 -> IO () STRICT3(map_) map_ n p1 p2 | n >= len = return () | otherwise = do x <- peekByteOff p1 n pokeByteOff p2 n (f x) map_ (n+1) p1 p2 {-# INLINE map #-} -- | /O(n)/ 'reverse' @xs@ efficiently returns the elements of @xs@ in reverse order. reverse :: ByteString -> ByteString reverse (PS x s l) = unsafeCreate l $ \p -> withForeignPtr x $ \f -> c_reverse p (f `plusPtr` s) (fromIntegral l) -- | /O(n)/ The 'intersperse' function takes a 'Word8' and a -- 'ByteString' and \`intersperses\' that byte between the elements of -- the 'ByteString'. It is analogous to the intersperse function on -- Lists. intersperse :: Word8 -> ByteString -> ByteString intersperse c ps@(PS x s l) | length ps < 2 = ps | otherwise = unsafeCreate (2*l-1) $ \p -> withForeignPtr x $ \f -> c_intersperse p (f `plusPtr` s) (fromIntegral l) c -- | The 'transpose' function transposes the rows and columns of its -- 'ByteString' argument. transpose :: [ByteString] -> [ByteString] transpose ps = P.map pack (List.transpose (P.map unpack ps)) -- --------------------------------------------------------------------- -- Reducing 'ByteString's -- | 'foldl', applied to a binary operator, a starting value (typically -- the left-identity of the operator), and a ByteString, reduces the -- ByteString using the binary operator, from left to right. -- -- This function is subject to array fusion. -- foldl :: (a -> Word8 -> a) -> a -> ByteString -> a foldl f v (PS x s l) = inlinePerformIO $ withForeignPtr x $ \ptr -> lgo v (ptr `plusPtr` s) (ptr `plusPtr` (s+l)) where STRICT3(lgo) lgo z p q | p == q = return z | otherwise = do c <- peek p lgo (f z c) (p `plusPtr` 1) q {-# INLINE foldl #-} -- | 'foldl\'' is like 'foldl', but strict in the accumulator. -- However, for ByteStrings, all left folds are strict in the accumulator. -- foldl' :: (a -> Word8 -> a) -> a -> ByteString -> a foldl' = foldl {-# INLINE foldl' #-} -- | 'foldr', applied to a binary operator, a starting value -- (typically the right-identity of the operator), and a ByteString, -- reduces the ByteString using the binary operator, from right to left. foldr :: (Word8 -> a -> a) -> a -> ByteString -> a foldr k v (PS x s l) = inlinePerformIO $ withForeignPtr x $ \ptr -> go v (ptr `plusPtr` (s+l-1)) (ptr `plusPtr` (s-1)) where STRICT3(go) go z p q | p == q = return z | otherwise = do c <- peek p go (c `k` z) (p `plusPtr` (-1)) q -- tail recursive {-# INLINE foldr #-} -- | 'foldr\'' is like 'foldr', but strict in the accumulator. foldr' :: (Word8 -> a -> a) -> a -> ByteString -> a foldr' k v (PS x s l) = inlinePerformIO $ withForeignPtr x $ \ptr -> go v (ptr `plusPtr` (s+l-1)) (ptr `plusPtr` (s-1)) where STRICT3(go) go z p q | p == q = return z | otherwise = do c <- peek p go (c `k` z) (p `plusPtr` (-1)) q -- tail recursive {-# INLINE foldr' #-} -- | 'foldl1' is a variant of 'foldl' that has no starting value -- argument, and thus must be applied to non-empty 'ByteStrings'. -- This function is subject to array fusion. -- An exception will be thrown in the case of an empty ByteString. foldl1 :: (Word8 -> Word8 -> Word8) -> ByteString -> Word8 foldl1 f ps | null ps = errorEmptyList "foldl1" | otherwise = foldl f (unsafeHead ps) (unsafeTail ps) {-# INLINE foldl1 #-} -- | 'foldl1\'' is like 'foldl1', but strict in the accumulator. -- An exception will be thrown in the case of an empty ByteString. foldl1' :: (Word8 -> Word8 -> Word8) -> ByteString -> Word8 foldl1' f ps | null ps = errorEmptyList "foldl1'" | otherwise = foldl' f (unsafeHead ps) (unsafeTail ps) {-# INLINE foldl1' #-} -- | 'foldr1' is a variant of 'foldr' that has no starting value argument, -- and thus must be applied to non-empty 'ByteString's -- An exception will be thrown in the case of an empty ByteString. foldr1 :: (Word8 -> Word8 -> Word8) -> ByteString -> Word8 foldr1 f ps | null ps = errorEmptyList "foldr1" | otherwise = foldr f (last ps) (init ps) {-# INLINE foldr1 #-} -- | 'foldr1\'' is a variant of 'foldr1', but is strict in the -- accumulator. foldr1' :: (Word8 -> Word8 -> Word8) -> ByteString -> Word8 foldr1' f ps | null ps = errorEmptyList "foldr1" | otherwise = foldr' f (last ps) (init ps) {-# INLINE foldr1' #-} -- --------------------------------------------------------------------- -- Special folds -- | /O(n)/ Concatenate a list of ByteStrings. concat :: [ByteString] -> ByteString concat [] = empty concat [ps] = ps concat xs = unsafeCreate len $ \ptr -> go xs ptr where len = P.sum . P.map length $ xs STRICT2(go) go [] _ = return () go (PS p s l:ps) ptr = do withForeignPtr p $ \fp -> memcpy ptr (fp `plusPtr` s) (fromIntegral l) go ps (ptr `plusPtr` l) -- | Map a function over a 'ByteString' and concatenate the results concatMap :: (Word8 -> ByteString) -> ByteString -> ByteString concatMap f = concat . foldr ((:) . f) [] -- foldr (append . f) empty -- | /O(n)/ Applied to a predicate and a ByteString, 'any' determines if -- any element of the 'ByteString' satisfies the predicate. any :: (Word8 -> Bool) -> ByteString -> Bool any _ (PS _ _ 0) = False any f (PS x s l) = inlinePerformIO $ withForeignPtr x $ \ptr -> go (ptr `plusPtr` s) (ptr `plusPtr` (s+l)) where STRICT2(go) go p q | p == q = return False | otherwise = do c <- peek p if f c then return True else go (p `plusPtr` 1) q {-# INLINE any #-} -- todo fuse -- | /O(n)/ Applied to a predicate and a 'ByteString', 'all' determines -- if all elements of the 'ByteString' satisfy the predicate. all :: (Word8 -> Bool) -> ByteString -> Bool all _ (PS _ _ 0) = True all f (PS x s l) = inlinePerformIO $ withForeignPtr x $ \ptr -> go (ptr `plusPtr` s) (ptr `plusPtr` (s+l)) where STRICT2(go) go p q | p == q = return True -- end of list | otherwise = do c <- peek p if f c then go (p `plusPtr` 1) q else return False {-# INLINE all #-} ------------------------------------------------------------------------ -- | /O(n)/ 'maximum' returns the maximum value from a 'ByteString' -- This function will fuse. -- An exception will be thrown in the case of an empty ByteString. maximum :: ByteString -> Word8 maximum xs@(PS x s l) | null xs = errorEmptyList "maximum" | otherwise = inlinePerformIO $ withForeignPtr x $ \p -> c_maximum (p `plusPtr` s) (fromIntegral l) {-# INLINE maximum #-} -- | /O(n)/ 'minimum' returns the minimum value from a 'ByteString' -- This function will fuse. -- An exception will be thrown in the case of an empty ByteString. minimum :: ByteString -> Word8 minimum xs@(PS x s l) | null xs = errorEmptyList "minimum" | otherwise = inlinePerformIO $ withForeignPtr x $ \p -> c_minimum (p `plusPtr` s) (fromIntegral l) {-# INLINE minimum #-} ------------------------------------------------------------------------