bytestring 0.10.10.0 → 0.10.10.1
raw patch · 13 files changed
+179/−57 lines, 13 filesdep +ghc-bignumdep ~QuickChecknew-uploaderPVP ok
version bump matches the API change (PVP)
Dependencies added: ghc-bignum
Dependency ranges changed: QuickCheck
API changes (from Hackage documentation)
Files
- Changelog.md +15/−1
- Data/ByteString.hs +12/−2
- Data/ByteString/Builder/ASCII.hs +21/−11
- Data/ByteString/Builder/Prim.hs +3/−3
- Data/ByteString/Builder/Prim/Binary.hs +0/−3
- Data/ByteString/Builder/Prim/Internal.hs +12/−0
- Data/ByteString/Internal.hs +10/−4
- Data/ByteString/Lazy/Internal.hs +7/−2
- Data/ByteString/Short/Internal.hs +1/−1
- bytestring.cabal +39/−8
- tests/Properties.hs +34/−18
- tests/Rules.hs +10/−1
- tests/builder/Data/ByteString/Builder/Tests.hs +15/−3
Changelog.md view
@@ -1,3 +1,18 @@+0.10.10.1 – June 2020++ * Fix off-by-one infinite loop in primMapByteStringBounded ([#203])+ * Don't perform unaligned writes when it isn't known to be safe ([#133])+ * Improve the performance of sconcat for lazy and strict bytestrings ([#142])+ * Document inadvertent 0.10.6.0 behaviour change in findSubstrings+ * Fix benchmark builds ([#52])+ * Documentation fixes+ * Test fixes++[#52]: https://github.com/haskell/bytestring/issues/52+[#133]: https://github.com/haskell/bytestring/pull/133+[#142]: https://github.com/haskell/bytestring/pull/142+[#203]: https://github.com/haskell/bytestring/issues/203+ 0.10.10.0 July 2019 <duncan+haskell@dcoutts.me.uk> July 2019 * Build with GHC 8.8, and tests with QC 2.10+@@ -41,4 +56,3 @@ * Fix strictness of lazy bytestring foldl' * Numerous minor documentation fixes * Various testsuite improvements-
Data/ByteString.hs view
@@ -1413,9 +1413,11 @@ {-# DEPRECATED findSubstring "findSubstring is deprecated in favour of breakSubstring." #-} --- | Find the indexes of all (possibly overlapping) occurences of a--- substring in a string.+-- | Find the indices of all non-overlapping occurences of a substring in a+-- string. --+-- Note, prior to @0.10.6.0@ this function returned the indices of all+-- possibly-overlapping matches. findSubstrings :: ByteString -- ^ String to search for. -> ByteString -- ^ String to seach in. -> [Int]@@ -1432,6 +1434,14 @@ where (a, b) = breakSubstring pat (unsafeDrop n src) +-- In+-- [0.10.6.0](<https://github.com/haskell/bytestring/commit/2160e091e215fecc9177d55a37cd50fc253ba86a?w=1>)+-- 'findSubstrings' was refactored to call an improved 'breakString'+-- implementation, but the refactored code no longer matches overlapping+-- strings. The behaviour change appears to be inadvertent, but the function+-- had already been deprecated for more than seven years. At this time+-- (@0.10.10.1@), the deprecation was twelve years in the past.+-- {-# DEPRECATED findSubstrings "findSubstrings is deprecated in favour of breakSubstring." #-} -- ---------------------------------------------------------------------
Data/ByteString/Builder/ASCII.hs view
@@ -85,23 +85,25 @@ import Foreign -#if defined(INTEGER_GMP)+#if __GLASGOW_HASKELL__ >= 811 -#if !(MIN_VERSION_base(4,8,0))+import GHC.Num.Integer+#define HAS_INTEGER_CONSTR 1+#define quotRemInteger integerQuotRem#++#elif defined(INTEGER_GMP)++#define HAS_INTEGER_CONSTR 1+#define IS S#++# if !(MIN_VERSION_base(4,8,0)) import Data.Monoid (mappend) # endif-import Foreign.C.Types -import qualified Data.ByteString.Builder.Prim.Internal as P-import Data.ByteString.Builder.Prim.Internal.UncheckedShifts- ( caseWordSize_32_64 )- # if __GLASGOW_HASKELL__ < 710 import GHC.Num (quotRemInteger) # endif-import GHC.Types (Int(..)) - # if __GLASGOW_HASKELL__ < 611 import GHC.Integer.Internals # else@@ -109,6 +111,14 @@ # endif #endif +#if HAS_INTEGER_CONSTR+import qualified Data.ByteString.Builder.Prim.Internal as P+import Data.ByteString.Builder.Prim.Internal.UncheckedShifts+ ( caseWordSize_32_64 )+import Foreign.C.Types+import GHC.Types (Int(..))+#endif+ ------------------------------------------------------------------------------ -- Decimal Encoding ------------------------------------------------------------------------------@@ -304,7 +314,7 @@ -- Fast decimal 'Integer' encoding. ------------------------------------------------------------------------------ -#if defined(INTEGER_GMP)+#if HAS_INTEGER_CONSTR -- An optimized version of the integer serialization code -- in blaze-textual (c) 2011 MailRank, Inc. Bryan O'Sullivan -- <bos@mailrank.com>. It is 2.5x faster on Int-sized integers and 4.5x faster@@ -323,7 +333,7 @@ -- | Decimal encoding of an 'Integer' using the ASCII digits. integerDec :: Integer -> Builder-integerDec (S# i#) = intDec (I# i#)+integerDec (IS i#) = intDec (I# i#) integerDec i | i < 0 = P.primFixed P.char8 '-' `mappend` go (-i) | otherwise = go ( i)
Data/ByteString/Builder/Prim.hs view
@@ -633,9 +633,9 @@ -- using a 'BoundedPrim'. For example, we can write a 'Builder' that filters -- a strict 'S.ByteString' as follows. ----- > import Data.ByteString.Builder.Primas P (word8, condB, emptyB)+-- > import qualified Data.ByteString.Builder.Prim as P ----- > filterBS p = P.condB p P.word8 P.emptyB+-- > filterBS p = P.condB p (P.liftFixedToBounded P.word8) P.emptyB -- {-# INLINE primMapByteStringBounded #-} primMapByteStringBounded :: BoundedPrim Word8 -> S.ByteString -> Builder@@ -652,7 +652,7 @@ touchForeignPtr ifp -- input buffer consumed k br - | op0 `plusPtr` bound < ope =+ | op0 `plusPtr` bound <= ope = goPartial (ip0 `plusPtr` min outRemaining inpRemaining) | otherwise = return $ bufferFull bound op0 (goBS ip0)
Data/ByteString/Builder/Prim/Binary.hs view
@@ -272,9 +272,6 @@ int64LE = fromIntegral >$< word64LE --- TODO: Ensure that they are safe on architectures where an unaligned write is--- an error.- -- | Encode a single native machine 'Int'. The 'Int's is encoded in host order, -- host endian form, for the machine you are on. On a 64 bit machine the 'Int' -- is an 8 byte value, on a 32 bit machine, 4 bytes. Values encoded this way
Data/ByteString/Builder/Prim/Internal.hs view
@@ -198,7 +198,19 @@ {-# INLINE CONLIKE storableToF #-} storableToF :: forall a. Storable a => FixedPrim a+-- Not all architectures are forgiving of unaligned accesses; whitelist ones+-- which are known not to trap (either to the kernel for emulation, or crash).+#if defined(i386_HOST_ARCH) || defined(x86_64_HOST_ARCH) \+ || ((defined(arm_HOST_ARCH) || defined(aarch64_HOST_ARCH)) \+ && defined(__ARM_FEATURE_UNALIGNED)) \+ || defined(powerpc_HOST_ARCH) || defined(powerpc64_HOST_ARCH) \+ || defined(powerpc64le_HOST_ARCH) storableToF = FP (sizeOf (undefined :: a)) (\x op -> poke (castPtr op) x)+#else+storableToF = FP (sizeOf (undefined :: a)) $ \x op ->+ if (ptrToWordPtr op) `mod` (fromIntegral (alignment (undefined :: a))) == 0 then poke (castPtr op) x+ else with x $ \tp -> copyBytes op (castPtr tp) (sizeOf (undefined :: a))+#endif {- {-# INLINE CONLIKE liftIOF #-}
Data/ByteString/Internal.hs view
@@ -91,9 +91,14 @@ import Foreign.C.String (CString) -#if !(MIN_VERSION_base(4,11,0)) && MIN_VERSION_base(4,9,0)-import Data.Semigroup (Semigroup((<>)))+#if MIN_VERSION_base(4,13,0)+import Data.Semigroup (Semigroup (sconcat))+import Data.List.NonEmpty (NonEmpty ((:|)))+#elif MIN_VERSION_base(4,9,0)+import Data.Semigroup (Semigroup ((<>), sconcat))+import Data.List.NonEmpty (NonEmpty ((:|))) #endif+ #if !(MIN_VERSION_base(4,8,0)) import Data.Monoid (Monoid(..)) #endif@@ -156,6 +161,7 @@ #if MIN_VERSION_base(4,9,0) instance Semigroup ByteString where (<>) = append+ sconcat (b:|bs) = concat (b:bs) #endif instance Monoid ByteString where@@ -264,8 +270,8 @@ go !_ !0 cs = return (len, cs) go !p !n (c:cs) = poke p (c2w c) >> go (p `plusPtr` 1) (n-1) cs --- Unpacking bytestrings into lists effeciently is a tradeoff: on the one hand--- we would like to write a tight loop that just blats the list into memory, on+-- Unpacking bytestrings into lists efficiently is a tradeoff: on the one hand+-- we would like to write a tight loop that just blasts the list into memory, on -- the other hand we want it to be unpacked lazily so we don't end up with a -- massive list data structure in memory. --
Data/ByteString/Lazy/Internal.hs view
@@ -51,8 +51,12 @@ import Data.Word (Word8) import Foreign.Storable (Storable(sizeOf)) -#if !(MIN_VERSION_base(4,11,0)) && MIN_VERSION_base(4,9,0)-import Data.Semigroup (Semigroup((<>)))+#if MIN_VERSION_base(4,13,0)+import Data.Semigroup (Semigroup (sconcat))+import Data.List.NonEmpty (NonEmpty ((:|)))+#elif MIN_VERSION_base(4,9,0)+import Data.Semigroup (Semigroup ((<>), sconcat))+import Data.List.NonEmpty (NonEmpty ((:|))) #endif #if !(MIN_VERSION_base(4,8,0)) import Data.Monoid (Monoid(..))@@ -84,6 +88,7 @@ #if MIN_VERSION_base(4,9,0) instance Semigroup ByteString where (<>) = append+ sconcat (b:|bs) = concat (b:bs) #endif instance Monoid ByteString where
Data/ByteString/Short/Internal.hs view
@@ -111,7 +111,7 @@ -- | A compact representation of a 'Word8' vector. ----- It has a lower memory overhead than a 'ByteString' and and does not+-- It has a lower memory overhead than a 'ByteString' and does not -- contribute to heap fragmentation. It can be converted to or from a -- 'ByteString' (at the cost of copying the string data). It supports very few -- other operations.
bytestring.cabal view
@@ -1,5 +1,5 @@ Name: bytestring-Version: 0.10.10.0+Version: 0.10.10.1 Synopsis: Fast, compact, strict and lazy byte strings with a list interface Description: An efficient compact, immutable byte string type (both strict and lazy)@@ -54,7 +54,9 @@ Maintainer: Duncan Coutts <duncan@community.haskell.org> Homepage: https://github.com/haskell/bytestring Bug-reports: https://github.com/haskell/bytestring/issues-Tested-With: GHC==7.10.1, GHC==7.8.4, GHC==7.6.3, GHC==7.4.2, GHC==6.12.3+Tested-With: GHC==8.10.1, GHC==8.8.3, GHC==8.6.5, GHC==8.4.4, GHC==8.2.2,+ GHC==8.0.2, GHC==7.10.3, GHC==7.8.4, GHC==7.6.3, GHC==7.4.2,+ GHC==7.2.2, GHC==7.0.4 Build-Type: Simple Cabal-Version: >= 1.10 extra-source-files: README.md Changelog.md@@ -133,7 +135,10 @@ install-includes: fpstring.h -- flags for the decimal integer serialization code- if impl(ghc >= 6.11)+ if impl(ghc >= 8.11)+ build-depends: ghc-bignum >= 1.0++ if impl(ghc >= 6.11) && impl(ghc < 8.11) if !flag(integer-simple) cpp-options: -DINTEGER_GMP build-depends: integer-gmp >= 0.2@@ -150,10 +155,19 @@ other-modules: Rules QuickCheckUtils TestFramework+ Data.ByteString+ Data.ByteString.Char8+ Data.ByteString.Internal+ Data.ByteString.Lazy+ Data.ByteString.Lazy.Char8+ Data.ByteString.Lazy.Internal+ Data.ByteString.Short+ Data.ByteString.Short.Internal+ Data.ByteString.Unsafe hs-source-dirs: . tests build-depends: base, ghc-prim, deepseq, random, directory, test-framework, test-framework-quickcheck2,- QuickCheck >= 2.10 && < 2.14+ QuickCheck >= 2.10 && < 2.15 c-sources: cbits/fpstring.c include-dirs: include ghc-options: -fwarn-unused-binds@@ -191,14 +205,31 @@ type: exitcode-stdio-1.0 hs-source-dirs: . tests tests/builder main-is: TestSuite.hs- other-modules: Data.ByteString.Builder.Tests- Data.ByteString.Builder.Prim.Tests+ other-modules: Data.ByteString+ Data.ByteString.Internal+ Data.ByteString.Lazy+ Data.ByteString.Lazy.Internal+ Data.ByteString.Short+ Data.ByteString.Short.Internal+ Data.ByteString.Unsafe+ Data.ByteString.Builder+ Data.ByteString.Builder.ASCII+ Data.ByteString.Builder.Extra+ Data.ByteString.Builder.Internal+ Data.ByteString.Builder.Prim+ Data.ByteString.Builder.Prim.ASCII+ Data.ByteString.Builder.Prim.Binary+ Data.ByteString.Builder.Prim.Internal+ Data.ByteString.Builder.Prim.Internal.Base16+ Data.ByteString.Builder.Prim.Internal.Floating+ Data.ByteString.Builder.Prim.Internal.UncheckedShifts Data.ByteString.Builder.Prim.TestUtils+ Data.ByteString.Builder.Prim.Tests+ Data.ByteString.Builder.Tests TestFramework- build-depends: base, ghc-prim, deepseq,- QuickCheck >= 2.10 && < 2.14,+ QuickCheck >= 2.10 && < 2.15, byteorder == 1.0.*, dlist >= 0.5 && < 0.9, directory,
tests/Properties.hs view
@@ -1240,31 +1240,47 @@ prop_tailsBB xs = tails xs == map P.unpack (P.tails (P.pack xs)) -prop_findSubstringsBB s x l- = C.findSubstrings (C.pack p) (C.pack s) == naive_findSubstrings p s+-- The correspondence between the test 'ByteString' and naive test 'String'+-- must be injective, otherwise the ByteString may find matches at positions+-- that don't match in the "corresponding" string. To that end, we start+-- with and pack a Word8 array, rather than a unicode String.+--+prop_findSubstringsBB :: [Word8] -> Int -> Int -> Bool+prop_findSubstringsBB ws x l+ = let bstr = P.pack ws+ -- we look for some random substring of the test string+ slice = C.take l $ C.drop x bstr+ str = C.unpack bstr+ substr = C.unpack slice+ in C.findSubstrings slice bstr == naive_findSubstrings substr str where- _ = l :: Int- _ = x :: Int-- -- we look for some random substring of the test string- p = take (model l) $ drop (model x) s- -- naive reference implementation+ -- Note, overlapping matches have been broken since 2015, so at this+ -- point just test for the current behaviour. naive_findSubstrings :: String -> String -> [Int]- naive_findSubstrings p s = [x | x <- [0..length s], p `isPrefixOf` drop x s]+ naive_findSubstrings p q+ | null p = [0..length q]+ | otherwise = go 0 (length p) p (length q) q+ go n !lp p !lq q =+ if (lp > lq)+ then []+ else if p `isPrefixOf` q+ then n : go (n + lp) lp p (lq - lp) (drop lp q)+ else go (n + 1) lp p (lq - 1) (tail q) -prop_findSubstringBB s x l- = C.findSubstring (C.pack p) (C.pack s) == naive_findSubstring p s+-- See above re injective string -> bytestring correspondence.+prop_findSubstringBB :: [Word8] -> Int -> Int -> Bool+prop_findSubstringBB ws x l+ = let bstr = P.pack ws+ -- we look for some random substring of the test string+ slice = C.take l $ C.drop x bstr+ str = C.unpack bstr+ substr = C.unpack slice+ in C.findSubstring slice bstr == naive_findSubstring substr str where- _ = l :: Int- _ = x :: Int-- -- we look for some random substring of the test string- p = take (model l) $ drop (model x) s- -- naive reference implementation naive_findSubstring :: String -> String -> Maybe Int- naive_findSubstring p s = listToMaybe [x | x <- [0..length s], p `isPrefixOf` drop x s]+ naive_findSubstring p q = listToMaybe [x | x <- [0..length q], p `isPrefixOf` drop x q] -- correspondance between break and breakSubstring prop_breakSubstringBB c l
tests/Rules.hs view
@@ -11,6 +11,7 @@ import qualified Data.ByteString.Lazy.Char8 as D import Data.List import Data.Char+import Data.Word import QuickCheckUtils @@ -21,7 +22,15 @@ #endif -prop_break_C x = C.break ((==) x) `eq1` break ((==) x)+prop_break_C :: Word8 -> C.ByteString -> Bool+prop_break_C w = C.break ((==) x) `eq1` break ((==) x)+ where+ -- Make sure we're not testing non-octet character values, for which+ -- C.break is not isomorphic to breaking the corresponding string,+ -- Instead start with a byte, and make a character out of that.+ x = chr $ fromIntegral w++prop_break_P :: Word8 -> C.ByteString -> Bool prop_break_P x = P.break ((==) x) `eq1` break ((==) x) prop_intercalate_P c = (\s1 s2 -> P.intercalate (P.singleton c) (s1 : s2 : [])) `eq2`
tests/builder/Data/ByteString/Builder/Tests.hs view
@@ -98,10 +98,22 @@ testProperty "hPutBuilder" testRecipe where testRecipe :: (UnicodeString, UnicodeString, UnicodeString, Recipe) -> Bool- testRecipe args@(UnicodeString before,- UnicodeString between,- UnicodeString after, recipe) =+ testRecipe args = unsafePerformIO $ do+ let (UnicodeString a1, UnicodeString a2, UnicodeString a3, recipe) = args+#if MIN_VERSION_base(4,5,0)+ before = a1+ between = a2+ after = a3+#else+ -- See https://github.com/haskell/bytestring/issues/212+ -- write -> read does not roundrip with GHC 7.2 and+ -- characters in the \xEF00-\xEFFF range.+ safeChr = \c -> c < '\xEF00' || c > '\xEFFF'+ before = filter safeChr a1+ between = filter safeChr a2+ after = filter safeChr a3+#endif tempDir <- getTemporaryDirectory (tempFile, tempH) <- openTempFile tempDir "TestBuilder" -- switch to UTF-8 encoding