From 43d159c841fbfd04355460639b7320e4e5f62813 Mon Sep 17 00:00:00 2001 From: Edward Kmett Date: Wed, 5 Jun 2019 17:03:49 -0400 Subject: [PATCH] Use plusForeignPtr (Close #174) --- Data/ByteString.hs | 233 +++++++++--------- Data/ByteString/Builder/Internal.hs | 10 +- Data/ByteString/Builder/Prim.hs | 6 +- .../Builder/Prim/Internal/Base16.hs | 2 +- Data/ByteString/Char8.hs | 16 +- Data/ByteString/Internal.hs | 171 +++++++++---- Data/ByteString/Lazy.hs | 14 +- Data/ByteString/Lazy/Internal.hs | 8 +- Data/ByteString/Short/Internal.hs | 9 +- Data/ByteString/Unsafe.hs | 40 +-- bytestring.cabal | 2 +- tests/Hash.hs | 13 +- tests/Words.hs | 10 +- tests/test-compare.hs | 15 +- tests/unpack.hs | 4 +- 15 files changed, 309 insertions(+), 244 deletions(-) diff --git a/Data/ByteString.hs b/Data/ByteString.hs index 8d80d262d..bd29635d8 100644 --- a/Data/ByteString.hs +++ b/Data/ByteString.hs @@ -292,7 +292,7 @@ finiteBitSize = bitSize -- | /O(1)/ The empty 'ByteString' empty :: ByteString -empty = PS nullForeignPtr 0 0 +empty = BS nullForeignPtr 0 -- | /O(1)/ Convert a 'Word8' into a 'ByteString' singleton :: Word8 -> ByteString @@ -349,13 +349,13 @@ unpackFoldr bs k z = foldr k z bs -- | /O(1)/ Test whether a ByteString is empty. null :: ByteString -> Bool -null (PS _ _ l) = assert (l >= 0) $ l <= 0 +null (BS _ 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 +length (BS _ l) = assert (l >= 0) l {-# INLINE length #-} ------------------------------------------------------------------------ @@ -366,15 +366,15 @@ infixl 5 `snoc` -- | /O(n)/ 'cons' is analogous to (:) for lists, but of different -- complexity, as it requires making a copy. cons :: Word8 -> ByteString -> ByteString -cons c (PS x s l) = unsafeCreate (l+1) $ \p -> withForeignPtr x $ \f -> do +cons c (BS x l) = unsafeCreate (l+1) $ \p -> withForeignPtr x $ \f -> do poke p c - memcpy (p `plusPtr` 1) (f `plusPtr` s) (fromIntegral l) + memcpy (p `plusPtr` 1) f (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) +snoc (BS x l) c = unsafeCreate (l+1) $ \p -> withForeignPtr x $ \f -> do + memcpy p f (fromIntegral l) poke (p `plusPtr` l) c {-# INLINE snoc #-} @@ -383,54 +383,54 @@ snoc (PS x s l) c = unsafeCreate (l+1) $ \p -> withForeignPtr x $ \f -> do -- | /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) +head (BS x l) | l <= 0 = errorEmptyList "head" - | otherwise = accursedUnutterablePerformIO $ withForeignPtr x $ \p -> peekByteOff p s + | otherwise = accursedUnutterablePerformIO $ withForeignPtr x $ \p -> peek p {-# 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) +tail (BS p l) | l <= 0 = errorEmptyList "tail" - | otherwise = PS p (s+1) (l-1) + | otherwise = BS (plusForeignPtr p 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) +uncons (BS x l) | l <= 0 = Nothing | otherwise = Just (accursedUnutterablePerformIO $ withForeignPtr x - $ \p -> peekByteOff p s, - PS x (s+1) (l-1)) + $ \p -> peek p, + BS (plusForeignPtr x 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) +last ps@(BS x l) | null ps = errorEmptyList "last" | otherwise = accursedUnutterablePerformIO $ - withForeignPtr x $ \p -> peekByteOff p (s+l-1) + withForeignPtr x $ \p -> peekByteOff p (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) +init ps@(BS p l) | null ps = errorEmptyList "init" - | otherwise = PS p s (l-1) + | otherwise = BS p (l-1) {-# INLINE init #-} -- | /O(1)/ Extract the 'init' and 'last' of a ByteString, returning Nothing -- if it is empty. unsnoc :: ByteString -> Maybe (ByteString, Word8) -unsnoc (PS x s l) +unsnoc (BS x l) | l <= 0 = Nothing - | otherwise = Just (PS x s (l-1), + | otherwise = Just (BS x (l-1), accursedUnutterablePerformIO $ - withForeignPtr x $ \p -> peekByteOff p (s+l-1)) + withForeignPtr x $ \p -> peekByteOff p (l-1)) {-# INLINE unsnoc #-} -- | /O(n)/ Append two ByteStrings @@ -444,8 +444,8 @@ append = mappend -- | /O(n)/ 'map' @f xs@ is the ByteString obtained by applying @f@ to each -- element of @xs@. map :: (Word8 -> Word8) -> ByteString -> ByteString -map f (PS fp s len) = unsafeDupablePerformIO $ withForeignPtr fp $ \a -> - create len $ map_ 0 (a `plusPtr` s) +map f (BS fp len) = unsafeDupablePerformIO $ withForeignPtr fp $ \a -> + create len $ map_ 0 a where map_ :: Int -> Ptr Word8 -> Ptr Word8 -> IO () map_ !n !p1 !p2 @@ -458,18 +458,18 @@ map f (PS fp s len) = unsafeDupablePerformIO $ withForeignPtr fp $ \a -> -- | /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) +reverse (BS x l) = unsafeCreate l $ \p -> withForeignPtr x $ \f -> + c_reverse p f (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) +intersperse c ps@(BS x l) | length ps < 2 = ps | otherwise = unsafeCreate (2*l-1) $ \p -> withForeignPtr x $ \f -> - c_intersperse p (f `plusPtr` s) (fromIntegral l) c + c_intersperse p f (fromIntegral l) c -- | The 'transpose' function transposes the rows and columns of its -- 'ByteString' argument. @@ -484,9 +484,9 @@ transpose ps = P.map pack . List.transpose . P.map unpack $ ps -- ByteString using the binary operator, from left to right. -- foldl :: (a -> Word8 -> a) -> a -> ByteString -> a -foldl f z (PS fp off len) = +foldl f z (BS fp len) = let p = unsafeForeignPtrToPtr fp - in go (p `plusPtr` (off+len-1)) (p `plusPtr` (off-1)) + in go (p `plusPtr` (len-1)) (p `plusPtr` (-1)) where -- not tail recursive; traverses array right to left go !p !q | p == q = z @@ -500,9 +500,9 @@ foldl f z (PS fp off len) = -- | 'foldl'' is like 'foldl', but strict in the accumulator. -- foldl' :: (a -> Word8 -> a) -> a -> ByteString -> a -foldl' f v (PS fp off len) = +foldl' f v (BS fp len) = accursedUnutterablePerformIO $ withForeignPtr fp $ \p -> - go v (p `plusPtr` off) (p `plusPtr` (off+len)) + go v p (p `plusPtr` len) where -- tail recursive; traverses array left to right go !z !p !q | p == q = return z @@ -514,9 +514,9 @@ foldl' f v (PS fp off len) = -- (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 z (PS fp off len) = +foldr k z (BS fp len) = let p = unsafeForeignPtrToPtr fp - in go (p `plusPtr` off) (p `plusPtr` (off+len)) + in go p (p `plusPtr` len) where -- not tail recursive; traverses array left to right go !p !q | p == q = z @@ -529,9 +529,9 @@ foldr k z (PS fp off len) = -- | 'foldr'' is like 'foldr', but strict in the accumulator. foldr' :: (Word8 -> a -> a) -> a -> ByteString -> a -foldr' k v (PS fp off len) = +foldr' k v (BS fp len) = accursedUnutterablePerformIO $ withForeignPtr fp $ \p -> - go v (p `plusPtr` (off+len-1)) (p `plusPtr` (off-1)) + go v (p `plusPtr` (len-1)) (p `plusPtr` (-1)) where -- tail recursive; traverses array right to left go !z !p !q | p == q = return z @@ -589,9 +589,9 @@ concatMap f = concat . foldr ((:) . f) [] -- | /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) = accursedUnutterablePerformIO $ withForeignPtr x $ \ptr -> - go (ptr `plusPtr` s) (ptr `plusPtr` (s+l)) +any _ (BS _ 0) = False +any f (BS x l) = accursedUnutterablePerformIO $ withForeignPtr x $ \ptr -> + go ptr (ptr `plusPtr` l) where go !p !q | p == q = return False | otherwise = do c <- peek p @@ -604,9 +604,9 @@ any f (PS x s l) = accursedUnutterablePerformIO $ withForeignPtr x $ \ptr -> -- | /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) = accursedUnutterablePerformIO $ withForeignPtr x $ \ptr -> - go (ptr `plusPtr` s) (ptr `plusPtr` (s+l)) +all _ (BS _ 0) = True +all f (BS x l) = accursedUnutterablePerformIO $ withForeignPtr x $ \ptr -> + go ptr (ptr `plusPtr` l) where go !p !q | p == q = return True -- end of list | otherwise = do c <- peek p @@ -621,20 +621,20 @@ all f (PS x s l) = accursedUnutterablePerformIO $ withForeignPtr x $ \ptr -> -- 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) +maximum xs@(BS x l) | null xs = errorEmptyList "maximum" | otherwise = accursedUnutterablePerformIO $ withForeignPtr x $ \p -> - c_maximum (p `plusPtr` s) (fromIntegral l) + c_maximum p (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) +minimum xs@(BS x l) | null xs = errorEmptyList "minimum" | otherwise = accursedUnutterablePerformIO $ withForeignPtr x $ \p -> - c_minimum (p `plusPtr` s) (fromIntegral l) + c_minimum p (fromIntegral l) {-# INLINE minimum #-} ------------------------------------------------------------------------ @@ -644,10 +644,10 @@ minimum xs@(PS x s l) -- passing an accumulating parameter from left to right, and returning a -- final value of this accumulator together with the new list. mapAccumL :: (acc -> Word8 -> (acc, Word8)) -> acc -> ByteString -> (acc, ByteString) -mapAccumL f acc (PS fp o len) = unsafeDupablePerformIO $ withForeignPtr fp $ \a -> do +mapAccumL f acc (BS fp len) = unsafeDupablePerformIO $ withForeignPtr fp $ \a -> do gp <- mallocByteString len - acc' <- withForeignPtr gp $ \p -> mapAccumL_ acc 0 (a `plusPtr` o) p - return (acc', PS gp 0 len) + acc' <- withForeignPtr gp $ \p -> mapAccumL_ acc 0 a p + return (acc', BS gp len) where mapAccumL_ !s !n !p1 !p2 | n >= len = return s @@ -663,10 +663,10 @@ mapAccumL f acc (PS fp o len) = unsafeDupablePerformIO $ withForeignPtr fp $ \a -- passing an accumulating parameter from right to left, and returning a -- final value of this accumulator together with the new ByteString. mapAccumR :: (acc -> Word8 -> (acc, Word8)) -> acc -> ByteString -> (acc, ByteString) -mapAccumR f acc (PS fp o len) = unsafeDupablePerformIO $ withForeignPtr fp $ \a -> do +mapAccumR f acc (BS fp len) = unsafeDupablePerformIO $ withForeignPtr fp $ \a -> do gp <- mallocByteString len - acc' <- withForeignPtr gp $ \p -> mapAccumR_ acc (len-1) (a `plusPtr` o) p - return $! (acc', PS gp 0 len) + acc' <- withForeignPtr gp $ \p -> mapAccumR_ acc (len-1) a p + return $! (acc', BS gp len) where mapAccumR_ !s !n !p !q | n < 0 = return s @@ -691,10 +691,10 @@ mapAccumR f acc (PS fp o len) = unsafeDupablePerformIO $ withForeignPtr fp $ \a -- scanl :: (Word8 -> Word8 -> Word8) -> Word8 -> ByteString -> ByteString -scanl f v (PS fp s len) = unsafeDupablePerformIO $ withForeignPtr fp $ \a -> +scanl f v (BS fp len) = unsafeDupablePerformIO $ withForeignPtr fp $ \a -> create (len+1) $ \q -> do poke q v - scanl_ v 0 (a `plusPtr` s) (q `plusPtr` 1) + scanl_ v 0 a (q `plusPtr` 1) where scanl_ !z !n !p !q | n >= len = return () @@ -721,10 +721,10 @@ scanl1 f ps -- | scanr is the right-to-left dual of scanl. scanr :: (Word8 -> Word8 -> Word8) -> Word8 -> ByteString -> ByteString -scanr f v (PS fp s len) = unsafeDupablePerformIO $ withForeignPtr fp $ \a -> +scanr f v (BS fp len) = unsafeDupablePerformIO $ withForeignPtr fp $ \a -> create (len+1) $ \q -> do poke (q `plusPtr` len) v - scanr_ v (len-1) (a `plusPtr` s) q + scanr_ v (len-1) a q where scanr_ !z !n !p !q | n < 0 = return () @@ -806,27 +806,27 @@ unfoldrN i f x0 -- | /O(1)/ 'take' @n@, applied to a ByteString @xs@, returns the prefix -- of @xs@ of length @n@, or @xs@ itself if @n > 'length' xs@. take :: Int -> ByteString -> ByteString -take n ps@(PS x s l) +take n ps@(BS x l) | n <= 0 = empty | n >= l = ps - | otherwise = PS x s n + | otherwise = BS x n {-# INLINE take #-} -- | /O(1)/ 'drop' @n xs@ returns the suffix of @xs@ after the first @n@ -- elements, or @[]@ if @n > 'length' xs@. drop :: Int -> ByteString -> ByteString -drop n ps@(PS x s l) +drop n ps@(BS x l) | n <= 0 = ps | n >= l = empty - | otherwise = PS x (s+n) (l-n) + | otherwise = BS (plusForeignPtr x n) (l-n) {-# INLINE drop #-} -- | /O(1)/ 'splitAt' @n xs@ is equivalent to @('take' n xs, 'drop' n xs)@. splitAt :: Int -> ByteString -> (ByteString, ByteString) -splitAt n ps@(PS x s l) +splitAt n ps@(BS x l) | n <= 0 = (empty, ps) | n >= l = (ps, empty) - | otherwise = (PS x s n, PS x (s+n) (l-n)) + | otherwise = (BS x n, BS (plusForeignPtr x n) (l-n)) {-# INLINE splitAt #-} -- | 'takeWhile', applied to a predicate @p@ and a ByteString @xs@, @@ -906,10 +906,10 @@ span p ps = break (not . p) ps -- > span (=='c') "abcd" == spanByte 'c' "abcd" -- spanByte :: Word8 -> ByteString -> (ByteString, ByteString) -spanByte c ps@(PS x s l) = +spanByte c ps@(BS x l) = accursedUnutterablePerformIO $ withForeignPtr x $ \p -> - go (p `plusPtr` s) 0 + go p 0 where go !p !i | i >= l = return (ps, empty) | otherwise = do c' <- peekByteOff p i @@ -958,8 +958,8 @@ spanEnd p ps = splitAt (findFromEndUntil (not.p) ps) ps -- > splitWith (=='a') [] == [] -- splitWith :: (Word8 -> Bool) -> ByteString -> [ByteString] -splitWith _pred (PS _ _ 0) = [] -splitWith pred_ (PS fp off len) = splitWith0 pred# off len fp +splitWith _pred (BS _ 0) = [] +splitWith pred_ (BS fp len) = splitWith0 pred# 0 len fp where pred# c# = pred_ (W8# c#) splitWith0 !pred' !off' !len' !fp' = @@ -974,11 +974,11 @@ splitWith pred_ (PS fp off len) = splitWith0 pred# off len fp -> IO [ByteString] splitLoop pred' p idx' off' len' fp' - | idx' >= len' = return [PS fp' off' idx'] + | idx' >= len' = return [BS (plusForeignPtr fp' off') idx'] | otherwise = do w <- peekElemOff p (off'+idx') if pred' (case w of W8# w# -> w#) - then return (PS fp' off' idx' : + then return (BS (plusForeignPtr fp' off') idx' : splitWith0 pred' (off'+idx'+1) (len'-idx'-1) fp') else splitLoop pred' p (idx'+1) off' len' fp' {-# INLINE splitWith #-} @@ -1000,18 +1000,18 @@ splitWith pred_ (PS fp off len) = splitWith0 pred# off len fp -- are slices of the original. -- split :: Word8 -> ByteString -> [ByteString] -split _ (PS _ _ 0) = [] -split w (PS x s l) = loop 0 +split _ (BS _ 0) = [] +split w (BS x l) = loop 0 where loop !n = let q = accursedUnutterablePerformIO $ withForeignPtr x $ \p -> - memchr (p `plusPtr` (s+n)) + memchr (p `plusPtr` n) w (fromIntegral (l-n)) in if q == nullPtr - then [PS x (s+n) (l-n)] + then [BS (plusForeignPtr x n) (l-n)] else let i = accursedUnutterablePerformIO $ withForeignPtr x $ \p -> - return (q `minusPtr` (p `plusPtr` s)) - in PS x (s+n) (i-n) : loop (i+1) + return (q `minusPtr` p) + in BS (plusForeignPtr x n) (i-n) : loop (i+1) {-# INLINE split #-} @@ -1057,12 +1057,12 @@ intercalate s = concat . List.intersperse s -- with a char. Around 4 times faster than the generalised join. -- intercalateWithByte :: Word8 -> ByteString -> ByteString -> ByteString -intercalateWithByte c f@(PS ffp s l) g@(PS fgp t m) = unsafeCreate len $ \ptr -> +intercalateWithByte c f@(BS ffp l) g@(BS fgp m) = unsafeCreate len $ \ptr -> withForeignPtr ffp $ \fp -> withForeignPtr fgp $ \gp -> do - memcpy ptr (fp `plusPtr` s) (fromIntegral l) + memcpy ptr fp (fromIntegral l) poke (ptr `plusPtr` l) c - memcpy (ptr `plusPtr` (l + 1)) (gp `plusPtr` t) (fromIntegral m) + memcpy (ptr `plusPtr` (l + 1)) gp (fromIntegral m) where len = length f + length g + 1 {-# INLINE intercalateWithByte #-} @@ -1084,10 +1084,9 @@ index ps n -- element, or 'Nothing' if there is no such element. -- This implementation uses memchr(3). elemIndex :: Word8 -> ByteString -> Maybe Int -elemIndex c (PS x s l) = accursedUnutterablePerformIO $ withForeignPtr x $ \p -> do - let p' = p `plusPtr` s - q <- memchr p' c (fromIntegral l) - return $! if q == nullPtr then Nothing else Just $! q `minusPtr` p' +elemIndex c (BS x l) = accursedUnutterablePerformIO $ withForeignPtr x $ \p -> do + q <- memchr p c (fromIntegral l) + return $! if q == nullPtr then Nothing else Just $! q `minusPtr` p {-# INLINE elemIndex #-} -- | /O(n)/ The 'elemIndexEnd' function returns the last index of the @@ -1099,8 +1098,8 @@ elemIndex c (PS x s l) = accursedUnutterablePerformIO $ withForeignPtr x $ \p -> -- > (-) (length xs - 1) `fmap` elemIndex c (reverse xs) -- elemIndexEnd :: Word8 -> ByteString -> Maybe Int -elemIndexEnd ch (PS x s l) = accursedUnutterablePerformIO $ withForeignPtr x $ \p -> - go (p `plusPtr` s) (l-1) +elemIndexEnd ch (BS x l) = accursedUnutterablePerformIO $ withForeignPtr x $ \p -> + go p (l-1) where go !p !i | i < 0 = return Nothing | otherwise = do ch' <- peekByteOff p i @@ -1113,15 +1112,15 @@ elemIndexEnd ch (PS x s l) = accursedUnutterablePerformIO $ withForeignPtr x $ \ -- the indices of all elements equal to the query element, in ascending order. -- This implementation uses memchr(3). elemIndices :: Word8 -> ByteString -> [Int] -elemIndices w (PS x s l) = loop 0 +elemIndices w (BS x l) = loop 0 where loop !n = let q = accursedUnutterablePerformIO $ withForeignPtr x $ \p -> - memchr (p `plusPtr` (n+s)) + memchr (p `plusPtr` n) w (fromIntegral (l - n)) in if q == nullPtr then [] else let i = accursedUnutterablePerformIO $ withForeignPtr x $ \p -> - return (q `minusPtr` (p `plusPtr` s)) + return (q `minusPtr` p) in i : loop (i+1) {-# INLINE elemIndices #-} @@ -1131,15 +1130,15 @@ elemIndices w (PS x s l) = loop 0 -- -- But more efficiently than using length on the intermediate list. count :: Word8 -> ByteString -> Int -count w (PS x s m) = accursedUnutterablePerformIO $ withForeignPtr x $ \p -> - fmap fromIntegral $ c_count (p `plusPtr` s) (fromIntegral m) w +count w (BS x m) = accursedUnutterablePerformIO $ withForeignPtr x $ \p -> + fmap fromIntegral $ c_count p (fromIntegral m) w {-# INLINE count #-} -- | The 'findIndex' function takes a predicate and a 'ByteString' and -- returns the index of the first element in the ByteString -- satisfying the predicate. findIndex :: (Word8 -> Bool) -> ByteString -> Maybe Int -findIndex k (PS x s l) = accursedUnutterablePerformIO $ withForeignPtr x $ \f -> go (f `plusPtr` s) 0 +findIndex k (BS x l) = accursedUnutterablePerformIO $ withForeignPtr x $ \f -> go f 0 where go !ptr !n | n >= l = return Nothing | otherwise = do w <- peek ptr @@ -1174,10 +1173,10 @@ notElem c ps = not (elem c ps) -- returns a ByteString containing those characters that satisfy the -- predicate. filter :: (Word8 -> Bool) -> ByteString -> ByteString -filter k ps@(PS x s l) +filter k ps@(BS x l) | null ps = ps | otherwise = unsafePerformIO $ createAndTrim l $ \p -> withForeignPtr x $ \f -> do - t <- go (f `plusPtr` s) p (f `plusPtr` (s + l)) + t <- go f p (f `plusPtr` l) return $! t `minusPtr` p -- actual length where go !f !t !end | f == end = return t @@ -1237,8 +1236,8 @@ partition f s = unsafeDupablePerformIO $ mid <- sep 0 p end rev mid end let i = mid `minusPtr` p - return (PS fp' 0 i, - PS fp' i (len - i)) + return (BS fp' i, + BS (plusForeignPtr fp' i) (len - i)) where len = length s incr = (`plusPtr` 1) @@ -1267,12 +1266,12 @@ partition f s = unsafeDupablePerformIO $ -- |/O(n)/ The 'isPrefixOf' function takes two ByteStrings and returns 'True' -- if the first is a prefix of the second. isPrefixOf :: ByteString -> ByteString -> Bool -isPrefixOf (PS x1 s1 l1) (PS x2 s2 l2) +isPrefixOf (BS x1 l1) (BS x2 l2) | l1 == 0 = True | l2 < l1 = False | otherwise = accursedUnutterablePerformIO $ withForeignPtr x1 $ \p1 -> withForeignPtr x2 $ \p2 -> do - i <- memcmp (p1 `plusPtr` s1) (p2 `plusPtr` s2) (fromIntegral l1) + i <- memcmp p1 p2 (fromIntegral l1) return $! i == 0 -- | /O(n)/ The 'stripPrefix' function takes two ByteStrings and returns 'Just' @@ -1281,7 +1280,7 @@ isPrefixOf (PS x1 s1 l1) (PS x2 s2 l2) -- -- @since 0.10.8.0 stripPrefix :: ByteString -> ByteString -> Maybe ByteString -stripPrefix bs1@(PS _ _ l1) bs2 +stripPrefix bs1@(BS _ l1) bs2 | bs1 `isPrefixOf` bs2 = Just (unsafeDrop l1 bs2) | otherwise = Nothing @@ -1295,19 +1294,19 @@ stripPrefix bs1@(PS _ _ l1) bs2 -- However, the real implemenation uses memcmp to compare the end of the -- string only, with no reverse required.. isSuffixOf :: ByteString -> ByteString -> Bool -isSuffixOf (PS x1 s1 l1) (PS x2 s2 l2) +isSuffixOf (BS x1 l1) (BS x2 l2) | l1 == 0 = True | l2 < l1 = False | otherwise = accursedUnutterablePerformIO $ withForeignPtr x1 $ \p1 -> withForeignPtr x2 $ \p2 -> do - i <- memcmp (p1 `plusPtr` s1) (p2 `plusPtr` s2 `plusPtr` (l2 - l1)) (fromIntegral l1) + i <- memcmp p1 (p2 `plusPtr` (l2 - l1)) (fromIntegral l1) return $! i == 0 -- | /O(n)/ The 'stripSuffix' function takes two ByteStrings and returns 'Just' -- the remainder of the second iff the first is its suffix, and otherwise -- 'Nothing'. stripSuffix :: ByteString -> ByteString -> Maybe ByteString -stripSuffix bs1@(PS _ _ l1) bs2@(PS _ _ l2) +stripSuffix bs1@(BS _ l1) bs2@(BS _ l2) | bs1 `isSuffixOf` bs2 = Just (unsafeTake (l2 - l1) bs2) | otherwise = Nothing @@ -1474,10 +1473,10 @@ zipWith f ps qs -- performed on the result of zipWith. -- zipWith' :: (Word8 -> Word8 -> Word8) -> ByteString -> ByteString -> ByteString -zipWith' f (PS fp s l) (PS fq t m) = unsafeDupablePerformIO $ +zipWith' f (BS fp l) (BS fq m) = unsafeDupablePerformIO $ withForeignPtr fp $ \a -> withForeignPtr fq $ \b -> - create len $ zipWith_ 0 (a `plusPtr` s) (b `plusPtr` t) + create len $ zipWith_ 0 a b where zipWith_ :: Int -> Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> IO () zipWith_ !n !p1 !p2 !r @@ -1507,7 +1506,7 @@ unzip ls = (pack (P.map fst ls), pack (P.map snd ls)) -- | /O(n)/ Return all initial segments of the given 'ByteString', shortest first. inits :: ByteString -> [ByteString] -inits (PS x s l) = [PS x s n | n <- [0..l]] +inits (BS x l) = [BS x n | n <- [0..l]] -- | /O(n)/ Return all final segments of the given 'ByteString', longest first. tails :: ByteString -> [ByteString] @@ -1521,10 +1520,10 @@ tails p | null p = [empty] -- | /O(n)/ Sort a ByteString efficiently, using counting sort. sort :: ByteString -> ByteString -sort (PS input s l) = unsafeCreate l $ \p -> allocaArray 256 $ \arr -> do +sort (BS input l) = unsafeCreate l $ \p -> allocaArray 256 $ \arr -> do _ <- memset (castPtr arr) 0 (256 * fromIntegral (sizeOf (undefined :: CSize))) - withForeignPtr input (\x -> countOccurrences arr (x `plusPtr` s) l) + withForeignPtr input (\x -> countOccurrences arr x l) let go 256 !_ = return () go i !ptr = do n <- peekElemOff arr i @@ -1553,10 +1552,10 @@ sort (PS input s l) = unsafeCreate l $ \p -> allocaArray 256 $ \arr -> do -- automatically; it must not be stored or used after the -- subcomputation finishes. useAsCString :: ByteString -> (CString -> IO a) -> IO a -useAsCString (PS fp o l) action = +useAsCString (BS fp l) action = allocaBytes (l+1) $ \buf -> withForeignPtr fp $ \p -> do - memcpy buf (p `plusPtr` o) (fromIntegral l) + memcpy buf p (fromIntegral l) pokeByteOff buf l (0::Word8) action (castPtr buf) @@ -1564,7 +1563,7 @@ useAsCString (PS fp o l) action = -- As for @useAsCString@ this function makes a copy of the original @ByteString@. -- It must not be stored or used after the subcomputation finishes. useAsCStringLen :: ByteString -> (CStringLen -> IO a) -> IO a -useAsCStringLen p@(PS _ _ l) f = useAsCString p $ \cstr -> f (cstr,l) +useAsCStringLen p@(BS _ l) f = useAsCString p $ \cstr -> f (cstr,l) ------------------------------------------------------------------------ @@ -1596,8 +1595,8 @@ packCStringLen (_, len) = -- is needed in the rest of the program. -- copy :: ByteString -> ByteString -copy (PS x s l) = unsafeCreate l $ \p -> withForeignPtr x $ \f -> - memcpy p (f `plusPtr` s) (fromIntegral l) +copy (BS x l) = unsafeCreate l $ \p -> withForeignPtr x $ \f -> + memcpy p f (fromIntegral l) -- --------------------------------------------------------------------- -- Line IO @@ -1670,8 +1669,8 @@ mkBigPS _ pss = return $! concat (P.reverse pss) -- | Outputs a 'ByteString' to the specified 'Handle'. hPut :: Handle -> ByteString -> IO () -hPut _ (PS _ _ 0) = return () -hPut h (PS ps s l) = withForeignPtr ps $ \p-> hPutBuf h (p `plusPtr` s) l +hPut _ (BS _ 0) = return () +hPut h (BS ps l) = withForeignPtr ps $ \p-> hPutBuf h p l -- | Similar to 'hPut' except that it will never block. Instead it returns -- any tail that did not get written. This tail may be 'empty' in the case that @@ -1682,8 +1681,8 @@ hPut h (PS ps s l) = withForeignPtr ps $ \p-> hPutBuf h (p `plusPtr` s) l -- function does not work correctly; it behaves identically to 'hPut'. -- hPutNonBlocking :: Handle -> ByteString -> IO ByteString -hPutNonBlocking h bs@(PS ps s l) = do - bytesWritten <- withForeignPtr ps $ \p-> hPutBufNonBlocking h (p `plusPtr` s) l +hPutNonBlocking h bs@(BS ps l) = do + bytesWritten <- withForeignPtr ps $ \p-> hPutBufNonBlocking h p l return $! drop bytesWritten bs -- | A synonym for @hPut@, for compatibility @@ -1808,7 +1807,7 @@ hGetContentsSizeHint hnd = readChunks chunks sz sz' = do fp <- mallocByteString sz readcount <- withForeignPtr fp $ \buf -> hGetBuf hnd buf sz - let chunk = PS fp 0 readcount + let chunk = BS fp readcount -- We rely on the hGetBuf behaviour (not hGetBufSome) where it reads up -- to the size we ask for, or EOF. So short reads indicate EOF. if readcount < sz && sz > 0 @@ -1866,10 +1865,10 @@ appendFile = modifyFile AppendMode -- | 'findIndexOrEnd' is a variant of findIndex, that returns the length -- of the string if no element is found, rather than Nothing. findIndexOrEnd :: (Word8 -> Bool) -> ByteString -> Int -findIndexOrEnd k (PS x s l) = +findIndexOrEnd k (BS x l) = accursedUnutterablePerformIO $ withForeignPtr x $ \f -> - go (f `plusPtr` s) 0 + go f 0 where go !ptr !n | n >= l = return l | otherwise = do w <- peek ptr @@ -1897,7 +1896,7 @@ moduleErrorMsg fun msg = "Data.ByteString." ++ fun ++ ':':' ':msg -- Find from the end of the string using predicate findFromEndUntil :: (Word8 -> Bool) -> ByteString -> Int -findFromEndUntil f ps@(PS x s l) +findFromEndUntil f ps@(BS x l) | null ps = 0 | f (unsafeLast ps) = l - | otherwise = findFromEndUntil f (PS x s (l - 1)) + | otherwise = findFromEndUntil f (BS x (l - 1)) diff --git a/Data/ByteString/Builder/Internal.hs b/Data/ByteString/Builder/Internal.hs index b55e0550d..3fb083052 100644 --- a/Data/ByteString/Builder/Internal.hs +++ b/Data/ByteString/Builder/Internal.hs @@ -203,7 +203,7 @@ newBuffer size = do {-# INLINE byteStringFromBuffer #-} byteStringFromBuffer :: Buffer -> S.ByteString byteStringFromBuffer (Buffer fpbuf (BufferRange op _)) = - S.PS fpbuf 0 (op `minusPtr` unsafeForeignPtrToPtr fpbuf) + S.BS fpbuf (op `minusPtr` unsafeForeignPtrToPtr fpbuf) -- | Prepend the filled part of a 'Buffer' to a lazy 'L.ByteString' -- trimming it if necessary. @@ -857,7 +857,7 @@ byteStringThreshold :: Int -> S.ByteString -> Builder byteStringThreshold maxCopySize = \bs -> builder $ step bs where - step !bs@(S.PS _ _ len) !k br@(BufferRange !op _) + step !bs@(S.BS _ len) !k br@(BufferRange !op _) | len <= maxCopySize = byteStringCopyStep bs k br | otherwise = return $ insertChunk op bs k @@ -873,7 +873,7 @@ byteStringCopy = \bs -> builder $ byteStringCopyStep bs {-# INLINE byteStringCopyStep #-} byteStringCopyStep :: S.ByteString -> BuildStep a -> BuildStep a -byteStringCopyStep (S.PS ifp ioff isize) !k0 br0@(BufferRange op ope) +byteStringCopyStep (S.BS ifp isize) !k0 br0@(BufferRange op ope) -- Ensure that the common case is not recursive and therefore yields -- better code. | op' <= ope = do copyBytes op ip isize @@ -882,7 +882,7 @@ byteStringCopyStep (S.PS ifp ioff isize) !k0 br0@(BufferRange op ope) | otherwise = do wrappedBytesCopyStep (BufferRange ip ipe) k br0 where op' = op `plusPtr` isize - ip = unsafeForeignPtrToPtr ifp `plusPtr` ioff + ip = unsafeForeignPtrToPtr ifp ipe = ip `plusPtr` isize k br = do touchForeignPtr ifp -- input consumed: OK to release here k0 br @@ -1147,7 +1147,7 @@ buildStepToCIOS !(AllocationStrategy nextBuffer bufSize trim) = -- FIXME: We could reuse the trimmed buffer here. return $ Yield1 bs (mkCIOS False) | otherwise = - return $ Yield1 (S.PS fpbuf 0 chunkSize) (mkCIOS False) + return $ Yield1 (S.BS fpbuf chunkSize) (mkCIOS False) where chunkSize = op' `minusPtr` pbuf size = pe `minusPtr` pbuf diff --git a/Data/ByteString/Builder/Prim.hs b/Data/ByteString/Builder/Prim.hs index 4dcc150fb..645ab48aa 100644 --- a/Data/ByteString/Builder/Prim.hs +++ b/Data/ByteString/Builder/Prim.hs @@ -643,10 +643,10 @@ primMapByteStringBounded w = \bs -> builder $ step bs where bound = I.sizeBound w - step (S.PS ifp ioff isize) !k = - goBS (unsafeForeignPtrToPtr ifp `plusPtr` ioff) + step (S.BS ifp isize) !k = + goBS (unsafeForeignPtrToPtr ifp) where - !ipe = unsafeForeignPtrToPtr ifp `plusPtr` (ioff + isize) + !ipe = unsafeForeignPtrToPtr ifp `plusPtr` isize goBS !ip0 !br@(BufferRange op0 ope) | ip0 >= ipe = do touchForeignPtr ifp -- input buffer consumed diff --git a/Data/ByteString/Builder/Prim/Internal/Base16.hs b/Data/ByteString/Builder/Prim/Internal/Base16.hs index e27424f07..aa80dd176 100644 --- a/Data/ByteString/Builder/Prim/Internal/Base16.hs +++ b/Data/ByteString/Builder/Prim/Internal/Base16.hs @@ -48,7 +48,7 @@ import Foreign newtype EncodingTable = EncodingTable (ForeignPtr Word8) tableFromList :: [Word8] -> EncodingTable -tableFromList xs = case S.pack xs of S.PS fp _ _ -> EncodingTable fp +tableFromList xs = case S.pack xs of S.BS fp _ -> EncodingTable fp unsafeIndex :: EncodingTable -> Int -> IO Word8 unsafeIndex (EncodingTable table) = peekElemOff (unsafeForeignPtrToPtr table) diff --git a/Data/ByteString/Char8.hs b/Data/ByteString/Char8.hs index 6b1efb32f..761eed9e9 100644 --- a/Data/ByteString/Char8.hs +++ b/Data/ByteString/Char8.hs @@ -791,12 +791,12 @@ unsafeHead = w2c . B.unsafeHead -- > break isSpace == breakSpace -- breakSpace :: ByteString -> (ByteString,ByteString) -breakSpace (PS x s l) = accursedUnutterablePerformIO $ withForeignPtr x $ \p -> do - i <- firstspace (p `plusPtr` s) 0 l +breakSpace (BS x l) = accursedUnutterablePerformIO $ withForeignPtr x $ \p -> do + i <- firstspace p 0 l return $! case () of {_ - | i == 0 -> (empty, PS x s l) - | i == l -> (PS x s l, empty) - | otherwise -> (PS x s i, PS x (s+i) (l-i)) + | i == 0 -> (empty, BS x l) + | i == l -> (BS x l, empty) + | otherwise -> (BS x i, BS (plusForeignPtr x i) (l-i)) } {-# INLINE breakSpace #-} @@ -813,9 +813,9 @@ firstspace !ptr !n !m -- > dropWhile isSpace == dropSpace -- dropSpace :: ByteString -> ByteString -dropSpace (PS x s l) = accursedUnutterablePerformIO $ withForeignPtr x $ \p -> do - i <- firstnonspace (p `plusPtr` s) 0 l - return $! if i == l then empty else PS x (s+i) (l-i) +dropSpace (BS x l) = accursedUnutterablePerformIO $ withForeignPtr x $ \p -> do + i <- firstnonspace p 0 l + return $! if i == l then empty else BS (plusForeignPtr x i) (l-i) {-# INLINE dropSpace #-} firstnonspace :: Ptr Word8 -> Int -> Int -> IO Int diff --git a/Data/ByteString/Internal.hs b/Data/ByteString/Internal.hs index 4e1e19b21..4fbc838ec 100644 --- a/Data/ByteString/Internal.hs +++ b/Data/ByteString/Internal.hs @@ -1,6 +1,9 @@ {-# LANGUAGE CPP, ForeignFunctionInterface, BangPatterns #-} {-# LANGUAGE UnliftedFFITypes, MagicHash, UnboxedTuples, DeriveDataTypeable #-} +#if __GLASGOW_HASKELL__ >= 800 +{-# LANGUAGE PatternSynonyms, ViewPatterns #-} +#endif #if __GLASGOW_HASKELL__ >= 703 {-# LANGUAGE Unsafe #-} #endif @@ -26,7 +29,12 @@ module Data.ByteString.Internal ( -- * The @ByteString@ type and representation - ByteString(..), -- instances: Eq, Ord, Show, Read, Data, Typeable + ByteString + ( BS +#if __GLASGOW_HASKELL__ >= 800 + , PS -- backwards compatibility shim +#endif + ), -- instances: Eq, Ord, Show, Read, Data, Typeable -- * Conversion with lists: packing and unpacking packBytes, packUptoLenBytes, unsafePackLenBytes, @@ -47,6 +55,8 @@ module Data.ByteString.Internal ( -- * Conversion to and from ForeignPtrs fromForeignPtr, -- :: ForeignPtr Word8 -> Int -> Int -> ByteString toForeignPtr, -- :: ByteString -> (ForeignPtr Word8, Int, Int) + fromForeignPtr0, -- :: ForeignPtr Word8 -> Int -> ByteString + toForeignPtr0, -- :: ByteString -> (ForeignPtr Word8, Int) -- * Utilities nullForeignPtr, -- :: ForeignPtr Word8 @@ -73,7 +83,10 @@ module Data.ByteString.Internal ( -- * Deprecated and unmentionable accursedUnutterablePerformIO, -- :: IO a -> a - inlinePerformIO -- :: IO a -> a + inlinePerformIO, -- :: IO a -> a + + -- * Exported compatibility shim + plusForeignPtr ) where import Prelude hiding (concat, null) @@ -103,6 +116,7 @@ import Data.List.NonEmpty (NonEmpty ((:|))) import Data.Monoid (Monoid(..)) #endif + import Control.DeepSeq (NFData(rnf)) import Data.String (IsString(..)) @@ -133,6 +147,13 @@ import GHC.IOBase (IO(IO),RawBuffer,unsafeDupablePerformIO) import GHC.ForeignPtr (ForeignPtr(ForeignPtr) ,newForeignPtr_, mallocPlainForeignPtrBytes) +#if MIN_VERSION_base(4,10,0) +import GHC.ForeignPtr (plusForeignPtr) +#else +import GHC.Types (Int (..)) +import GHC.Prim (plusAddr#) +#endif + import GHC.Ptr (Ptr(..), castPtr) #if __GLASGOW_HASKELL__ >= 811 @@ -144,6 +165,25 @@ import GHC.ForeignPtr (ForeignPtrContents(FinalPtr)) -- CFILES stuff is Hugs only {-# CFILES cbits/fpstring.c #-} +#if !MIN_VERSION_base(4,10,0) +-- |Advances the given address by the given offset in bytes. +-- +-- The new 'ForeignPtr' shares the finalizer of the original, +-- equivalent from a finalization standpoint to just creating another +-- reference to the original. That is, the finalizer will not be +-- called before the new 'ForeignPtr' is unreachable, nor will it be +-- called an additional time due to this call, and the finalizer will +-- be called with the same address that it would have had this call +-- not happened, *not* the new address. +plusForeignPtr :: ForeignPtr a -> Int -> ForeignPtr b +plusForeignPtr (ForeignPtr addr guts) (I# offset) = ForeignPtr (plusAddr# addr offset) guts +{-# INLINE [0] plusForeignPtr #-} +{-# RULES +"ByteString plusForeignPtr/0" forall fp . + plusForeignPtr fp 0 = fp + #-} +#endif + -- ----------------------------------------------------------------------------- -- | A space-efficient representation of a 'Word8' vector, supporting many @@ -153,11 +193,31 @@ import GHC.ForeignPtr (ForeignPtrContents(FinalPtr)) -- "Data.ByteString.Char8" it can be interpreted as containing 8-bit -- characters. -- -data ByteString = PS {-# UNPACK #-} !(ForeignPtr Word8) -- payload - {-# UNPACK #-} !Int -- offset +data ByteString = BS {-# UNPACK #-} !(ForeignPtr Word8) -- payload {-# UNPACK #-} !Int -- length deriving (Typeable) + +#if __GLASGOW_HASKELL__ >= 800 +-- | +-- @'PS' foreignPtr offset length@ represents a 'ByteString' with data +-- backed by a given @foreignPtr@, starting at a given @offset@ in bytes +-- and of a specified @length@. +-- +-- This pattern is used to emulate the legacy 'ByteString' data +-- constructor, so that pre-existing code generally doesn't need to +-- change to benefit from the simplified 'BS' constructor and can +-- continue to function unchanged. +-- +-- /Note:/ Matching with this constructor will always be given a 0 'offset', +-- as the base will be manipulated by 'plusForeignPtr' instead. +-- +pattern PS :: ForeignPtr Word8 -> Int -> Int -> ByteString +pattern PS fp zero len <- BS fp (((,) 0) -> (zero, len)) where + PS fp o len = BS (plusForeignPtr fp o) len +{-# COMPLETE PS #-} +#endif + instance Eq ByteString where (==) = eq @@ -171,7 +231,7 @@ instance Semigroup ByteString where #endif instance Monoid ByteString where - mempty = PS nullForeignPtr 0 0 + mempty = BS nullForeignPtr 0 #if MIN_VERSION_base(4,9,0) mappend = (<>) #else @@ -180,7 +240,7 @@ instance Monoid ByteString where mconcat = concat instance NFData ByteString where - rnf PS{} = () + rnf BS{} = () instance Show ByteString where showsPrec p ps r = showsPrec p (unpackChars ps) r @@ -253,15 +313,13 @@ unsafePackLenChars len cs0 = unsafePackAddress :: Addr# -> IO ByteString unsafePackAddress addr# = do #if __GLASGOW_HASKELL__ >= 811 - return $ PS + return $ BS (accursedUnutterablePerformIO (newForeignPtr_ (Ptr addr#))) - 0 (I# (cstringLength# addr#)) #else p <- newForeignPtr_ (castPtr cstr) l <- c_strlen cstr - let len = fromIntegral l - return $ PS p 0 len + return $ BS p (fromIntegral l) where cstr :: CString cstr = Ptr addr# @@ -279,10 +337,10 @@ unsafePackAddress addr# = do unsafePackLiteral :: Addr# -> ByteString unsafePackLiteral addr# = #if __GLASGOW_HASKELL__ >= 811 - PS (ForeignPtr addr# FinalPtr) 0 (I# (cstringLength# addr#)) + BS (ForeignPtr addr# FinalPtr) (I# (cstringLength# addr#)) #else let len = accursedUnutterablePerformIO (c_strlen (Ptr addr#)) - in PS (accursedUnutterablePerformIO (newForeignPtr_ (Ptr addr#))) 0 (fromIntegral len) + in BS (accursedUnutterablePerformIO (newForeignPtr_ (Ptr addr#))) (fromIntegral len) #endif {-# INLINE unsafePackLiteral #-} @@ -321,22 +379,22 @@ unpackChars :: ByteString -> [Char] unpackChars bs = unpackAppendCharsLazy bs [] unpackAppendBytesLazy :: ByteString -> [Word8] -> [Word8] -unpackAppendBytesLazy (PS fp off len) xs - | len <= 100 = unpackAppendBytesStrict (PS fp off len) xs - | otherwise = unpackAppendBytesStrict (PS fp off 100) remainder +unpackAppendBytesLazy (BS fp len) xs + | len <= 100 = unpackAppendBytesStrict (BS fp len) xs + | otherwise = unpackAppendBytesStrict (BS fp 100) remainder where - remainder = unpackAppendBytesLazy (PS fp (off+100) (len-100)) xs + remainder = unpackAppendBytesLazy (BS (plusForeignPtr fp 100) (len-100)) xs -- Why 100 bytes you ask? Because on a 64bit machine the list we allocate -- takes just shy of 4k which seems like a reasonable amount. -- (5 words per list element, 8 bytes per word, 100 elements = 4000 bytes) unpackAppendCharsLazy :: ByteString -> [Char] -> [Char] -unpackAppendCharsLazy (PS fp off len) cs - | len <= 100 = unpackAppendCharsStrict (PS fp off len) cs - | otherwise = unpackAppendCharsStrict (PS fp off 100) remainder +unpackAppendCharsLazy (BS fp len) cs + | len <= 100 = unpackAppendCharsStrict (BS fp len) cs + | otherwise = unpackAppendCharsStrict (BS fp 100) remainder where - remainder = unpackAppendCharsLazy (PS fp (off+100) (len-100)) cs + remainder = unpackAppendCharsLazy (BS (plusForeignPtr fp 100) (len-100)) cs -- For these unpack functions, since we're unpacking the whole list strictly we -- build up the result list in an accumulator. This means we have to build up @@ -344,9 +402,9 @@ unpackAppendCharsLazy (PS fp off len) cs -- buffer and loops down until we hit the sentinal: unpackAppendBytesStrict :: ByteString -> [Word8] -> [Word8] -unpackAppendBytesStrict (PS fp off len) xs = +unpackAppendBytesStrict (BS fp len) xs = accursedUnutterablePerformIO $ withForeignPtr fp $ \base -> - loop (base `plusPtr` (off-1)) (base `plusPtr` (off-1+len)) xs + loop (base `plusPtr` (-1)) (base `plusPtr` (-1+len)) xs where loop !sentinal !p acc | p == sentinal = return acc @@ -354,9 +412,9 @@ unpackAppendBytesStrict (PS fp off len) xs = loop sentinal (p `plusPtr` (-1)) (x:acc) unpackAppendCharsStrict :: ByteString -> [Char] -> [Char] -unpackAppendCharsStrict (PS fp off len) xs = +unpackAppendCharsStrict (BS fp len) xs = accursedUnutterablePerformIO $ withForeignPtr fp $ \base -> - loop (base `plusPtr` (off-1)) (base `plusPtr` (off-1+len)) xs + loop (base `plusPtr` (-1)) (base `plusPtr` (-1+len)) xs where loop !sentinal !p acc | p == sentinal = return acc @@ -382,14 +440,25 @@ fromForeignPtr :: ForeignPtr Word8 -> Int -- ^ Offset -> Int -- ^ Length -> ByteString -fromForeignPtr = PS +fromForeignPtr fp o len = BS (plusForeignPtr fp o) len {-# INLINE fromForeignPtr #-} +fromForeignPtr0 :: ForeignPtr Word8 + -> Int -- ^ Length + -> ByteString +fromForeignPtr0 = BS +{-# INLINE fromForeignPtr0 #-} + -- | /O(1)/ Deconstruct a ForeignPtr from a ByteString toForeignPtr :: ByteString -> (ForeignPtr Word8, Int, Int) -- ^ (ptr, offset, length) -toForeignPtr (PS ps s l) = (ps, s, l) +toForeignPtr (BS ps l) = (ps, 0, l) {-# INLINE toForeignPtr #-} +-- | /O(1)/ Deconstruct a ForeignPtr from a ByteString +toForeignPtr0 :: ByteString -> (ForeignPtr Word8, Int) -- ^ (ptr, length) +toForeignPtr0 (BS ps l) = (ps, l) +{-# INLINE toForeignPtr0 #-} + -- | A way of creating ByteStrings outside the IO monad. The @Int@ -- argument gives the final size of the ByteString. unsafeCreate :: Int -> (Ptr Word8 -> IO ()) -> ByteString @@ -413,7 +482,7 @@ create :: Int -> (Ptr Word8 -> IO ()) -> IO ByteString create l f = do fp <- mallocByteString l withForeignPtr fp $ \p -> f p - return $! PS fp 0 l + return $! BS fp l {-# INLINE create #-} -- | Create ByteString of up to size size @l@ and use action @f@ to fill it's @@ -422,7 +491,7 @@ createUptoN :: Int -> (Ptr Word8 -> IO Int) -> IO ByteString createUptoN l f = do fp <- mallocByteString l l' <- withForeignPtr fp $ \p -> f p - assert (l' <= l) $ return $! PS fp 0 l' + assert (l' <= l) $ return $! BS fp l' {-# INLINE createUptoN #-} -- | Create ByteString of up to size @l@ and use action @f@ to fill it's contents which returns its true size. @@ -430,7 +499,7 @@ createUptoN' :: Int -> (Ptr Word8 -> IO (Int, a)) -> IO (ByteString, a) createUptoN' l f = do fp <- mallocByteString l (l', res) <- withForeignPtr fp $ \p -> f p - assert (l' <= l) $ return (PS fp 0 l', res) + assert (l' <= l) $ return (BS fp l', res) {-# INLINE createUptoN' #-} -- | Given the maximum size needed and a function to make the contents @@ -447,7 +516,7 @@ createAndTrim l f = do withForeignPtr fp $ \p -> do l' <- f p if assert (l' <= l) $ l' >= l - then return $! PS fp 0 l + then return $! BS fp l else create l' $ \p' -> memcpy p' p l' {-# INLINE createAndTrim #-} @@ -457,7 +526,7 @@ createAndTrim' l f = do withForeignPtr fp $ \p -> do (off, l', res) <- f p if assert (l' <= l) $ l' >= l - then return (PS fp 0 l, res) + then return (BS fp l, res) else do ps <- create l' $ \p' -> memcpy p' (p `plusPtr` off) l' return (ps, res) @@ -472,32 +541,32 @@ mallocByteString = mallocPlainForeignPtrBytes -- Implementations for Eq, Ord and Monoid instances eq :: ByteString -> ByteString -> Bool -eq a@(PS fp off len) b@(PS fp' off' len') - | len /= len' = False -- short cut on length - | fp == fp' && off == off' = True -- short cut for the same string - | otherwise = compareBytes a b == EQ +eq a@(BS fp len) b@(BS fp' len') + | len /= len' = False -- short cut on length + | fp == fp' = True -- short cut for the same string + | otherwise = compareBytes a b == EQ {-# INLINE eq #-} -- ^ still needed compareBytes :: ByteString -> ByteString -> Ordering -compareBytes (PS _ _ 0) (PS _ _ 0) = EQ -- short cut for empty strings -compareBytes (PS fp1 off1 len1) (PS fp2 off2 len2) = +compareBytes (BS _ 0) (BS _ 0) = EQ -- short cut for empty strings +compareBytes (BS fp1 len1) (BS fp2 len2) = accursedUnutterablePerformIO $ withForeignPtr fp1 $ \p1 -> withForeignPtr fp2 $ \p2 -> do - i <- memcmp (p1 `plusPtr` off1) (p2 `plusPtr` off2) (min len1 len2) + i <- memcmp p1 p2 (min len1 len2) return $! case i `compare` 0 of EQ -> len1 `compare` len2 x -> x append :: ByteString -> ByteString -> ByteString -append (PS _ _ 0) b = b -append a (PS _ _ 0) = a -append (PS fp1 off1 len1) (PS fp2 off2 len2) = +append (BS _ 0) b = b +append a (BS _ 0) = a +append (BS fp1 len1) (BS fp2 len2) = unsafeCreate (len1+len2) $ \destptr1 -> do let destptr2 = destptr1 `plusPtr` len1 - withForeignPtr fp1 $ \p1 -> memcpy destptr1 (p1 `plusPtr` off1) len1 - withForeignPtr fp2 $ \p2 -> memcpy destptr2 (p2 `plusPtr` off2) len2 + withForeignPtr fp1 $ \p1 -> memcpy destptr1 p1 len1 + withForeignPtr fp2 $ \p2 -> memcpy destptr2 p2 len2 concat :: [ByteString] -> ByteString concat = \bss0 -> goLen0 bss0 bss0 @@ -520,26 +589,26 @@ concat = \bss0 -> goLen0 bss0 bss0 where -- It's still possible that the result is empty goLen0 _ [] = mempty - goLen0 bss0 (PS _ _ 0 :bss) = goLen0 bss0 bss + goLen0 bss0 (BS _ 0 :bss) = goLen0 bss0 bss goLen0 bss0 (bs :bss) = goLen1 bss0 bs bss -- It's still possible that the result is a single chunk goLen1 _ bs [] = bs - goLen1 bss0 bs (PS _ _ 0 :bss) = goLen1 bss0 bs bss - goLen1 bss0 bs (PS _ _ len:bss) = goLen bss0 (checkedAdd "concat" len' len) bss - where PS _ _ len' = bs + goLen1 bss0 bs (BS _ 0 :bss) = goLen1 bss0 bs bss + goLen1 bss0 bs (BS _ len:bss) = goLen bss0 (checkedAdd "concat" len' len) bss + where BS _ len' = bs -- General case, just find the total length we'll need - goLen bss0 !total (PS _ _ len:bss) = goLen bss0 total' bss + goLen bss0 !total (BS _ len:bss) = goLen bss0 total' bss where total' = checkedAdd "concat" total len goLen bss0 total [] = unsafeCreate total $ \ptr -> goCopy bss0 ptr -- Copy the data goCopy [] !_ = return () - goCopy (PS _ _ 0 :bss) !ptr = goCopy bss ptr - goCopy (PS fp off len:bss) !ptr = do - withForeignPtr fp $ \p -> memcpy ptr (p `plusPtr` off) len + goCopy (BS _ 0 :bss) !ptr = goCopy bss ptr + goCopy (BS fp len:bss) !ptr = do + withForeignPtr fp $ \p -> memcpy ptr p len goCopy bss (ptr `plusPtr` len) {-# NOINLINE concat #-} diff --git a/Data/ByteString/Lazy.hs b/Data/ByteString/Lazy.hs index 9157826f2..9a1e9b2e9 100644 --- a/Data/ByteString/Lazy.hs +++ b/Data/ByteString/Lazy.hs @@ -309,10 +309,10 @@ toStrict = \cs -> goLen0 cs cs -- Copy the data goCopy Empty !_ = return () - goCopy (Chunk (S.PS _ _ 0 ) cs) !ptr = goCopy cs ptr - goCopy (Chunk (S.PS fp off len) cs) !ptr = do + goCopy (Chunk (S.BS _ 0 ) cs) !ptr = goCopy cs ptr + goCopy (Chunk (S.BS fp len) cs) !ptr = do withForeignPtr fp $ \p -> do - S.memcpy ptr (p `plusPtr` off) len + S.memcpy ptr p len goCopy cs (ptr `plusPtr` len) -- See the comment on Data.ByteString.Internal.concat for some background on -- this implementation. @@ -464,10 +464,10 @@ intersperse _ Empty = Empty intersperse w (Chunk c cs) = Chunk (S.intersperse w c) (foldrChunks (Chunk . intersperse') Empty cs) where intersperse' :: P.ByteString -> P.ByteString - intersperse' (S.PS fp o l) = + intersperse' (S.BS fp l) = S.unsafeCreate (2*l) $ \p' -> withForeignPtr fp $ \p -> do poke p' w - S.c_intersperse (p' `plusPtr` 1) (p `plusPtr` o) (fromIntegral l) w + S.c_intersperse (p' `plusPtr` 1) p (fromIntegral l) w -- | The 'transpose' function transposes the rows and columns of its -- 'ByteString' argument. @@ -1360,9 +1360,9 @@ revChunks cs = L.foldl' (flip chunk) Empty cs -- | 'findIndexOrEnd' is a variant of findIndex, that returns the length -- of the string if no element is found, rather than Nothing. findIndexOrEnd :: (Word8 -> Bool) -> P.ByteString -> Int -findIndexOrEnd k (S.PS x s l) = +findIndexOrEnd k (S.BS x l) = S.accursedUnutterablePerformIO $ - withForeignPtr x $ \f -> go (f `plusPtr` s) 0 + withForeignPtr x $ \f -> go f 0 where go !ptr !n | n >= l = return l | otherwise = do w <- peek ptr diff --git a/Data/ByteString/Lazy/Internal.hs b/Data/ByteString/Lazy/Internal.hs index bd07fb570..cf569c020 100644 --- a/Data/ByteString/Lazy/Internal.hs +++ b/Data/ByteString/Lazy/Internal.hs @@ -153,12 +153,12 @@ unpackChars (Chunk c cs) = S.unpackAppendCharsLazy c (unpackChars cs) -- invariant :: ByteString -> Bool invariant Empty = True -invariant (Chunk (S.PS _ _ len) cs) = len > 0 && invariant cs +invariant (Chunk (S.BS _ len) cs) = len > 0 && invariant cs -- | In a form that checks the invariant lazily. checkInvariant :: ByteString -> ByteString checkInvariant Empty = Empty -checkInvariant (Chunk c@(S.PS _ _ len) cs) +checkInvariant (Chunk c@(S.BS _ len) cs) | len > 0 = Chunk c (checkInvariant cs) | otherwise = error $ "Data.ByteString.Lazy: invariant violation:" ++ show (Chunk c cs) @@ -167,8 +167,8 @@ checkInvariant (Chunk c@(S.PS _ _ len) cs) -- | Smart constructor for 'Chunk'. Guarantees the data type invariant. chunk :: S.ByteString -> ByteString -> ByteString -chunk c@(S.PS _ _ len) cs | len == 0 = cs - | otherwise = Chunk c cs +chunk c@(S.BS _ len) cs | len == 0 = cs + | otherwise = Chunk c cs {-# INLINE chunk #-} -- | Consume the chunks of a lazy ByteString with a natural right fold. diff --git a/Data/ByteString/Short/Internal.hs b/Data/ByteString/Short/Internal.hs index 17ff47db0..8bdc4d754 100644 --- a/Data/ByteString/Short/Internal.hs +++ b/Data/ByteString/Short/Internal.hs @@ -65,7 +65,6 @@ import Foreign.C.Types (CSize(..), CInt(..), CLong(..)) import Foreign.C.Types (CSize, CInt, CLong) #endif import Foreign.Marshal.Alloc (allocaBytes) -import Foreign.Ptr import Foreign.ForeignPtr (touchForeignPtr) #if MIN_VERSION_base(4,5,0) import Foreign.ForeignPtr.Unsafe (unsafeForeignPtrToPtr) @@ -239,10 +238,10 @@ toShort :: ByteString -> ShortByteString toShort !bs = unsafeDupablePerformIO (toShortIO bs) toShortIO :: ByteString -> IO ShortByteString -toShortIO (PS fptr off len) = do +toShortIO (BS fptr len) = do mba <- stToIO (newByteArray len) let ptr = unsafeForeignPtrToPtr fptr - stToIO (copyAddrToByteArray (ptr `plusPtr` off) mba 0 len) + stToIO (copyAddrToByteArray ptr mba 0 len) touchForeignPtr fptr BA# ba# <- stToIO (unsafeFreezeByteArray mba) return (SBS ba# LEN(len)) @@ -261,7 +260,7 @@ fromShortIO sbs = do stToIO (copyByteArray (asBA sbs) 0 mba 0 len) let fp = ForeignPtr (byteArrayContents# (unsafeCoerce# mba#)) (PlainPtr mba#) - return (PS fp 0 len) + return (BS fp len) #else -- Before base 4.6 ForeignPtrContents is not exported from GHC.ForeignPtr -- so we cannot get direct access to the mbarr# @@ -270,7 +269,7 @@ fromShortIO sbs = do let ptr = unsafeForeignPtrToPtr fptr stToIO (copyByteArrayToAddr (asBA sbs) 0 ptr len) touchForeignPtr fptr - return (PS fptr 0 len) + return (BS fptr len) #endif diff --git a/Data/ByteString/Unsafe.hs b/Data/ByteString/Unsafe.hs index a9e29db25..fed1f3c23 100644 --- a/Data/ByteString/Unsafe.hs +++ b/Data/ByteString/Unsafe.hs @@ -51,7 +51,7 @@ module Data.ByteString.Unsafe ( import Data.ByteString.Internal import Foreign.ForeignPtr (newForeignPtr_, newForeignPtr, withForeignPtr) -import Foreign.Ptr (Ptr, plusPtr, castPtr) +import Foreign.Ptr (Ptr, castPtr) import Foreign.Storable (Storable(..)) import Foreign.C.String (CString, CStringLen) @@ -75,30 +75,30 @@ import GHC.Ptr (Ptr(..)) -- check for the empty case, so there is an obligation on the programmer -- to provide a proof that the ByteString is non-empty. unsafeHead :: ByteString -> Word8 -unsafeHead (PS x s l) = assert (l > 0) $ - accursedUnutterablePerformIO $ withForeignPtr x $ \p -> peekByteOff p s +unsafeHead (BS x l) = assert (l > 0) $ + accursedUnutterablePerformIO $ withForeignPtr x $ \p -> peek p {-# INLINE unsafeHead #-} -- | A variety of 'tail' for non-empty ByteStrings. 'unsafeTail' omits the -- check for the empty case. As with 'unsafeHead', the programmer must -- provide a separate proof that the ByteString is non-empty. unsafeTail :: ByteString -> ByteString -unsafeTail (PS ps s l) = assert (l > 0) $ PS ps (s+1) (l-1) +unsafeTail (BS ps l) = assert (l > 0) $ BS (plusForeignPtr ps 1) (l-1) {-# INLINE unsafeTail #-} -- | A variety of 'init' for non-empty ByteStrings. 'unsafeInit' omits the -- check for the empty case. As with 'unsafeHead', the programmer must -- provide a separate proof that the ByteString is non-empty. unsafeInit :: ByteString -> ByteString -unsafeInit (PS ps s l) = assert (l > 0) $ PS ps s (l-1) +unsafeInit (BS ps l) = assert (l > 0) $ BS ps (l-1) {-# INLINE unsafeInit #-} -- | A variety of 'last' for non-empty ByteStrings. 'unsafeLast' omits the -- check for the empty case. As with 'unsafeHead', the programmer must -- provide a separate proof that the ByteString is non-empty. unsafeLast :: ByteString -> Word8 -unsafeLast (PS x s l) = assert (l > 0) $ - accursedUnutterablePerformIO $ withForeignPtr x $ \p -> peekByteOff p (s+l-1) +unsafeLast (BS x l) = assert (l > 0) $ + accursedUnutterablePerformIO $ withForeignPtr x $ \p -> peekByteOff p (l-1) {-# INLINE unsafeLast #-} -- | Unsafe 'ByteString' index (subscript) operator, starting from 0, returning a 'Word8' @@ -106,20 +106,20 @@ unsafeLast (PS x s l) = assert (l > 0) $ -- obligation on the programmer to ensure the bounds are checked in some -- other way. unsafeIndex :: ByteString -> Int -> Word8 -unsafeIndex (PS x s l) i = assert (i >= 0 && i < l) $ - accursedUnutterablePerformIO $ withForeignPtr x $ \p -> peekByteOff p (s+i) +unsafeIndex (BS x l) i = assert (i >= 0 && i < l) $ + accursedUnutterablePerformIO $ withForeignPtr x $ \p -> peekByteOff p i {-# INLINE unsafeIndex #-} -- | A variety of 'take' which omits the checks on @n@ so there is an -- obligation on the programmer to provide a proof that @0 <= n <= 'length' xs@. unsafeTake :: Int -> ByteString -> ByteString -unsafeTake n (PS x s l) = assert (0 <= n && n <= l) $ PS x s n +unsafeTake n (BS x l) = assert (0 <= n && n <= l) $ BS x n {-# INLINE unsafeTake #-} -- | A variety of 'drop' which omits the checks on @n@ so there is an -- obligation on the programmer to provide a proof that @0 <= n <= 'length' xs@. unsafeDrop :: Int -> ByteString -> ByteString -unsafeDrop n (PS x s l) = assert (0 <= n && n <= l) $ PS x (s+n) (l-n) +unsafeDrop n (BS x l) = assert (0 <= n && n <= l) $ BS (plusForeignPtr x n) (l-n) {-# INLINE unsafeDrop #-} @@ -143,7 +143,7 @@ unsafeDrop n (PS x s l) = assert (0 <= n && n <= l) $ PS x (s+n) (l-n) unsafePackAddressLen :: Int -> Addr# -> IO ByteString unsafePackAddressLen len addr# = do p <- newForeignPtr_ (Ptr addr#) - return $ PS p 0 len + return $ BS p len {-# INLINE unsafePackAddressLen #-} -- | /O(1)/ Construct a 'ByteString' given a Ptr Word8 to a buffer, a @@ -158,7 +158,7 @@ unsafePackAddressLen len addr# = do unsafePackCStringFinalizer :: Ptr Word8 -> Int -> IO () -> IO ByteString unsafePackCStringFinalizer p l f = do fp <- FC.newForeignPtr p f - return $ PS fp 0 l + return $ BS fp l -- | Explicitly run the finaliser associated with a 'ByteString'. -- References to this value after finalisation may generate invalid memory @@ -170,7 +170,7 @@ unsafePackCStringFinalizer p l f = do -- ever generated from the underlying byte array are no longer live. -- unsafeFinalize :: ByteString -> IO () -unsafeFinalize (PS p _ _) = FC.finalizeForeignPtr p +unsafeFinalize (BS p _) = FC.finalizeForeignPtr p ------------------------------------------------------------------------ -- Packing CStrings into ByteStrings @@ -188,7 +188,7 @@ unsafePackCString :: CString -> IO ByteString unsafePackCString cstr = do fp <- newForeignPtr_ (castPtr cstr) l <- c_strlen cstr - return $! PS fp 0 (fromIntegral l) + return $! BS fp (fromIntegral l) -- | /O(1)/ Build a 'ByteString' from a 'CStringLen'. This value will -- have /no/ finalizer associated with it, and will not be garbage @@ -202,7 +202,7 @@ unsafePackCString cstr = do unsafePackCStringLen :: CStringLen -> IO ByteString unsafePackCStringLen (ptr,len) = do fp <- newForeignPtr_ (castPtr ptr) - return $! PS fp 0 (fromIntegral len) + return $! BS fp (fromIntegral len) -- | /O(n)/ Build a 'ByteString' from a malloced 'CString'. This value will -- have a @free(3)@ finalizer associated to it. @@ -219,7 +219,7 @@ unsafePackMallocCString :: CString -> IO ByteString unsafePackMallocCString cstr = do fp <- newForeignPtr c_free_finalizer (castPtr cstr) len <- c_strlen cstr - return $! PS fp 0 (fromIntegral len) + return $! BS fp (fromIntegral len) -- | /O(1)/ Build a 'ByteString' from a malloced 'CStringLen'. This -- value will have a @free(3)@ finalizer associated to it. @@ -235,7 +235,7 @@ unsafePackMallocCString cstr = do unsafePackMallocCStringLen :: CStringLen -> IO ByteString unsafePackMallocCStringLen (cstr, len) = do fp <- newForeignPtr c_free_finalizer (castPtr cstr) - return $! PS fp 0 len + return $! BS fp len -- --------------------------------------------------------------------- @@ -265,7 +265,7 @@ unsafePackMallocCStringLen (cstr, len) = do -- after this. -- unsafeUseAsCString :: ByteString -> (CString -> IO a) -> IO a -unsafeUseAsCString (PS ps s _) ac = withForeignPtr ps $ \p -> ac (castPtr p `plusPtr` s) +unsafeUseAsCString (BS ps _) ac = withForeignPtr ps $ \p -> ac (castPtr p) -- | /O(1) construction/ Use a 'ByteString' with a function requiring a -- 'CStringLen'. @@ -283,4 +283,4 @@ unsafeUseAsCString (PS ps s _) ac = withForeignPtr ps $ \p -> ac (castPtr p `plu -- 'useAsCStringLen', which makes a copy of the original 'ByteString'. -- unsafeUseAsCStringLen :: ByteString -> (CStringLen -> IO a) -> IO a -unsafeUseAsCStringLen (PS ps s l) f = withForeignPtr ps $ \p -> f (castPtr p `plusPtr` s,l) +unsafeUseAsCStringLen (BS ps l) f = withForeignPtr ps $ \p -> f (castPtr p,l) diff --git a/bytestring.cabal b/bytestring.cabal index b6384047b..5269c41f9 100644 --- a/bytestring.cabal +++ b/bytestring.cabal @@ -1,5 +1,5 @@ Name: bytestring -Version: 0.10.10.0 +Version: 0.11.0.0 Synopsis: Fast, compact, strict and lazy byte strings with a list interface Description: An efficient compact, immutable byte string type (both strict and lazy) diff --git a/tests/Hash.hs b/tests/Hash.hs index 2e86b55d2..ea7b4e234 100644 --- a/tests/Hash.hs +++ b/tests/Hash.hs @@ -64,16 +64,15 @@ mulHi a b = fromIntegral (r `shiftR` 32) newtype OrdString = OrdString S.ByteString deriving Show -eq a@(S.PS p s l) b@(S.PS p' s' l') - | l /= l' = False -- short cut on length - | p == p' && s == s' = True -- short cut for the same string - | otherwise = compare a b == EQ +eq a@(S.BS p l) b@(S.BS p' l') + | l /= l' = False -- shortcut on length + | p == p' = True -- shortcut for the same string + | otherwise = compare a b == EQ where - compare (S.PS fp1 off1 len1) (S.PS fp2 off2 len2) = S.inlinePerformIO $ + compare (S.BS fp1 len1) (S.BS fp2 len2) = S.inlinePerformIO $ withForeignPtr fp1 $ \p1 -> withForeignPtr fp2 $ \p2 -> - cmp (p1 `plusPtr` off1) - (p2 `plusPtr` off2) 0 len1 len2 + cmp p1 p2 0 len1 len2 cmp :: Ptr Word8 -> Ptr Word8 -> Int -> Int -> Int-> IO Ordering cmp !p1 !p2 !n len1 len2 diff --git a/tests/Words.hs b/tests/Words.hs index 45a561d4b..499185cb1 100644 --- a/tests/Words.hs +++ b/tests/Words.hs @@ -35,11 +35,11 @@ instance Ord OrdString where compare (OrdString p) (OrdString q) = compareBytes p q compareBytes :: ByteString -> ByteString -> Ordering -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 --- | max len1 len2 > 1 = inlinePerformIO $ - | otherwise = inlinePerformIO $ +compareBytes (BS fp1 len1) (BS fp2 len2) + | len1 == 0 && len2 == 0 = EQ -- shortcut for empty strings + | fp1 == fp2 && len1 == len2 = EQ -- shortcut for the same string +-- | max len1 len2 > 1 = inlinePerformIO $ + | otherwise = inlinePerformIO $ withForeignPtr fp1 $ \p1 -> withForeignPtr fp2 $ \p2 -> do i <- memcmp (p1 `plusPtr` off1) (p2 `plusPtr` off2) (fromIntegral $ min len1 len2) diff --git a/tests/test-compare.hs b/tests/test-compare.hs index 77d44c65e..6c0d2c330 100644 --- a/tests/test-compare.hs +++ b/tests/test-compare.hs @@ -37,14 +37,13 @@ main = do ------------------------------------------------------------------------ compareBytes :: ByteString -> ByteString -> Ordering -compareBytes (PS fp1 off1 len1) (PS fp2 off2 len2) +compareBytes (BS fp1 len1) (BS fp2 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 + cmp p1 p2 0 len1 len2 cmp :: Ptr Word8 -> Ptr Word8 -> Int -> Int -> Int-> IO Ordering cmp p1 p2 n len1 len2 @@ -58,13 +57,13 @@ cmp p1 p2 n len1 len2 LT -> return LT GT -> return GT -compareBytesC (PS x1 s1 l1) (PS x2 s2 l2) - | l1 == 0 && l2 == 0 = EQ -- short cut for empty strings - | x1 == x2 && s1 == s2 && l1 == l2 = EQ -- short cut for the same string - | otherwise = inlinePerformIO $ +compareBytesC (BS x1 l1) (BS x2 l2) + | l1 == 0 && l2 == 0 = EQ -- short cut for empty strings + | x1 == x2 && l1 == l2 = EQ -- short cut for the same string + | otherwise = inlinePerformIO $ withForeignPtr x1 $ \p1 -> withForeignPtr x2 $ \p2 -> do - i <- memcmp (p1 `plusPtr` s1) (p2 `plusPtr` s2) (fromIntegral $ min l1 l2) + i <- memcmp p1 p2 (fromIntegral $ min l1 l2) return $! case i `compare` 0 of EQ -> l1 `compare` l2 x -> x diff --git a/tests/unpack.hs b/tests/unpack.hs index 71bcf97c6..27972e3a0 100644 --- a/tests/unpack.hs +++ b/tests/unpack.hs @@ -26,11 +26,11 @@ my_unpack ps = build (unpackFoldr ps) {-# INLINE my_unpack #-} unpackFoldr :: ByteString -> (Word8 -> a -> a) -> a -> a -unpackFoldr (PS fp off len) f ch = +unpackFoldr (BS fp len) f ch = unsafePerformIO $ withForeignPtr fp $ \p -> do let loop a b c | a `seq` b `seq` False = undefined -- needs the strictness 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 + loop p (len-1) ch