packages feed

bytestring 0.11.1.0 → 0.11.2.0

raw patch · 49 files changed

+7182/−4120 lines, 49 filesdep +QuickCheckdep +template-haskelldep −dlistdep −ghc-bignumdep −ghc-byteorderdep ~basedep ~deepseqdep ~ghc-primPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependencies added: QuickCheck, template-haskell

Dependencies removed: dlist, ghc-bignum, ghc-byteorder, integer, integer-gmp, tasty-hunit

Dependency ranges changed: base, deepseq, ghc-prim

API changes (from Hackage documentation)

+ Data.ByteString: fromFilePath :: FilePath -> IO ByteString
+ Data.ByteString: isValidUtf8 :: ByteString -> Bool
+ Data.ByteString: toFilePath :: ByteString -> IO FilePath
+ Data.ByteString: type StrictByteString = ByteString
+ Data.ByteString.Builder: writeFile :: FilePath -> Builder -> IO ()
+ Data.ByteString.Builder.RealFloat: data FloatFormat
+ Data.ByteString.Builder.RealFloat: doubleDec :: Double -> Builder
+ Data.ByteString.Builder.RealFloat: floatDec :: Float -> Builder
+ Data.ByteString.Builder.RealFloat: formatDouble :: FloatFormat -> Double -> Builder
+ Data.ByteString.Builder.RealFloat: formatFloat :: FloatFormat -> Float -> Builder
+ Data.ByteString.Builder.RealFloat: generic :: FloatFormat
+ Data.ByteString.Builder.RealFloat: instance GHC.Show.Show Data.ByteString.Builder.RealFloat.FormatMode
+ Data.ByteString.Builder.RealFloat: scientific :: FloatFormat
+ Data.ByteString.Builder.RealFloat: standard :: Int -> FloatFormat
+ Data.ByteString.Builder.RealFloat: standardDefaultPrecision :: FloatFormat
+ Data.ByteString.Internal: instance Language.Haskell.TH.Syntax.Lift Data.ByteString.Internal.ByteString
+ Data.ByteString.Internal: type StrictByteString = ByteString
+ Data.ByteString.Internal: unsafePackLenAddress :: Int -> Addr# -> IO ByteString
+ Data.ByteString.Internal: unsafePackLenLiteral :: Int -> Addr# -> ByteString
+ Data.ByteString.Lazy: breakEnd :: (Word8 -> Bool) -> ByteString -> (ByteString, ByteString)
+ Data.ByteString.Lazy: dropEnd :: Int64 -> ByteString -> ByteString
+ Data.ByteString.Lazy: dropWhileEnd :: (Word8 -> Bool) -> ByteString -> ByteString
+ Data.ByteString.Lazy: foldr' :: (Word8 -> a -> a) -> a -> ByteString -> a
+ Data.ByteString.Lazy: foldr1' :: HasCallStack => (Word8 -> Word8 -> Word8) -> ByteString -> Word8
+ Data.ByteString.Lazy: scanl1 :: (Word8 -> Word8 -> Word8) -> ByteString -> ByteString
+ Data.ByteString.Lazy: scanr :: (Word8 -> Word8 -> Word8) -> Word8 -> ByteString -> ByteString
+ Data.ByteString.Lazy: scanr1 :: (Word8 -> Word8 -> Word8) -> ByteString -> ByteString
+ Data.ByteString.Lazy: spanEnd :: (Word8 -> Bool) -> ByteString -> (ByteString, ByteString)
+ Data.ByteString.Lazy: takeEnd :: Int64 -> ByteString -> ByteString
+ Data.ByteString.Lazy: takeWhileEnd :: (Word8 -> Bool) -> ByteString -> ByteString
+ Data.ByteString.Lazy: type LazyByteString = ByteString
+ Data.ByteString.Lazy.Char8: breakEnd :: (Char -> Bool) -> ByteString -> (ByteString, ByteString)
+ Data.ByteString.Lazy.Char8: dropEnd :: Int64 -> ByteString -> ByteString
+ Data.ByteString.Lazy.Char8: dropWhileEnd :: (Char -> Bool) -> ByteString -> ByteString
+ Data.ByteString.Lazy.Char8: foldr' :: (Char -> a -> a) -> a -> ByteString -> a
+ Data.ByteString.Lazy.Char8: foldr1' :: (Char -> Char -> Char) -> ByteString -> Char
+ Data.ByteString.Lazy.Char8: scanl1 :: (Char -> Char -> Char) -> ByteString -> ByteString
+ Data.ByteString.Lazy.Char8: scanr :: (Char -> Char -> Char) -> Char -> ByteString -> ByteString
+ Data.ByteString.Lazy.Char8: scanr1 :: (Char -> Char -> Char) -> ByteString -> ByteString
+ Data.ByteString.Lazy.Char8: spanEnd :: (Char -> Bool) -> ByteString -> (ByteString, ByteString)
+ Data.ByteString.Lazy.Char8: takeEnd :: Int64 -> ByteString -> ByteString
+ Data.ByteString.Lazy.Char8: takeWhileEnd :: (Char -> Bool) -> ByteString -> ByteString
+ Data.ByteString.Lazy.Internal: instance Language.Haskell.TH.Syntax.Lift Data.ByteString.Lazy.Internal.ByteString
+ Data.ByteString.Lazy.Internal: type LazyByteString = ByteString
+ Data.ByteString.Short.Internal: instance Language.Haskell.TH.Syntax.Lift Data.ByteString.Short.Internal.ShortByteString
- Data.ByteString: foldl1 :: (Word8 -> Word8 -> Word8) -> ByteString -> Word8
+ Data.ByteString: foldl1 :: HasCallStack => (Word8 -> Word8 -> Word8) -> ByteString -> Word8
- Data.ByteString: foldl1' :: (Word8 -> Word8 -> Word8) -> ByteString -> Word8
+ Data.ByteString: foldl1' :: HasCallStack => (Word8 -> Word8 -> Word8) -> ByteString -> Word8
- Data.ByteString: foldr1 :: (Word8 -> Word8 -> Word8) -> ByteString -> Word8
+ Data.ByteString: foldr1 :: HasCallStack => (Word8 -> Word8 -> Word8) -> ByteString -> Word8
- Data.ByteString: foldr1' :: (Word8 -> Word8 -> Word8) -> ByteString -> Word8
+ Data.ByteString: foldr1' :: HasCallStack => (Word8 -> Word8 -> Word8) -> ByteString -> Word8
- Data.ByteString: head :: ByteString -> Word8
+ Data.ByteString: head :: HasCallStack => ByteString -> Word8
- Data.ByteString: index :: ByteString -> Int -> Word8
+ Data.ByteString: index :: HasCallStack => ByteString -> Int -> Word8
- Data.ByteString: init :: ByteString -> ByteString
+ Data.ByteString: init :: HasCallStack => ByteString -> ByteString
- Data.ByteString: last :: ByteString -> Word8
+ Data.ByteString: last :: HasCallStack => ByteString -> Word8
- Data.ByteString: maximum :: ByteString -> Word8
+ Data.ByteString: maximum :: HasCallStack => ByteString -> Word8
- Data.ByteString: minimum :: ByteString -> Word8
+ Data.ByteString: minimum :: HasCallStack => ByteString -> Word8
- Data.ByteString: tail :: ByteString -> ByteString
+ Data.ByteString: tail :: HasCallStack => ByteString -> ByteString
- Data.ByteString.Char8: init :: ByteString -> ByteString
+ Data.ByteString.Char8: init :: HasCallStack => ByteString -> ByteString
- Data.ByteString.Char8: tail :: ByteString -> ByteString
+ Data.ByteString.Char8: tail :: HasCallStack => ByteString -> ByteString
- Data.ByteString.Lazy: cycle :: ByteString -> ByteString
+ Data.ByteString.Lazy: cycle :: HasCallStack => ByteString -> ByteString
- Data.ByteString.Lazy: foldl1 :: (Word8 -> Word8 -> Word8) -> ByteString -> Word8
+ Data.ByteString.Lazy: foldl1 :: HasCallStack => (Word8 -> Word8 -> Word8) -> ByteString -> Word8
- Data.ByteString.Lazy: foldl1' :: (Word8 -> Word8 -> Word8) -> ByteString -> Word8
+ Data.ByteString.Lazy: foldl1' :: HasCallStack => (Word8 -> Word8 -> Word8) -> ByteString -> Word8
- Data.ByteString.Lazy: foldr1 :: (Word8 -> Word8 -> Word8) -> ByteString -> Word8
+ Data.ByteString.Lazy: foldr1 :: HasCallStack => (Word8 -> Word8 -> Word8) -> ByteString -> Word8
- Data.ByteString.Lazy: head :: ByteString -> Word8
+ Data.ByteString.Lazy: head :: HasCallStack => ByteString -> Word8
- Data.ByteString.Lazy: index :: ByteString -> Int64 -> Word8
+ Data.ByteString.Lazy: index :: HasCallStack => ByteString -> Int64 -> Word8
- Data.ByteString.Lazy: init :: ByteString -> ByteString
+ Data.ByteString.Lazy: init :: HasCallStack => ByteString -> ByteString
- Data.ByteString.Lazy: last :: ByteString -> Word8
+ Data.ByteString.Lazy: last :: HasCallStack => ByteString -> Word8
- Data.ByteString.Lazy: maximum :: ByteString -> Word8
+ Data.ByteString.Lazy: maximum :: HasCallStack => ByteString -> Word8
- Data.ByteString.Lazy: minimum :: ByteString -> Word8
+ Data.ByteString.Lazy: minimum :: HasCallStack => ByteString -> Word8
- Data.ByteString.Lazy: tail :: ByteString -> ByteString
+ Data.ByteString.Lazy: tail :: HasCallStack => ByteString -> ByteString
- Data.ByteString.Lazy.Char8: cycle :: ByteString -> ByteString
+ Data.ByteString.Lazy.Char8: cycle :: HasCallStack => ByteString -> ByteString
- Data.ByteString.Lazy.Char8: init :: ByteString -> ByteString
+ Data.ByteString.Lazy.Char8: init :: HasCallStack => ByteString -> ByteString
- Data.ByteString.Lazy.Char8: tail :: ByteString -> ByteString
+ Data.ByteString.Lazy.Char8: tail :: HasCallStack => ByteString -> ByteString
- Data.ByteString.Short: index :: ShortByteString -> Int -> Word8
+ Data.ByteString.Short: index :: HasCallStack => ShortByteString -> Int -> Word8
- Data.ByteString.Short.Internal: index :: ShortByteString -> Int -> Word8
+ Data.ByteString.Short.Internal: index :: HasCallStack => ShortByteString -> Int -> Word8

Files

Changelog.md view
@@ -1,3 +1,26 @@+[0.11.2.0] — December 2021++* [Add `Data.ByteString.isValidUtf8`](https://github.com/haskell/bytestring/pull/423)+* [Speed up `floatDec` and `doubleDec` using the Ryu algorithm](https://github.com/haskell/bytestring/pull/365)+  - `Data.ByteString.Builder.RealFloat` offers additional custom formatters+    for floating point numbers.+* [Add `StrictByteString` and `LazyByteString` type aliases](https://github.com/haskell/bytestring/pull/378)+* [Add `foldr'`, `foldr1'`, `scanl1`, `scanr`, `scanr1` to `Data.ByteString.Lazy{,.Char8}`](https://github.com/haskell/bytestring/pull/364)+* [Add `takeEnd`, `dropEnd`, `takeWhileEnd`, `dropWhileEnd`, `spanEnd`, `breakEnd` to `Data.ByteString.Lazy{,.Char8}`](https://github.com/haskell/bytestring/pull/395)+* [Add `Data.ByteString.Builder.writeFile` to write `Builder` to file directly](https://github.com/haskell/bytestring/pull/408)+* [Add `Data.ByteString.{from,to}FilePath` for encoding-aware conversions](https://github.com/haskell/bytestring/pull/403)+* [Add `Lift` instances for all flavors of `ByteString`](https://github.com/haskell/bytestring/pull/392)+* [Add `HasCallStack` for partial functions](https://github.com/haskell/bytestring/pull/440)+* [Define `foldl`, `foldl'`, `foldr`, `foldr'`, `mapAccumL`, `mapAccumR`, `scanl`, `scanr` and `filter` with one argument less to allow more inlining](https://github.com/haskell/bytestring/pull/345)+* [Speed up internal loop in `unfoldrN`](https://github.com/haskell/bytestring/pull/356)+* [Speed up `count` with SSE and AVX instructions](https://github.com/haskell/bytestring/pull/202)+* [Improve performance of certain `Builder`s by using a static table for Base16](https://github.com/haskell/bytestring/pull/418)+* [Use `unsafeWithForeignPtr` whenever possible](https://github.com/haskell/bytestring/pull/401)+* [Remove `integer-simple` flag](https://github.com/haskell/bytestring/pull/371)+* [Remove misleading mentions of fusion](https://github.com/haskell/bytestring/pull/412)++[0.11.2.0]: https://github.com/haskell/bytestring/compare/0.11.1.0...0.11.2.0+ [0.11.1.0] — February 2021  * [Add `Data.ByteString.Char8.findIndexEnd` and `Data.ByteString.Lazy.Char8.{elemIndexEnd,findIndexEnd,unzip}`](https://github.com/haskell/bytestring/pull/342)@@ -55,7 +78,7 @@  * [Add `findIndexEnd` to `Data.ByteString` and `Data.ByteString.Lazy`](https://github.com/haskell/bytestring/pull/155)  * [Add `partition` to `Data.ByteString.Char8` and `Data.ByteString.Lazy.Char8`](https://github.com/haskell/bytestring/pull/251)  * [Add `IsList` instances for strict and lazy `ByteString` and for `ShortByteString`](https://github.com/haskell/bytestring/pull/219)- * [Add `createUpToN'` and `unsafeCreateUpToN'` to `Data.ByteString.Internal`](https://github.com/haskell/bytestring/pull/245)+ * [Add `createUptoN'` and `unsafeCreateUptoN'` to `Data.ByteString.Internal`](https://github.com/haskell/bytestring/pull/245)  * [Add `boundedPrim` to `Data.ByteString.Builder.Prim.Internal` and deprecate `boudedPrim`](https://github.com/haskell/bytestring/pull/246)  * [Deprecate the `Data.ByteString.Lazy.Builder` and `Data.ByteString.Lazy.Builder.{ASCII,Extras}` modules](https://github.com/haskell/bytestring/pull/250)  * [Fix documented complexity of `Data.ByteString.Lazy.length`](https://github.com/haskell/bytestring/pull/255)
Data/ByteString.hs view
@@ -1,11 +1,8 @@-{-# LANGUAGE CPP #-} {-# LANGUAGE BangPatterns #-} {-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE TupleSections #-} {-# OPTIONS_HADDOCK prune #-}-#if __GLASGOW_HASKELL__ >= 701 {-# LANGUAGE Trustworthy #-}-#endif  -- | -- Module      : Data.ByteString@@ -43,173 +40,179 @@  module Data.ByteString ( -        -- * The @ByteString@ type-        ByteString,             -- abstract, instances: Eq, Ord, Show, Read, Data, Typeable, Monoid+        -- * Strict @ByteString@+        ByteString,+        StrictByteString,          -- * Introducing and eliminating 'ByteString's-        empty,                  -- :: ByteString-        singleton,              -- :: Word8   -> ByteString-        pack,                   -- :: [Word8] -> ByteString-        unpack,                 -- :: ByteString -> [Word8]-        fromStrict,             -- :: ByteString -> Lazy.ByteString-        toStrict,               -- :: Lazy.ByteString -> ByteString+        empty,+        singleton,+        pack,+        unpack,+        fromStrict,+        toStrict,+        fromFilePath,+        toFilePath,          -- * Basic interface-        cons,                   -- :: Word8 -> ByteString -> ByteString-        snoc,                   -- :: ByteString -> Word8 -> ByteString-        append,                 -- :: ByteString -> ByteString -> ByteString-        head,                   -- :: ByteString -> Word8-        uncons,                 -- :: ByteString -> Maybe (Word8, ByteString)-        unsnoc,                 -- :: ByteString -> Maybe (ByteString, Word8)-        last,                   -- :: ByteString -> Word8-        tail,                   -- :: ByteString -> ByteString-        init,                   -- :: ByteString -> ByteString-        null,                   -- :: ByteString -> Bool-        length,                 -- :: ByteString -> Int+        cons,+        snoc,+        append,+        head,+        uncons,+        unsnoc,+        last,+        tail,+        init,+        null,+        length,          -- * Transforming ByteStrings-        map,                    -- :: (Word8 -> Word8) -> ByteString -> ByteString-        reverse,                -- :: ByteString -> ByteString-        intersperse,            -- :: Word8 -> ByteString -> ByteString-        intercalate,            -- :: ByteString -> [ByteString] -> ByteString-        transpose,              -- :: [ByteString] -> [ByteString]+        map,+        reverse,+        intersperse,+        intercalate,+        transpose,          -- * 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+        foldl,+        foldl',+        foldl1,+        foldl1', -        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+        foldr,+        foldr',+        foldr1,+        foldr1',          -- ** 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+        concat,+        concatMap,+        any,+        all,+        maximum,+        minimum,          -- * 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+        scanl,+        scanl1,+        scanr,+        scanr1,          -- ** Accumulating maps-        mapAccumL,              -- :: (acc -> Word8 -> (acc, Word8)) -> acc -> ByteString -> (acc, ByteString)-        mapAccumR,              -- :: (acc -> Word8 -> (acc, Word8)) -> acc -> ByteString -> (acc, ByteString)+        mapAccumL,+        mapAccumR,          -- ** 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)+        replicate,+        unfoldr,+        unfoldrN,          -- * Substrings          -- ** Breaking strings-        take,                   -- :: Int -> ByteString -> ByteString-        takeEnd,                -- :: Int -> ByteString -> ByteString-        drop,                   -- :: Int -> ByteString -> ByteString-        dropEnd,                -- :: Int -> ByteString -> ByteString-        splitAt,                -- :: Int -> ByteString -> (ByteString, ByteString)-        takeWhile,              -- :: (Word8 -> Bool) -> ByteString -> ByteString-        takeWhileEnd,           -- :: (Word8 -> Bool) -> ByteString -> ByteString-        dropWhile,              -- :: (Word8 -> Bool) -> ByteString -> ByteString-        dropWhileEnd,           -- :: (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]-        stripPrefix,            -- :: ByteString -> ByteString -> Maybe ByteString-        stripSuffix,            -- :: ByteString -> ByteString -> Maybe ByteString+        take,+        takeEnd,+        drop,+        dropEnd,+        splitAt,+        takeWhile,+        takeWhileEnd,+        dropWhile,+        dropWhileEnd,+        span,+        spanEnd,+        break,+        breakEnd,+        group,+        groupBy,+        inits,+        tails,+        stripPrefix,+        stripSuffix,          -- ** Breaking into many substrings-        split,                  -- :: Word8 -> ByteString -> [ByteString]-        splitWith,              -- :: (Word8 -> Bool) -> ByteString -> [ByteString]+        split,+        splitWith,          -- * Predicates-        isPrefixOf,             -- :: ByteString -> ByteString -> Bool-        isSuffixOf,             -- :: ByteString -> ByteString -> Bool-        isInfixOf,              -- :: ByteString -> ByteString -> Bool+        isPrefixOf,+        isSuffixOf,+        isInfixOf, +        -- ** Encoding validation+        isValidUtf8,+         -- ** Search for arbitrary substrings-        breakSubstring,         -- :: ByteString -> ByteString -> (ByteString,ByteString)+        breakSubstring,          -- * Searching ByteStrings          -- ** Searching by equality-        elem,                   -- :: Word8 -> ByteString -> Bool-        notElem,                -- :: Word8 -> ByteString -> Bool+        elem,+        notElem,          -- ** Searching with a predicate-        find,                   -- :: (Word8 -> Bool) -> ByteString -> Maybe Word8-        filter,                 -- :: (Word8 -> Bool) -> ByteString -> ByteString-        partition,              -- :: (Word8 -> Bool) -> ByteString -> (ByteString, ByteString)+        find,+        filter,+        partition,          -- * Indexing ByteStrings-        index,                  -- :: ByteString -> Int -> Word8-        indexMaybe,             -- :: ByteString -> Int -> Maybe Word8-        (!?),                   -- :: ByteString -> Int -> Maybe 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]-        findIndexEnd,           -- :: (Word8 -> Bool) -> ByteString -> Maybe Int-        count,                  -- :: Word8 -> ByteString -> Int+        index,+        indexMaybe,+        (!?),+        elemIndex,+        elemIndices,+        elemIndexEnd,+        findIndex,+        findIndices,+        findIndexEnd,+        count,          -- * Zipping and unzipping ByteStrings-        zip,                    -- :: ByteString -> ByteString -> [(Word8,Word8)]-        zipWith,                -- :: (Word8 -> Word8 -> c) -> ByteString -> ByteString -> [c]-        packZipWith,            -- :: (Word8 -> Word8 -> Word8) -> ByteString -> ByteString -> ByteString-        unzip,                  -- :: [(Word8,Word8)] -> (ByteString,ByteString)+        zip,+        zipWith,+        packZipWith,+        unzip,          -- * Ordered ByteStrings-        sort,                   -- :: ByteString -> ByteString+        sort,          -- * Low level conversions         -- ** Copying ByteStrings-        copy,                   -- :: ByteString -> ByteString+        copy,          -- ** Packing 'CString's and pointers-        packCString,            -- :: CString -> IO ByteString-        packCStringLen,         -- :: CStringLen -> IO ByteString+        packCString,+        packCStringLen,          -- ** Using ByteStrings as 'CString's-        useAsCString,           -- :: ByteString -> (CString    -> IO a) -> IO a-        useAsCStringLen,        -- :: ByteString -> (CStringLen -> IO a) -> IO a+        useAsCString,+        useAsCStringLen,          -- * I\/O with 'ByteString's          -- ** Standard input and output-        getLine,                -- :: IO ByteString-        getContents,            -- :: IO ByteString-        putStr,                 -- :: ByteString -> IO ()-        interact,               -- :: (ByteString -> ByteString) -> IO ()+        getLine,+        getContents,+        putStr,+        interact,          -- ** Files-        readFile,               -- :: FilePath -> IO ByteString-        writeFile,              -- :: FilePath -> ByteString -> IO ()-        appendFile,             -- :: FilePath -> ByteString -> IO ()+        readFile,+        writeFile,+        appendFile,          -- ** I\/O with Handles-        hGetLine,               -- :: Handle -> IO ByteString-        hGetContents,           -- :: Handle -> IO ByteString-        hGet,                   -- :: Handle -> Int -> IO ByteString-        hGetSome,               -- :: Handle -> Int -> IO ByteString-        hGetNonBlocking,        -- :: Handle -> Int -> IO ByteString-        hPut,                   -- :: Handle -> ByteString -> IO ()-        hPutNonBlocking,        -- :: Handle -> ByteString -> IO ByteString-        hPutStr,                -- :: Handle -> ByteString -> IO ()+        hGetLine,+        hGetContents,+        hGet,+        hGetSome,+        hGetNonBlocking,+        hPut,+        hPutNonBlocking,+        hPutStr,   ) where  import qualified Prelude as P@@ -222,16 +225,9 @@                                 ,readFile,writeFile,appendFile,replicate                                 ,getContents,getLine,putStr,putStrLn,interact                                 ,zip,zipWith,unzip,notElem-#if !MIN_VERSION_base(4,6,0)-                                ,catch-#endif                                 ) -#if MIN_VERSION_base(4,7,0) import Data.Bits                (finiteBitSize, shiftL, (.|.), (.&.))-#else-import Data.Bits                (bitSize, shiftL, (.|.), (.&.))-#endif  import Data.ByteString.Internal import Data.ByteString.Lazy.Internal (fromStrict, toStrict)@@ -245,13 +241,9 @@ import Control.Monad            (when, void)  import Foreign.C.String         (CString, CStringLen)-import Foreign.C.Types          (CSize)+import Foreign.C.Types          (CSize (CSize), CInt (CInt)) import Foreign.ForeignPtr       (ForeignPtr, withForeignPtr, touchForeignPtr)-#if MIN_VERSION_base(4,5,0) import Foreign.ForeignPtr.Unsafe(unsafeForeignPtrToPtr)-#else-import Foreign.ForeignPtr       (unsafeForeignPtrToPtr)-#endif import Foreign.Marshal.Alloc    (allocaBytes) import Foreign.Marshal.Array    (allocaArray) import Foreign.Ptr@@ -264,27 +256,21 @@                                 ,IOMode(..),hGetBufSome) import System.IO.Error          (mkIOError, illegalOperationErrorType) -#if !(MIN_VERSION_base(4,8,0))-import Control.Applicative      ((<$>))-import Data.Monoid              (Monoid(..))-#endif- import Data.IORef import GHC.IO.Handle.Internals import GHC.IO.Handle.Types import GHC.IO.Buffer import GHC.IO.BufferedIO as Buffered+import GHC.IO.Encoding          (getFileSystemEncoding) import GHC.IO                   (unsafePerformIO, unsafeDupablePerformIO)+import GHC.Foreign              (newCStringLen, peekCStringLen)+import GHC.Stack.Types          (HasCallStack) import Data.Char                (ord) import Foreign.Marshal.Utils    (copyBytes)  import GHC.Base                 (build) import GHC.Word hiding (Word8) -#if !(MIN_VERSION_base(4,7,0))-finiteBitSize = bitSize-#endif- -- ----------------------------------------------------------------------------- -- Introducing and eliminating 'ByteString's @@ -342,6 +328,41 @@     unpackFoldr bs (:) [] = unpackBytes bs  #-} +-- | Convert a 'FilePath' to a 'ByteString'.+--+-- The 'FilePath' type is expected to use the file system encoding+-- as reported by 'GHC.IO.Encoding.getFileSystemEncoding'. This+-- encoding allows for round-tripping of arbitrary data on platforms+-- that allow arbitrary bytes in their paths. This conversion+-- function does the same thing that `System.IO.openFile` would+-- do when decoding the 'FilePath'.+--+-- This function is in 'IO' because the file system encoding can be+-- changed. If the encoding can be assumed to be constant in your+-- use case, you may invoke this function via 'unsafePerformIO'.+--+-- @since 0.11.2.0+fromFilePath :: FilePath -> IO ByteString+fromFilePath path = do+    enc <- getFileSystemEncoding+    newCStringLen enc path >>= unsafePackMallocCStringLen++-- | Convert a 'ByteString' to a 'FilePath'.+--+-- This function uses the file system encoding, and resulting 'FilePath's+-- can be safely used with standard IO functions and will reference the+-- correct path in the presence of arbitrary non-UTF-8 encoded paths.+--+-- This function is in 'IO' because the file system encoding can be+-- changed. If the encoding can be assumed to be constant in your+-- use case, you may invoke this function via 'unsafePerformIO'.+--+-- @since 0.11.2.0+toFilePath :: ByteString -> IO FilePath+toFilePath path = do+    enc <- getFileSystemEncoding+    useAsCStringLen path (peekCStringLen enc)+ -- --------------------------------------------------------------------- -- Basic interface @@ -376,11 +397,9 @@         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 :: HasCallStack => ByteString -> Word8 head (BS x l)     | l <= 0    = errorEmptyList "head"     | otherwise = accursedUnutterablePerformIO $ unsafeWithForeignPtr x $ \p -> peek p@@ -388,7 +407,7 @@  -- | /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 :: HasCallStack => ByteString -> ByteString tail (BS p l)     | l <= 0    = errorEmptyList "tail"     | otherwise = BS (plusForeignPtr p 1) (l-1)@@ -406,7 +425,7 @@  -- | /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 :: HasCallStack => ByteString -> Word8 last ps@(BS x l)     | null ps   = errorEmptyList "last"     | otherwise = accursedUnutterablePerformIO $@@ -415,7 +434,7 @@  -- | /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 :: HasCallStack => ByteString -> ByteString init ps@(BS p l)     | null ps   = errorEmptyList "init"     | otherwise = BS p (l-1)@@ -484,8 +503,8 @@ -- ByteString using the binary operator, from left to right. -- foldl :: (a -> Word8 -> a) -> a -> ByteString -> a-foldl f z (BS fp len) = go (end `plusPtr` len)-  where+foldl f z = \(BS fp len) ->+  let     end = unsafeForeignPtrToPtr fp `plusPtr` (-1)     -- not tail recursive; traverses array right to left     go !p | p == end  = z@@ -494,14 +513,26 @@                                    touchForeignPtr fp                                    return x'                         in f (go (p `plusPtr` (-1))) x++  in+    go (end `plusPtr` len) {-# INLINE foldl #-} +{-+Note [fold inlining]:++GHC will only inline a function marked INLINE+if it is fully saturated (meaning the number of+arguments provided at the call site is at least+equal to the number of lhs arguments).++-} -- | 'foldl'' is like 'foldl', but strict in the accumulator. -- foldl' :: (a -> Word8 -> a) -> a -> ByteString -> a-foldl' f v (BS fp len) =-    accursedUnutterablePerformIO $ unsafeWithForeignPtr fp g-  where+foldl' f v = \(BS fp len) ->+          -- see fold inlining+  let     g ptr = go v ptr       where         end  = ptr `plusPtr` len@@ -509,14 +540,17 @@         go !z !p | p == end  = return z                  | otherwise = do x <- peek p                                   go (f z x) (p `plusPtr` 1)+  in+    accursedUnutterablePerformIO $ unsafeWithForeignPtr fp g {-# 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 z (BS fp len) = go ptr-  where+foldr k z = \(BS fp len) ->+          -- see fold inlining+  let     ptr = unsafeForeignPtrToPtr fp     end = ptr `plusPtr` len     -- not tail recursive; traverses array left to right@@ -526,13 +560,15 @@                                    touchForeignPtr fp                                    return x'                          in k x (go (p `plusPtr` 1))+  in+    go ptr {-# INLINE foldr #-}  -- | 'foldr'' is like 'foldr', but strict in the accumulator. foldr' :: (Word8 -> a -> a) -> a -> ByteString -> a-foldr' k v (BS fp len) =-    accursedUnutterablePerformIO $ unsafeWithForeignPtr fp g-  where+foldr' k v = \(BS fp len) ->+          -- see fold inlining+  let     g ptr = go v (end `plusPtr` len)       where         end = ptr `plusPtr` (-1)@@ -540,12 +576,15 @@         go !z !p | p == end  = return z                  | otherwise = do x <- peek p                                   go (k x z) (p `plusPtr` (-1))+  in+    accursedUnutterablePerformIO $ unsafeWithForeignPtr fp g+ {-# INLINE foldr' #-}  -- | 'foldl1' is a variant of 'foldl' 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.-foldl1 :: (Word8 -> Word8 -> Word8) -> ByteString -> Word8+foldl1 :: HasCallStack => (Word8 -> Word8 -> Word8) -> ByteString -> Word8 foldl1 f ps = case uncons ps of   Nothing     -> errorEmptyList "foldl1"   Just (h, t) -> foldl f h t@@ -553,7 +592,7 @@  -- | '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' :: HasCallStack => (Word8 -> Word8 -> Word8) -> ByteString -> Word8 foldl1' f ps = case uncons ps of   Nothing     -> errorEmptyList "foldl1'"   Just (h, t) -> foldl' f h t@@ -562,7 +601,7 @@ -- | '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 :: HasCallStack => (Word8 -> Word8 -> Word8) -> ByteString -> Word8 foldr1 f ps = case unsnoc ps of   Nothing -> errorEmptyList "foldr1"   Just (b, c) -> foldr f c b@@ -570,7 +609,7 @@  -- | 'foldr1'' is a variant of 'foldr1', but is strict in the -- accumulator.-foldr1' :: (Word8 -> Word8 -> Word8) -> ByteString -> Word8+foldr1' :: HasCallStack => (Word8 -> Word8 -> Word8) -> ByteString -> Word8 foldr1' f ps = case unsnoc ps of   Nothing -> errorEmptyList "foldr1'"   Just (b, c) -> foldr' f c b@@ -604,21 +643,12 @@                                       else go (p `plusPtr` 1) {-# INLINE [1] any #-} -#if MIN_VERSION_base(4,9,0) {-# RULES "ByteString specialise any (x ==)" forall x.     any (x `eqWord8`) = anyByte x "ByteString specialise any (== x)" forall x.     any (`eqWord8` x) = anyByte x   #-}-#else-{-# RULES-"ByteString specialise any (x ==)" forall x.-    any (x ==) = anyByte x-"ByteString specialise any (== x)" forall x.-    any (== x) = anyByte x-  #-}-#endif  -- | Is any element of 'ByteString' equal to c? anyByte :: Word8 -> ByteString -> Bool@@ -627,8 +657,6 @@     return $! q /= nullPtr {-# INLINE anyByte #-} --- 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@@ -645,28 +673,18 @@                                   else return False {-# INLINE [1] all #-} -#if MIN_VERSION_base(4,9,0) {-# RULES "ByteString specialise all (x /=)" forall x.     all (x `neWord8`) = not . anyByte x "ByteString specialise all (/= x)" forall x.     all (`neWord8` x) = not . anyByte x   #-}-#else-{-# RULES-"ByteString specialise all (x /=)" forall x.-    all (x /=) = not . anyByte x-"ByteString specialise all (/= x)" forall x.-    all (/= x) = not . anyByte x-  #-}-#endif  ------------------------------------------------------------------------  -- | /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 :: HasCallStack => ByteString -> Word8 maximum xs@(BS x l)     | null xs   = errorEmptyList "maximum"     | otherwise = accursedUnutterablePerformIO $ unsafeWithForeignPtr x $ \p ->@@ -674,9 +692,8 @@ {-# 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 :: HasCallStack => ByteString -> Word8 minimum xs@(BS x l)     | null xs   = errorEmptyList "minimum"     | otherwise = accursedUnutterablePerformIO $ unsafeWithForeignPtr x $ \p ->@@ -690,20 +707,21 @@ -- 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 (BS fp len) = unsafeDupablePerformIO $ unsafeWithForeignPtr fp $ \a -> do+mapAccumL f acc = \(BS fp len) -> unsafeDupablePerformIO $ unsafeWithForeignPtr fp $ \a -> do+               -- see fold inlining     gp   <- mallocByteString len+    let+      go src dst = mapAccumL_ acc 0+        where+          mapAccumL_ !s !n+             | n >= len = return s+             | otherwise = do+                  x <- peekByteOff src n+                  let (s', y) = f s x+                  pokeByteOff dst n y+                  mapAccumL_ s' (n+1)     acc' <- unsafeWithForeignPtr gp (go a)     return (acc', BS gp len)-  where-    go src dst = mapAccumL_ acc 0-      where-        mapAccumL_ !s !n-           | n >= len = return s-           | otherwise = do-                x <- peekByteOff src n-                let (s', y) = f s x-                pokeByteOff dst n y-                mapAccumL_ s' (n+1) {-# INLINE mapAccumL #-}  -- | The 'mapAccumR' function behaves like a combination of 'map' and@@ -711,26 +729,27 @@ -- 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 (BS fp len) = unsafeDupablePerformIO $ unsafeWithForeignPtr fp $ \a -> do+mapAccumR f acc = \(BS fp len) -> unsafeDupablePerformIO $ unsafeWithForeignPtr fp $ \a -> do+               -- see fold inlining     gp   <- mallocByteString len+    let+      go src dst = mapAccumR_ acc (len-1)+        where+          mapAccumR_ !s (-1) = return s+          mapAccumR_ !s !n   = do+              x  <- peekByteOff src n+              let (s', y) = f s x+              pokeByteOff dst n y+              mapAccumR_ s' (n-1)     acc' <- unsafeWithForeignPtr gp (go a)     return (acc', BS gp len)-  where-    go src dst = mapAccumR_ acc (len-1)-      where-        mapAccumR_ !s (-1) = return s-        mapAccumR_ !s !n   = do-            x  <- peekByteOff src n-            let (s', y) = f s x-            pokeByteOff dst n y-            mapAccumR_ s' (n-1) {-# INLINE mapAccumR #-}  -- --------------------------------------------------------------------- -- Building ByteStrings  -- | 'scanl' is similar to 'foldl', but returns a list of successive--- reduced values from the left. This function will fuse.+-- reduced values from the left. -- -- > scanl f z [x1, x2, ...] == [z, z `f` x1, (z `f` x1) `f` x2, ...] --@@ -748,28 +767,24 @@     -- ^ input of length n     -> ByteString     -- ^ output of length n+1-scanl f v (BS fp len) = unsafeDupablePerformIO $ unsafeWithForeignPtr fp $ \a ->+scanl f v = \(BS fp len) -> unsafeDupablePerformIO $ unsafeWithForeignPtr fp $ \a ->+         -- see fold inlining     create (len+1) $ \q -> do         poke q v+        let+          go src dst = scanl_ v 0+            where+              scanl_ !z !n+                  | n >= len  = return ()+                  | otherwise = do+                      x <- peekByteOff src n+                      let z' = f z x+                      pokeByteOff dst n z'+                      scanl_ z' (n+1)         go a (q `plusPtr` 1)-  where-    go src dst = scanl_ v 0-      where-        scanl_ !z !n-            | n >= len  = return ()-            | otherwise = do-                x <- peekByteOff src n-                let z' = f z x-                pokeByteOff dst n z'-                scanl_ z' (n+1) {-# INLINE scanl #-} -    -- n.b. haskell's List scan returns a list one bigger than the-    -- input, so we need to snoc here to get some extra space, however,-    -- it breaks map/up fusion (i.e. scanl . map no longer fuses)- -- | 'scanl1' is a variant of 'scanl' that has no starting value argument.--- This function will fuse. -- -- > scanl1 f [x1, x2, ...] == [x1, x1 `f` x2, ...] scanl1 :: (Word8 -> Word8 -> Word8) -> ByteString -> ByteString@@ -797,20 +812,21 @@     -- ^ input of length n     -> ByteString     -- ^ output of length n+1-scanr f v (BS fp len) = unsafeDupablePerformIO $ unsafeWithForeignPtr fp $ \a ->-    create (len+1) $ \q -> do-        poke (q `plusPtr` len) v-        go a q-  where-    go p q = scanr_ v (len-1)-      where-        scanr_ !z !n-            | n < 0     = return ()-            | otherwise = do-                x <- peekByteOff p n-                let z' = f x z-                pokeByteOff q n z'-                scanr_ z' (n-1)+scanr f v = \(BS fp len) -> unsafeDupablePerformIO $ unsafeWithForeignPtr fp $ \a ->+         -- see fold inlining+    create (len+1) $ \b -> do+        poke (b `plusPtr` len) v+        let+          go p q = scanr_ v (len-1)+            where+              scanr_ !z !n+                  | n < 0     = return ()+                  | otherwise = do+                      x <- peekByteOff p n+                      let z' = f x z+                      pokeByteOff q n z'+                      scanr_ z' (n-1)+        go a b {-# INLINE scanr #-}  -- | 'scanr1' is a variant of 'scanr' that has no starting value argument.@@ -870,12 +886,14 @@     | i < 0     = (empty, Just x0)     | otherwise = unsafePerformIO $ createAndTrim' i $ \p -> go p x0 0   where-    go !p !x !n-      | n == i    = return (0, n, Just x)-      | otherwise = case f x of-                      Nothing     -> return (0, n, Nothing)-                      Just (w,x') -> do poke p w-                                        go (p `plusPtr` 1) x' (n+1)+    go !p !x !n = go' x n+      where+        go' !x' !n'+          | n' == i    = return (0, n', Just x')+          | otherwise = case f x' of+                          Nothing      -> return (0, n', Nothing)+                          Just (w,x'') -> do pokeByteOff p n' w+                                             go' x'' (n'+1) {-# INLINE unfoldrN #-}  -- ---------------------------------------------------------------------@@ -950,7 +968,6 @@ takeWhile f ps = unsafeTake (findIndexOrLength (not . f) ps) ps {-# INLINE [1] takeWhile #-} -#if MIN_VERSION_base(4,9,0) {-# RULES "ByteString specialise takeWhile (x /=)" forall x.     takeWhile (x `neWord8`) = fst . breakByte x@@ -961,18 +978,6 @@ "ByteString specialise takeWhile (== x)" forall x.     takeWhile (`eqWord8` x) = fst . spanByte x   #-}-#else-{-# RULES-"ByteString specialise takeWhile (x /=)" forall x.-    takeWhile (x /=) = fst . breakByte x-"ByteString specialise takeWhile (/= x)" forall x.-    takeWhile (/= x) = fst . breakByte x-"ByteString specialise takeWhile (x ==)" forall x.-    takeWhile (x ==) = fst . spanByte x-"ByteString specialise takeWhile (== x)" forall x.-    takeWhile (== x) = fst . spanByte x-  #-}-#endif  -- | Returns the longest (possibly empty) suffix of elements -- satisfying the predicate.@@ -991,7 +996,6 @@ dropWhile f ps = unsafeDrop (findIndexOrLength (not . f) ps) ps {-# INLINE [1] dropWhile #-} -#if MIN_VERSION_base(4,9,0) {-# RULES "ByteString specialise dropWhile (x /=)" forall x.     dropWhile (x `neWord8`) = snd . breakByte x@@ -1002,18 +1006,6 @@ "ByteString specialise dropWhile (== x)" forall x.     dropWhile (`eqWord8` x) = snd . spanByte x   #-}-#else-{-# RULES-"ByteString specialise dropWhile (x /=)" forall x.-    dropWhile (x /=) = snd . breakByte x-"ByteString specialise dropWhile (/= x)" forall x.-    dropWhile (/= x) = snd . breakByte x-"ByteString specialise dropWhile (x ==)" forall x.-    dropWhile (x ==) = snd . spanByte x-"ByteString specialise dropWhile (== x)" forall x.-    dropWhile (== x) = snd . spanByte x-  #-}-#endif  -- | Similar to 'P.dropWhileEnd', -- drops the longest (possibly empty) suffix of elements@@ -1043,21 +1035,12 @@ {-# INLINE [1] break #-}  -- See bytestring #70-#if MIN_VERSION_base(4,9,0) {-# RULES "ByteString specialise break (x ==)" forall x.     break (x `eqWord8`) = breakByte x "ByteString specialise break (== x)" forall x.     break (`eqWord8` x) = breakByte x   #-}-#else-{-# RULES-"ByteString specialise break (x ==)" forall x.-    break (x ==) = breakByte x-"ByteString specialise break (== x)" forall x.-    break (== x) = breakByte x-  #-}-#endif  -- INTERNAL: @@ -1111,21 +1094,12 @@ {-# INLINE spanByte #-}  -- See bytestring #70-#if MIN_VERSION_base(4,9,0) {-# RULES "ByteString specialise span (x ==)" forall x.     span (x `eqWord8`) = spanByte x "ByteString specialise span (== x)" forall x.     span (`eqWord8` x) = spanByte x   #-}-#else-{-# RULES-"ByteString specialise span (x ==)" forall x.-    span (x ==) = spanByte x-"ByteString specialise span (== x)" forall x.-    span (== x) = spanByte x-  #-}-#endif  -- | Returns the longest (possibly empty) suffix of elements -- satisfying the predicate and the remainder of the string.@@ -1204,8 +1178,7 @@                              w (fromIntegral (l-n))             in if q == nullPtr                 then [BS (plusForeignPtr x n) (l-n)]-                else let i = accursedUnutterablePerformIO $ withForeignPtr x $ \p ->-                               return (q `minusPtr` p)+                else let i = q `minusPtr` unsafeForeignPtrToPtr x                       in BS (plusForeignPtr x n) (i-n) : loop (i+1)  {-# INLINE split #-}@@ -1266,7 +1239,7 @@ -- Indexing ByteStrings  -- | /O(1)/ 'ByteString' index (subscript) operator, starting from 0.-index :: ByteString -> Int -> Word8+index :: HasCallStack => ByteString -> Int -> Word8 index ps n     | n < 0          = moduleError "index" ("negative index: " ++ show n)     | n >= length ps = moduleError "index" ("index too large: " ++ show n@@ -1346,7 +1319,7 @@ -- returns the index of the first element in the ByteString -- satisfying the predicate. findIndex :: (Word8 -> Bool) -> ByteString -> Maybe Int-findIndex k (BS x l) = accursedUnutterablePerformIO $ withForeignPtr x g+findIndex k (BS x l) = accursedUnutterablePerformIO $ unsafeWithForeignPtr x g   where     g !ptr = go 0       where@@ -1363,7 +1336,7 @@ -- -- @since 0.10.12.0 findIndexEnd :: (Word8 -> Bool) -> ByteString -> Maybe Int-findIndexEnd k (BS x l) = accursedUnutterablePerformIO $ withForeignPtr x g+findIndexEnd k (BS x l) = accursedUnutterablePerformIO $ unsafeWithForeignPtr x g   where     g !ptr = go (l-1)       where@@ -1387,21 +1360,12 @@ {-# INLINE [1] findIndices #-}  -#if MIN_VERSION_base(4,9,0) {-# RULES "ByteString specialise findIndex (x ==)" forall x. findIndex (x`eqWord8`) = elemIndex x "ByteString specialise findIndex (== x)" forall x. findIndex (`eqWord8`x) = elemIndex x "ByteString specialise findIndices (x ==)" forall x. findIndices (x`eqWord8`) = elemIndices x "ByteString specialise findIndices (== x)" forall x. findIndices (`eqWord8`x) = elemIndices x   #-}-#else-{-# RULES-"ByteString specialise findIndex (x ==)" forall x. findIndex (x==) = elemIndex x-"ByteString specialise findIndex (== x)" forall x. findIndex (==x) = elemIndex x-"ByteString specialise findIndices (x ==)" forall x. findIndices (x==) = elemIndices x-"ByteString specialise findIndices (== x)" forall x. findIndices (==x) = elemIndices x-  #-}-#endif  -- --------------------------------------------------------------------- -- Searching ByteStrings@@ -1420,21 +1384,24 @@ -- returns a ByteString containing those characters that satisfy the -- predicate. filter :: (Word8 -> Bool) -> ByteString -> ByteString-filter k ps@(BS x l)-    | null ps   = ps-    | otherwise = unsafePerformIO $ createAndTrim l $ \p -> withForeignPtr x $ \f -> do-        t <- go' f p-        return $! t `minusPtr` p -- actual length-  where-    go' pf pt = go pf pt-      where-        end = pf `plusPtr` l-        go !f !t | f == end  = return t-                 | otherwise = do-                     w <- peek f-                     if k w-                       then poke t w >> go (f `plusPtr` 1) (t `plusPtr` 1)-                       else             go (f `plusPtr` 1) t+filter k = \ps@(BS x l) ->+        -- see fold inlining.+  if null ps+    then ps+    else+      unsafePerformIO $ createAndTrim l $ \pOut -> unsafeWithForeignPtr x $ \pIn -> do+        let+          go' pf pt = go pf pt+            where+              end = pf `plusPtr` l+              go !f !t | f == end  = return t+                       | otherwise = do+                           w <- peek f+                           if k w+                             then poke t w >> go (f `plusPtr` 1) (t `plusPtr` 1)+                             else             go (f `plusPtr` 1) t+        t <- go' pIn pOut+        return $! t `minusPtr` pOut -- actual length {-# INLINE filter #-}  {-@@ -1481,7 +1448,7 @@ partition :: (Word8 -> Bool) -> ByteString -> (ByteString, ByteString) partition f s = unsafeDupablePerformIO $     do fp' <- mallocByteString len-       withForeignPtr fp' $ \p ->+       unsafeWithForeignPtr fp' $ \p ->            do let end = p `plusPtr` (len - 1)               mid <- sep 0 p end               rev mid end@@ -1520,7 +1487,7 @@     | l1 == 0   = True     | l2 < l1   = False     | otherwise = accursedUnutterablePerformIO $ unsafeWithForeignPtr x1 $ \p1 ->-        withForeignPtr x2 $ \p2 -> do+        unsafeWithForeignPtr x2 $ \p2 -> do             i <- memcmp p1 p2 (fromIntegral l1)             return $! i == 0 @@ -1548,7 +1515,7 @@     | l1 == 0   = True     | l2 < l1   = False     | otherwise = accursedUnutterablePerformIO $ unsafeWithForeignPtr x1 $ \p1 ->-        withForeignPtr x2 $ \p2 -> do+        unsafeWithForeignPtr x2 $ \p2 -> do             i <- memcmp p1 (p2 `plusPtr` (l2 - l1)) (fromIntegral l1)             return $! i == 0 @@ -1564,6 +1531,17 @@ isInfixOf :: ByteString -> ByteString -> Bool isInfixOf p s = null p || not (null $ snd $ breakSubstring p s) +-- | /O(n)/ Check whether a 'ByteString' represents valid UTF-8.+--+-- @since 0.11.2.0+isValidUtf8 :: ByteString -> Bool+isValidUtf8 (BS ptr len) = accursedUnutterablePerformIO $ unsafeWithForeignPtr ptr $ \p -> do +  i <- cIsValidUtf8 p (fromIntegral len)+  pure $ i /= 0++foreign import ccall unsafe "bytestring_is_valid_utf8" cIsValidUtf8+  :: Ptr Word8 -> CSize -> IO CInt+ -- | Break a string on a substring, returning a pair of the part of the -- string prior to the match, and the rest of the string. --@@ -1672,8 +1650,8 @@ -- @since 0.11.1.0 packZipWith :: (Word8 -> Word8 -> Word8) -> ByteString -> ByteString -> ByteString packZipWith f (BS fp l) (BS fq m) = unsafeDupablePerformIO $-    withForeignPtr fp $ \a ->-    withForeignPtr fq $ \b ->+    unsafeWithForeignPtr fp $ \a ->+    unsafeWithForeignPtr fq $ \b ->     create len $ go a b   where     go p1 p2 = zipWith_ 0@@ -1722,7 +1700,7 @@ sort :: ByteString -> ByteString sort (BS input l)   -- qsort outperforms counting sort for small arrays-  | l <= 20 = unsafeCreate l $ \ptr -> withForeignPtr input $ \inp -> do+  | l <= 20 = unsafeCreate l $ \ptr -> unsafeWithForeignPtr input $ \inp -> do     memcpy ptr inp (fromIntegral l)     c_sort ptr (fromIntegral l)   | otherwise = unsafeCreate l $ \p -> allocaArray 256 $ \arr -> do@@ -1757,11 +1735,12 @@ -- subcomputation finishes. useAsCString :: ByteString -> (CString -> IO a) -> IO a useAsCString (BS fp l) action =- allocaBytes (l+1) $ \buf ->-   withForeignPtr fp $ \p -> do-     memcpy buf p (fromIntegral l)-     pokeByteOff buf l (0::Word8)-     action (castPtr buf)+  allocaBytes (l+1) $ \buf ->+    -- Cannot use unsafeWithForeignPtr, because action can diverge+    withForeignPtr fp $ \p -> do+      memcpy buf p (fromIntegral l)+      pokeByteOff buf l (0::Word8)+      action (castPtr buf)  -- | /O(n) construction/ Use a @ByteString@ with a function requiring a @CStringLen@. -- As for @useAsCString@ this function makes a copy of the original @ByteString@.@@ -2036,15 +2015,15 @@  -- Common up near identical calls to `error' to reduce the number -- constant strings created when compiled:-errorEmptyList :: String -> a+errorEmptyList :: HasCallStack => String -> a errorEmptyList fun = moduleError fun "empty ByteString" {-# NOINLINE errorEmptyList #-} -moduleError :: String -> String -> a+moduleError :: HasCallStack => String -> String -> a moduleError fun msg = error (moduleErrorMsg fun msg) {-# NOINLINE moduleError #-} -moduleErrorIO :: String -> String -> IO a+moduleErrorIO :: HasCallStack => String -> String -> IO a moduleErrorIO fun msg = throwIO . userError $ moduleErrorMsg fun msg {-# NOINLINE moduleErrorIO #-} 
Data/ByteString/Builder.hs view
@@ -1,8 +1,7 @@-{-# LANGUAGE CPP, MagicHash #-}-{-# OPTIONS_GHC -fno-warn-unused-imports -fno-warn-orphans #-}-#if __GLASGOW_HASKELL__ >= 701+{-# LANGUAGE MagicHash #-}+{-# LANGUAGE BangPatterns #-} {-# LANGUAGE Trustworthy #-}-#endif+{-# OPTIONS_GHC -fno-warn-unused-imports -fno-warn-orphans #-} {- | Copyright   : (c) 2010 Jasper Van der Jeugt                    (c) 2010 - 2011 Simon Meier License     : BSD3-style (see LICENSE)@@ -191,6 +190,7 @@       -- about fine-tuning them.     , toLazyByteString     , hPutBuilder+    , writeFile        -- * Creating Builders @@ -252,16 +252,20 @@     , stringUtf8      , module Data.ByteString.Builder.ASCII+    , module Data.ByteString.Builder.RealFloat      ) where +import           Prelude hiding (writeFile)+ import           Data.ByteString.Builder.Internal import qualified Data.ByteString.Builder.Prim  as P import qualified Data.ByteString.Lazy.Internal as L import           Data.ByteString.Builder.ASCII+import           Data.ByteString.Builder.RealFloat  import           Data.String (IsString(..))-import           System.IO (Handle)+import           System.IO (Handle, IOMode(..), withBinaryFile) import           Foreign import           GHC.Base (unpackCString#, unpackCStringUtf8#,                            unpackFoldrCString#, build)@@ -294,6 +298,17 @@ hPutBuilder :: Handle -> Builder -> IO () hPutBuilder h = hPut h . putBuilder +modifyFile :: IOMode -> FilePath -> Builder -> IO ()+modifyFile mode f bld = withBinaryFile f mode (`hPutBuilder` bld)++-- | Write a 'Builder' to a file.+--+-- Similarly to 'hPutBuilder', this function is more efficient than+-- using 'Data.ByteString.Lazy.hPut' . 'toLazyByteString' with a file handle.+--+-- @since 0.11.2.0+writeFile :: FilePath -> Builder -> IO ()+writeFile = modifyFile WriteMode  ------------------------------------------------------------------------------ -- Binary encodings
Data/ByteString/Builder/ASCII.hs view
@@ -1,9 +1,8 @@-{-# LANGUAGE ScopedTypeVariables, CPP, ForeignFunctionInterface,-             MagicHash, UnboxedTuples #-}-{-# OPTIONS_HADDOCK not-home #-}-#if __GLASGOW_HASKELL__ >= 701+{-# LANGUAGE ForeignFunctionInterface #-} {-# LANGUAGE Trustworthy #-}-#endif++{-# OPTIONS_HADDOCK not-home #-}+ -- | Copyright : (c) 2010 - 2011 Simon Meier -- License     : BSD3-style (see LICENSE) --@@ -81,52 +80,16 @@ import           Data.ByteString.Lazy                           as L import           Data.ByteString.Builder.Internal (Builder) import qualified Data.ByteString.Builder.Prim                   as P+import qualified Data.ByteString.Builder.Prim.Internal          as P+import           Data.ByteString.Builder.RealFloat (floatDec, doubleDec)  import           Foreign---#if __GLASGOW_HASKELL__ >= 811--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--# if __GLASGOW_HASKELL__ < 710-import           GHC.Num     (quotRemInteger)-# endif--import GHC.Integer.GMP.Internals-#endif--#if HAS_INTEGER_CONSTR-import qualified Data.ByteString.Builder.Prim.Internal          as P import           Foreign.C.Types-import           GHC.Types   (Int(..))-#endif  ------------------------------------------------------------------------------ -- Decimal Encoding ------------------------------------------------------------------------------ ---- | Encode a 'String' using 'P.char7'.-{-# INLINE string7 #-}-string7 :: String -> Builder-string7 = P.primMapListFixed P.char7----------------------------------------------------------------------------------- Decimal Encoding-------------------------------------------------------------------------------- -- Signed integers ------------------ @@ -191,22 +154,6 @@ wordDec = P.primBounded P.wordDec  --- Floating point numbers------------------------------ TODO: Use Bryan O'Sullivan's double-conversion package to speed it up.---- | /Currently slow./ Decimal encoding of an IEEE 'Float'.-{-# INLINE floatDec #-}-floatDec :: Float -> Builder-floatDec = string7 . show---- | /Currently slow./ Decimal encoding of an IEEE 'Double'.-{-# INLINE doubleDec #-}-doubleDec :: Double -> Builder-doubleDec = string7 . show-- ------------------------------------------------------------------------------ -- Hexadecimal Encoding ------------------------------------------------------------------------------@@ -308,14 +255,11 @@ -- Fast decimal 'Integer' encoding. ------------------------------------------------------------------------------ -#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 -- on larger integers. -# define PAIR(a,b) (# a,b #)- -- | Maximal power of 10 fitting into an 'Int' without using the MSB. --     10 ^ 9  for 32 bit ints  (31 * log 2 / log 10 =  9.33) --     10 ^ 18 for 64 bit ints  (63 * log 2 / log 10 = 18.96)@@ -327,8 +271,8 @@  -- | Decimal encoding of an 'Integer' using the ASCII digits. integerDec :: Integer -> Builder-integerDec (IS i#) = intDec (I# i#) integerDec i+    | i' <- fromInteger i, toInteger i' == i = intDec i'     | i < 0     = P.primFixed P.char8 '-' `mappend` go (-i)     | otherwise =                                   go i   where@@ -349,18 +293,18 @@       where         splith []     = errImpossible "splith"         splith (n:ns) =-            case n `quotRemInteger` pow10 of-                PAIR(q,r) | q > 0     -> q : r : splitb ns-                          | otherwise ->     r : splitb ns+            case n `quotRem` pow10 of+                (q,r) | q > 0     -> q : r : splitb ns+                      | otherwise ->     r : splitb ns          splitb []     = []-        splitb (n:ns) = case n `quotRemInteger` pow10 of-                            PAIR(q,r) -> q : r : splitb ns+        splitb (n:ns) = case n `quotRem` pow10 of+                            (q,r) -> q : r : splitb ns      putH :: [Integer] -> [Int]     putH []     = errImpossible "putH"-    putH (n:ns) = case n `quotRemInteger` maxPow10 of-                    PAIR(x,y)+    putH (n:ns) = case n `quotRem` maxPow10 of+                    (x,y)                         | q > 0     -> q : r : putB ns                         | otherwise ->     r : putB ns                         where q = fromInteger x@@ -368,8 +312,8 @@      putB :: [Integer] -> [Int]     putB []     = []-    putB (n:ns) = case n `quotRemInteger` maxPow10 of-                    PAIR(q,r) -> fromInteger q : fromInteger r : putB ns+    putB (n:ns) = case n `quotRem` maxPow10 of+                    (q,r) -> fromInteger q : fromInteger r : putB ns   foreign import ccall unsafe "static _hs_bytestring_int_dec_padded9"@@ -383,12 +327,3 @@ intDecPadded = P.liftFixedToBounded $ P.caseWordSize_32_64     (P.fixedPrim  9 $ c_int_dec_padded9            . fromIntegral)     (P.fixedPrim 18 $ c_long_long_int_dec_padded18 . fromIntegral)--#else--- compilers other than GHC---- | Decimal encoding of an 'Integer' using the ASCII digits. Implemented--- using via the 'Show' instance of 'Integer's.-integerDec :: Integer -> Builder-integerDec = string7 . show-#endif
Data/ByteString/Builder/Extra.hs view
@@ -1,8 +1,5 @@-{-# LANGUAGE CPP          #-} {-# LANGUAGE BangPatterns #-}-#if __GLASGOW_HASKELL__ >= 701 {-# LANGUAGE Trustworthy #-}-#endif ----------------------------------------------------------------------------- -- | Copyright : (c) 2010      Jasper Van der Jeugt --               (c) 2010-2011 Simon Meier
Data/ByteString/Builder/Internal.hs view
@@ -1,11 +1,5 @@ {-# LANGUAGE ScopedTypeVariables, CPP, BangPatterns, RankNTypes, TupleSections #-}-#if __GLASGOW_HASKELL__ == 700--- This is needed as a workaround for an old bug in GHC 7.0.1 (Trac #4498)-{-# LANGUAGE MonoPatBinds #-}-#endif-#if __GLASGOW_HASKELL__ >= 703 {-# LANGUAGE Unsafe #-}-#endif {-# OPTIONS_HADDOCK not-home #-} -- | Copyright : (c) 2010 - 2011 Simon Meier -- License     : BSD3-style (see LICENSE)@@ -134,13 +128,9 @@  import           Control.Arrow (second) -#if !(MIN_VERSION_base(4,11,0)) && MIN_VERSION_base(4,9,0)+#if !(MIN_VERSION_base(4,11,0)) import           Data.Semigroup (Semigroup((<>))) #endif-#if !(MIN_VERSION_base(4,8,0))-import           Data.Monoid-import           Control.Applicative (Applicative(..),(<$>))-#endif  import qualified Data.ByteString               as S import qualified Data.ByteString.Internal      as S@@ -153,18 +143,9 @@ import           System.IO (hFlush, BufferMode(..), Handle) import           Data.IORef -#if MIN_VERSION_base(4,4,0)-#if MIN_VERSION_base(4,7,0) import           Foreign-#else-import           Foreign hiding (unsafeForeignPtrToPtr)-#endif import           Foreign.ForeignPtr.Unsafe (unsafeForeignPtrToPtr) import           System.IO.Unsafe (unsafeDupablePerformIO)-#else-import           Foreign-import           GHC.IO (unsafeDupablePerformIO)-#endif  ------------------------------------------------------------------------------ -- Buffers@@ -401,21 +382,15 @@ append :: Builder -> Builder -> Builder append (Builder b1) (Builder b2) = Builder $ b1 . b2 -#if MIN_VERSION_base(4,9,0) instance Semigroup Builder where   {-# INLINE (<>) #-}   (<>) = append-#endif  instance Monoid Builder where   {-# INLINE mempty #-}   mempty = empty   {-# INLINE mappend #-}-#if MIN_VERSION_base(4,9,0)   mappend = (<>)-#else-  mappend = append-#endif   {-# INLINE mconcat #-}   mconcat = foldr mappend mempty 
Data/ByteString/Builder/Prim.hs view
@@ -1,13 +1,7 @@-{-# LANGUAGE CPP, BangPatterns, ScopedTypeVariables #-}+{-# LANGUAGE BangPatterns, ScopedTypeVariables #-} {-# LANGUAGE MagicHash, UnboxedTuples, PatternGuards #-} {-# OPTIONS_GHC -fno-warn-unused-imports #-}-#if __GLASGOW_HASKELL__ == 700--- This is needed as a workaround for an old bug in GHC 7.0.1 (Trac #4498)-{-# LANGUAGE MonoPatBinds #-}-#endif-#if __GLASGOW_HASKELL__ >= 701 {-# LANGUAGE Trustworthy #-}-#endif {- | Copyright : (c) 2010-2011 Simon Meier                  (c) 2010      Jasper van der Jeugt License        : BSD3-style (see LICENSE)@@ -472,17 +466,9 @@ import           Data.ByteString.Builder.Prim.Binary import           Data.ByteString.Builder.Prim.ASCII -#if MIN_VERSION_base(4,4,0)-#if MIN_VERSION_base(4,7,0) import           Foreign import           Foreign.C.Types-#else-import           Foreign hiding (unsafeForeignPtrToPtr)-#endif import           Foreign.ForeignPtr.Unsafe (unsafeForeignPtrToPtr)-#else-import           Foreign-#endif import           GHC.Word (Word8 (..)) import           GHC.Exts import           GHC.IO@@ -681,13 +667,10 @@ -- Raw CString encoding ------------------------------------------------------------------------------ -#if !MIN_VERSION_base(4,7,0)--- eqWord# et al. return Bools prior to GHC 7.6-isTrue# :: Bool -> Bool-isTrue# x = x-#endif---- | A null-terminated ASCII encoded 'CString'. Null characters are not representable.+-- | A null-terminated ASCII encoded 'Foreign.C.String.CString'.+-- Null characters are not representable.+--+-- @since 0.11.0.0 cstring :: Addr# -> Builder cstring =     \addr0 -> builder $ step addr0@@ -705,8 +688,10 @@       where         !ch = indexWord8OffAddr# addr 0# --- | A null-terminated UTF-8 encoded 'CString'. Null characters can be encoded as--- @0xc0 0x80@.+-- | A null-terminated UTF-8 encoded 'Foreign.C.String.CString'.+-- Null characters can be encoded as @0xc0 0x80@.+--+-- @since 0.11.0.0 cstringUtf8 :: Addr# -> Builder cstringUtf8 =     \addr0 -> builder $ step addr0
Data/ByteString/Builder/Prim/ASCII.hs view
@@ -1,8 +1,5 @@-{-# LANGUAGE CPP #-} {-# LANGUAGE ScopedTypeVariables, ForeignFunctionInterface #-}-#if __GLASGOW_HASKELL__ >= 701 {-# LANGUAGE Trustworthy #-}-#endif -- | Copyright   : (c) 2010 Jasper Van der Jeugt --                 (c) 2010 - 2011 Simon Meier -- License       : BSD3-style (see LICENSE)
Data/ByteString/Builder/Prim/Binary.hs view
@@ -1,7 +1,5 @@ {-# LANGUAGE CPP #-}-#if __GLASGOW_HASKELL__ >= 701 {-# LANGUAGE Trustworthy #-}-#endif -- | Copyright   : (c) 2010-2011 Simon Meier -- License       : BSD3-style (see LICENSE) --
Data/ByteString/Builder/Prim/Internal.hs view
@@ -1,7 +1,5 @@ {-# LANGUAGE ScopedTypeVariables, CPP #-}-#if __GLASGOW_HASKELL__ >= 703 {-# LANGUAGE Unsafe #-}-#endif {-# OPTIONS_HADDOCK not-home #-} -- | -- Copyright   : 2010-2011 Simon Meier, 2010 Jasper van der Jeugt
Data/ByteString/Builder/Prim/Internal/Base16.hs view
@@ -1,7 +1,5 @@-{-# LANGUAGE CPP #-}-#if __GLASGOW_HASKELL__ >= 701 {-# LANGUAGE Trustworthy #-}-#endif+{-# LANGUAGE MagicHash #-} -- | -- Copyright   : (c) 2011 Simon Meier -- License     : BSD3-style (see LICENSE)@@ -24,57 +22,42 @@   , encode8_as_16h   ) where -import qualified Data.ByteString          as S-import qualified Data.ByteString.Internal as S--#if MIN_VERSION_base(4,4,0)-#if MIN_VERSION_base(4,7,0) import           Foreign-#else-import           Foreign hiding (unsafePerformIO, unsafeForeignPtrToPtr)-#endif-import           Foreign.ForeignPtr.Unsafe (unsafeForeignPtrToPtr)-import           System.IO.Unsafe (unsafePerformIO)-#else-import           Foreign-#endif+import           GHC.Exts (Addr#, Ptr(..))  -- Creating the encoding table ------------------------------ --- TODO: Use table from C implementation.- -- | An encoding table for Base16 encoding.-newtype EncodingTable = EncodingTable (ForeignPtr Word8)--tableFromList :: [Word8] -> EncodingTable-tableFromList xs = case S.pack xs of S.BS fp _ -> EncodingTable fp--unsafeIndex :: EncodingTable -> Int -> IO Word8-unsafeIndex (EncodingTable table) = peekElemOff (unsafeForeignPtrToPtr table)--base16EncodingTable :: EncodingTable -> IO EncodingTable-base16EncodingTable alphabet = do-    xs <- sequence $ concat $ [ [ix j, ix k] | j <- [0..15], k <- [0..15] ]-    return $ tableFromList xs-  where-    ix = unsafeIndex alphabet--{-# NOINLINE lowerAlphabet #-}-lowerAlphabet :: EncodingTable-lowerAlphabet =-    tableFromList $ map (fromIntegral . fromEnum) $ ['0'..'9'] ++ ['a'..'f']+data EncodingTable = EncodingTable Addr#  -- | The encoding table for hexadecimal values with lower-case characters; -- e.g., deadbeef. {-# NOINLINE lowerTable #-} lowerTable :: EncodingTable-lowerTable = unsafePerformIO $ base16EncodingTable lowerAlphabet+lowerTable = EncodingTable+    "000102030405060708090a0b0c0d0e0f\+    \101112131415161718191a1b1c1d1e1f\+    \202122232425262728292a2b2c2d2e2f\+    \303132333435363738393a3b3c3d3e3f\+    \404142434445464748494a4b4c4d4e4f\+    \505152535455565758595a5b5c5d5e5f\+    \606162636465666768696a6b6c6d6e6f\+    \707172737475767778797a7b7c7d7e7f\+    \808182838485868788898a8b8c8d8e8f\+    \909192939495969798999a9b9c9d9e9f\+    \a0a1a2a3a4a5a6a7a8a9aaabacadaeaf\+    \b0b1b2b3b4b5b6b7b8b9babbbcbdbebf\+    \c0c1c2c3c4c5c6c7c8c9cacbcccdcecf\+    \d0d1d2d3d4d5d6d7d8d9dadbdcdddedf\+    \e0e1e2e3e4e5e6e7e8e9eaebecedeeef\+    \f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"# + -- | Encode an octet as 16bit word comprising both encoded nibbles ordered -- according to the host endianness. Writing these 16bit to memory will write -- the nibbles in the correct order (i.e. big-endian). {-# INLINE encode8_as_16h #-} encode8_as_16h :: EncodingTable -> Word8 -> IO Word16 encode8_as_16h (EncodingTable table) =-    peekElemOff (castPtr $ unsafeForeignPtrToPtr table) . fromIntegral+    peekElemOff (Ptr table) . fromIntegral
Data/ByteString/Builder/Prim/Internal/Floating.hs view
@@ -1,8 +1,5 @@-{-# LANGUAGE CPP #-} {-# LANGUAGE ScopedTypeVariables #-}-#if __GLASGOW_HASKELL__ >= 701 {-# LANGUAGE Trustworthy #-}-#endif -- | -- Copyright   : (c) 2010 Simon Meier --
+ Data/ByteString/Builder/RealFloat.hs view
@@ -0,0 +1,287 @@+-- |+-- Module      : Data.ByteString.Builder.RealFloat+-- Copyright   : (c) Lawrence Wu 2021+-- License     : BSD-style+-- Maintainer  : lawrencejwu@gmail.com+--+-- Floating point formatting for @Bytestring.Builder@+--+-- This module primarily exposes `floatDec` and `doubleDec` which do the+-- equivalent of converting through @'Data.ByteString.Builder.string7' . 'show'@.+--+-- It also exposes `formatFloat` and `formatDouble` with a similar API as+-- `GHC.Float.formatRealFloat`.+--+-- NB: The float-to-string conversions exposed by this module match `show`'s+-- output (specifically with respect to default rounding and length). In+-- particular, there are boundary cases where the closest and \'shortest\'+-- string representations are not used.  Mentions of \'shortest\' in the docs+-- below are with this caveat.+--+-- For example, for fidelity, we match `show` on the output below.+--+-- >>> show (1.0e23 :: Float)+-- "1.0e23"+-- >>> show (1.0e23 :: Double)+-- "9.999999999999999e22"+-- >>> floatDec 1.0e23+-- "1.0e23"+-- >>> doubleDec 1.0e23+-- "9.999999999999999e22"+--+-- Simplifying, we can build a shorter, lossless representation by just using+-- @"1.0e23"@ since the floating point values that are 1 ULP away are+--+-- >>> showHex (castDoubleToWord64 1.0e23) []+-- "44b52d02c7e14af6"+-- >>> castWord64ToDouble 0x44b52d02c7e14af5+-- 9.999999999999997e22+-- >>> castWord64ToDouble 0x44b52d02c7e14af6+-- 9.999999999999999e22+-- >>> castWord64ToDouble 0x44b52d02c7e14af7+-- 1.0000000000000001e23+--+-- In particular, we could use the exact boundary if it is the shortest+-- representation and the original floating number is even. To experiment with+-- the shorter rounding, refer to+-- `Data.ByteString.Builder.RealFloat.Internal.acceptBounds`. This will give us+--+-- >>> floatDec 1.0e23+-- "1.0e23"+-- >>> doubleDec 1.0e23+-- "1.0e23"+--+-- For more details, please refer to the+-- <https://dl.acm.org/doi/10.1145/3192366.3192369 Ryu paper>.+--+-- @since 0.11.2.0++module Data.ByteString.Builder.RealFloat+  ( floatDec+  , doubleDec++  -- * Custom formatting+  , formatFloat+  , formatDouble+  , FloatFormat+  , standard+  , standardDefaultPrecision+  , scientific+  , generic+  ) where++import Data.ByteString.Builder.Internal (Builder)+import qualified Data.ByteString.Builder.RealFloat.Internal as R+import qualified Data.ByteString.Builder.RealFloat.F2S as RF+import qualified Data.ByteString.Builder.RealFloat.D2S as RD+import qualified Data.ByteString.Builder.Prim as BP+import GHC.Float (roundTo)+import GHC.Word (Word64)+import GHC.Show (intToDigit)++-- | Returns a rendered Float. Matches `show` in displaying in standard or+-- scientific notation+--+-- @+-- floatDec = 'formatFloat' 'generic'+-- @+{-# INLINABLE floatDec #-}+floatDec :: Float -> Builder+floatDec = formatFloat generic++-- | Returns a rendered Double. Matches `show` in displaying in standard or+-- scientific notation+--+-- @+-- doubleDec = 'formatDouble' 'generic'+-- @+{-# INLINABLE doubleDec #-}+doubleDec :: Double -> Builder+doubleDec = formatDouble generic++-- | Format type for use with `formatFloat` and `formatDouble`.+--+-- @since 0.11.2.0+data FloatFormat = MkFloatFormat FormatMode (Maybe Int)++-- | Standard notation with `n` decimal places+--+-- @since 0.11.2.0+standard :: Int -> FloatFormat+standard n = MkFloatFormat FStandard (Just n)++-- | Standard notation with the \'default precision\' (decimal places matching `show`)+--+-- @since 0.11.2.0+standardDefaultPrecision :: FloatFormat+standardDefaultPrecision = MkFloatFormat FStandard Nothing++-- | Scientific notation with \'default precision\' (decimal places matching `show`)+--+-- @since 0.11.2.0+scientific :: FloatFormat+scientific = MkFloatFormat FScientific Nothing++-- | Standard or scientific notation depending on the exponent. Matches `show`+--+-- @since 0.11.2.0+generic :: FloatFormat+generic = MkFloatFormat FGeneric Nothing++-- | ByteString float-to-string format+data FormatMode+  = FScientific     -- ^ scientific notation+  | FStandard       -- ^ standard notation with `Maybe Int` digits after the decimal+  | FGeneric        -- ^ dispatches to scientific or standard notation based on the exponent+  deriving Show++-- TODO: support precision argument for FGeneric and FScientific+-- | Returns a rendered Float. Returns the \'shortest\' representation in+-- scientific notation and takes an optional precision argument in standard+-- notation. Also see `floatDec`.+--+-- With standard notation, the precision argument is used to truncate (or+-- extend with 0s) the \'shortest\' rendered Float. The \'default precision\' does+-- no such modifications and will return as many decimal places as the+-- representation demands.+--+-- e.g+--+-- >>> formatFloat (standard 1) 1.2345e-2+-- "0.0"+-- >>> formatFloat (standard 10) 1.2345e-2+-- "0.0123450000"+-- >>> formatFloat standardDefaultPrecision 1.2345e-2+-- "0.01234"+-- >>> formatFloat scientific 12.345+-- "1.2345e1"+-- >>> formatFloat generic 12.345+-- "12.345"+--+-- @since 0.11.2.0+{-# INLINABLE formatFloat #-}+formatFloat :: FloatFormat -> Float -> Builder+formatFloat (MkFloatFormat fmt prec) = \f ->+  let (RF.FloatingDecimal m e) = RF.f2Intermediate f+      e' = R.int32ToInt e + R.decimalLength9 m in+  case fmt of+    FGeneric ->+      case specialStr f of+        Just b -> b+        Nothing ->+          if e' >= 0 && e' <= 7+             then sign f `mappend` showStandard (R.word32ToWord64 m) e' prec+             else BP.primBounded (R.toCharsScientific (f < 0) m e) ()+    FScientific -> RF.f2s f+    FStandard ->+      case specialStr f of+        Just b -> b+        Nothing -> sign f `mappend` showStandard (R.word32ToWord64 m) e' prec++-- TODO: support precision argument for FGeneric and FScientific+-- | Returns a rendered Double. Returns the \'shortest\' representation in+-- scientific notation and takes an optional precision argument in standard+-- notation. Also see `doubleDec`.+--+-- With standard notation, the precision argument is used to truncate (or+-- extend with 0s) the \'shortest\' rendered Float. The \'default precision\'+-- does no such modifications and will return as many decimal places as the+-- representation demands.+--+-- e.g+--+-- >>> formatDouble (standard 1) 1.2345e-2+-- "0.0"+-- >>> formatDouble (standard 10) 1.2345e-2+-- "0.0123450000"+-- >>> formatDouble standardDefaultPrecision 1.2345e-2+-- "0.01234"+-- >>> formatDouble scientific 12.345+-- "1.2345e1"+-- >>> formatDouble generic 12.345+-- "12.345"+--+-- @since 0.11.2.0+{-# INLINABLE formatDouble #-}+formatDouble :: FloatFormat -> Double -> Builder+formatDouble (MkFloatFormat fmt prec) = \f ->+  let (RD.FloatingDecimal m e) = RD.d2Intermediate f+      e' = R.int32ToInt e + R.decimalLength17 m in+  case fmt of+    FGeneric ->+      case specialStr f of+        Just b -> b+        Nothing ->+          if e' >= 0 && e' <= 7+             then sign f `mappend` showStandard m e' prec+             else BP.primBounded (R.toCharsScientific (f < 0) m e) ()+    FScientific -> RD.d2s f+    FStandard ->+      case specialStr f of+        Just b -> b+        Nothing -> sign f `mappend` showStandard m e' prec++-- | Char7 encode a 'Char'.+{-# INLINE char7 #-}+char7 :: Char -> Builder+char7 = BP.primFixed BP.char7++-- | Char7 encode a 'String'.+{-# INLINE string7 #-}+string7 :: String -> Builder+string7 = BP.primMapListFixed BP.char7++-- | Encodes a `-` if input is negative+sign :: RealFloat a => a -> Builder+sign f = if f < 0 then char7 '-' else mempty++-- | Special rendering for Nan, Infinity, and 0. See+-- RealFloat.Internal.NonNumbersAndZero+specialStr :: RealFloat a => a -> Maybe Builder+specialStr f+  | isNaN f          = Just $ string7 "NaN"+  | isInfinite f     = Just $ sign f `mappend` string7 "Infinity"+  | isNegativeZero f = Just $ string7 "-0.0"+  | f == 0           = Just $ string7 "0.0"+  | otherwise        = Nothing++-- | Returns a list of decimal digits in a Word64+digits :: Word64 -> [Int]+digits w = go [] w+  where go ds 0 = ds+        go ds c = let (q, r) = R.dquotRem10 c+                   in go ((R.word64ToInt r) : ds) q++-- | Show a floating point value in standard notation. Based on GHC.Float.showFloat+showStandard :: Word64 -> Int -> Maybe Int -> Builder+showStandard m e prec =+  case prec of+    Nothing+      | e <= 0 -> char7 '0'+               `mappend` char7 '.'+               `mappend` string7 (replicate (-e) '0')+               `mappend` mconcat (digitsToBuilder ds)+      | otherwise ->+          let f 0 s     rs = mk0 (reverse s) `mappend` char7 '.' `mappend` mk0 rs+              f n s     [] = f (n-1) (char7 '0':s) []+              f n s (r:rs) = f (n-1) (r:s) rs+           in f e [] (digitsToBuilder ds)+    Just p+      | e >= 0 ->+          let (ei, is') = roundTo 10 (p' + e) ds+              (ls, rs) = splitAt (e + ei) (digitsToBuilder is')+           in mk0 ls `mappend` mkDot rs+      | otherwise ->+          let (ei, is') = roundTo 10 p' (replicate (-e) 0 ++ ds)+              -- ds' should always be non-empty but use redundant pattern+              -- matching to silence warning+              ds' = if ei > 0 then is' else 0:is'+              (ls, rs) = splitAt 1 $ digitsToBuilder ds'+           in mk0 ls `mappend` mkDot rs+          where p' = max p 0+  where+    mk0 ls = case ls of [] -> char7 '0'; _ -> mconcat ls+    mkDot rs = if null rs then mempty else char7 '.' `mappend` mconcat rs+    ds = digits m+    digitsToBuilder = fmap (char7 . intToDigit)+
+ Data/ByteString/Builder/RealFloat/D2S.hs view
@@ -0,0 +1,851 @@+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE BangPatterns, MagicHash #-}+-- |+-- Module      : Data.ByteString.Builder.RealFloat.D2S+-- Copyright   : (c) Lawrence Wu 2021+-- License     : BSD-style+-- Maintainer  : lawrencejwu@gmail.com+--+-- Implementation of double-to-string conversion++module Data.ByteString.Builder.RealFloat.D2S+    ( FloatingDecimal(..)+    , d2s+    , d2Intermediate+    ) where++import Control.Arrow (first)+import Data.Bits ((.|.), (.&.), unsafeShiftL, unsafeShiftR)+import Data.ByteString.Builder.Internal (Builder)+import Data.ByteString.Builder.Prim (primBounded)+import Data.ByteString.Builder.RealFloat.Internal+import Data.Maybe (fromMaybe)+import GHC.Int (Int32(..))+import GHC.Word (Word64(..))++-- See Data.ByteString.Builder.RealFloat.TableGenerator for a high-level+-- explanation of the ryu algorithm++-- | Table of 2^k / 5^q + 1+-- Byte-swapped version of+-- > fmap (finv double_pow5_inv_bitcount) [0..double_max_inv_split]+double_pow5_inv_split :: Addr+double_pow5_inv_split = Addr+  "\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20\+  \\x9a\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x19\+  \\x15\xae\x47\xe1\x7a\x14\xae\x47\xe1\x7a\x14\xae\x47\xe1\x7a\x14\+  \\xde\x24\x06\x81\x95\x43\x8b\x6c\xe7\xfb\xa9\xf1\xd2\x4d\x62\x10\+  \\x96\xd4\x09\x68\x22\x6c\x78\x7a\xa5\x2c\x43\x1c\xeb\xe2\x36\x1a\+  \\xab\x43\x6e\x86\x1b\xf0\xf9\x61\x84\xf0\x68\xe3\x88\xb5\xf8\x14\+  \\x22\x36\x58\x38\x49\xf3\xc7\xb4\x36\x8d\xed\xb5\xa0\xf7\xc6\x10\+  \\x6a\x23\x8d\xc0\x0e\x52\xa6\x87\x57\x48\xaf\xbc\x9a\xf2\xd7\x1a\+  \\x88\x4f\xd7\x66\xa5\x41\xb8\x9f\xdf\x39\x8c\x30\xe2\x8e\x79\x15\+  \\x07\xa6\x12\x1f\x51\x01\x2d\xe6\xb2\x94\xd6\x26\xe8\x0b\x2e\x11\+  \\xa4\x09\x51\xcb\x81\x68\xae\xd6\xb7\xba\xbd\xd7\xd9\xdf\x7c\x1b\+  \\xea\x3a\xa7\xa2\x34\xed\xf1\xde\x5f\x95\x64\x79\xe1\x7f\xfd\x15\+  \\xbb\xc8\x85\xe8\xf6\xf0\x27\x7f\x19\x11\xea\x2d\x81\x99\x97\x11\+  \\xf8\x0d\xd6\x40\xbe\xb4\x0c\x65\xc2\x81\x76\x49\x68\xc2\x25\x1c\+  \\x93\x71\xde\x33\x98\x90\x70\xea\x01\x9b\x2b\xa1\x86\x9b\x84\x16\+  \\x43\xc1\x7e\x29\xe0\xa6\xf3\x21\x9b\x15\x56\xe7\x9e\xaf\x03\x12\+  \\x37\x35\x31\x0f\xcd\xd7\x85\x69\x2b\xbc\x89\xd8\x97\xb2\xd2\x1c\+  \\xf9\x90\x5a\x3f\xd7\xdf\x37\x21\x89\x96\xd4\x46\x46\xf5\x0e\x17\+  \\xfa\x73\x48\xcc\x45\xe6\x5f\xe7\xa0\xab\x43\xd2\xd1\x5d\x72\x12\+  \\x5d\x86\x0d\x7a\x3c\x3d\x66\xa5\x34\xac\xd2\xb6\x4f\xc9\x83\x1d\+  \\xb1\x9e\xd7\x94\x63\x97\x1e\x51\x5d\x23\x42\x92\x0c\xa1\x9c\x17\+  \\xc1\x4b\x79\xdd\x82\xdf\x7e\xda\x7d\x4f\x9b\x0e\x0a\xb4\xe3\x12\+  \\x68\xac\x5b\x62\xd1\x98\x64\x2a\x96\xe5\x5e\x17\x10\x20\x39\x1e\+  \\x53\xf0\xe2\x81\xa7\xe0\xb6\xee\x44\x51\xb2\x12\x40\xb3\x2d\x18\+  \\xa9\x26\x4f\xce\x52\x4d\x92\x58\x6a\xa7\x8e\xa8\x99\xc2\x57\x13\+  \\x41\xa4\x7e\xb0\xb7\x7b\x50\x27\xaa\xd8\x7d\xda\xf5\xd0\xf2\x1e\+  \\x34\x50\x65\xc0\x5f\xc9\xa6\x52\xbb\x13\xcb\xae\xc4\x40\xc2\x18\+  \\x90\xa6\xea\x99\x4c\xd4\xeb\x0e\xc9\x0f\x3c\xf2\x36\x9a\xce\x13\+  \\x80\x0a\x11\xc3\xad\x53\x79\xb1\x41\x19\x60\x50\xbe\xf6\xb0\x1f\+  \\x67\x08\x74\x02\x8b\xdc\x2d\xc1\x67\x47\xb3\xa6\xfe\x5e\x5a\x19\+  \\x52\xa0\x29\x35\x6f\xb0\x24\x34\x86\x9f\xc2\xeb\xfe\x4b\x48\x14\+  \\xdb\x19\xee\x90\xf2\x59\x1d\x90\x9e\x7f\x68\x89\x65\xd6\x39\x10\+  \\x5f\x29\xb0\xb4\x1d\xc3\xfb\x4c\x97\x32\xa7\xa8\xd5\x23\xf6\x19\+  \\xb2\xba\x59\x5d\xb1\x35\x96\x3d\xac\x5b\x1f\xba\x77\xe9\xc4\x14\+  \\x28\x62\xe1\x7d\x27\x5e\xab\x97\x56\x49\x4c\xfb\x92\x87\x9d\x10\+  \\x0d\x9d\x68\xc9\xd8\xc9\xab\xf2\xf0\x0e\x7a\xf8\xb7\xa5\x95\x1a\+  \\x3e\x17\xba\x3a\x7a\xa1\xbc\x5b\x5a\x72\x2e\x2d\x93\x84\x44\x15\+  \\xcb\x45\xfb\x2e\xc8\x1a\xca\xaf\xae\x8e\x8b\x8a\x42\x9d\x03\x11\+  \\x45\x09\x92\xb1\xa6\xf7\xdc\xb2\x4a\xe4\x78\xaa\x9d\xfb\x38\x1b\+  \\x04\xa1\x41\xc1\xeb\x92\x7d\xf5\x6e\x83\x2d\x55\xb1\x2f\xc7\x15\+  \\x03\xb4\x67\x67\x89\x75\x64\xc4\x58\x9c\x57\x77\x27\x26\x6c\x11\+  \\xd2\xec\xa5\xd8\xdb\x88\x6d\x6d\xf4\xc6\x25\xf2\x0b\x3d\xe0\x1b\+  \\xdb\x23\xeb\x46\x16\x07\xbe\x8a\xc3\x38\x1e\x28\xa3\xfd\x4c\x16\+  \\x49\xb6\x55\xd2\x11\x6c\xfe\x6e\x9c\x60\x4b\x53\x4f\x31\xd7\x11\+  \\x0e\x8a\xef\xb6\x4f\x13\x97\xb1\x60\x67\x45\x85\x18\x82\x8b\x1c\+  \\xa5\xa1\xbf\xf8\x72\x0f\xac\x27\x1a\xb9\x6a\x37\xad\x01\xd6\x16\+  \\x1e\x4e\x99\x60\xc2\x72\x56\xb9\xe1\x60\x55\x2c\x24\xce\x44\x12\+  \\x95\x16\xc2\xcd\x03\x1e\x57\xf5\x35\xce\xbb\x13\x6d\xe3\x3a\x1d\+  \\xab\xab\x01\x0b\x03\x18\xac\x2a\x2b\xd8\x2f\x76\x8a\x4f\x62\x17\+  \\x56\x89\x34\x6f\x02\xe0\xbc\xbb\x55\x13\xf3\xc4\x6e\x0c\xb5\x12\+  \\x89\xa8\xed\xb1\xd0\xcc\xc7\x92\xef\x1e\xb8\xd4\x4a\x7a\xee\x1d\+  \\x07\xba\x57\x8e\x40\x0a\xd3\xdb\xf2\x4b\x93\x10\x6f\xfb\xf1\x17\+  \\x06\xc8\xdf\x71\x00\xd5\xa8\x7c\xf5\x6f\x0f\xda\x58\xfc\x27\x13\+  \\xd6\x0c\x66\xe9\x33\xbb\xa7\xfa\xbb\x4c\xb2\x29\x8e\x60\xa6\x1e\+  \\x11\xd7\x84\x87\x29\xfc\x52\x95\xc9\xa3\x8e\x54\x0b\x1a\x85\x18\+  \\x0e\xac\xd0\xd2\xba\xc9\xa8\xaa\x07\x83\xd8\x76\x6f\xae\x9d\x13\+  \\xe3\xac\x1a\x1e\x5e\xdc\xda\xdd\xa5\xd1\xc0\x57\xb2\xb0\x62\x1f\+  \\x4f\x8a\x48\x4b\x4b\xb0\x48\x7e\x51\x41\x9a\xac\x8e\xc0\x1b\x19\+  \\xd9\xa1\xd3\xd5\xd5\x59\x6d\xcb\xda\xcd\xe1\x56\xa5\x33\x16\x14\+  \\x7b\x81\xdc\x77\x11\x7b\x57\x3c\xe2\xd7\xe7\xab\xea\xc2\x11\x10\+  \\x2a\xcf\x60\x59\x82\x5e\xf2\xc6\x36\x26\xa6\xac\xaa\x04\xb6\x19\+  \\xbb\xa5\x80\x47\x68\x18\xf5\x6b\xc5\x51\xeb\x56\x55\x9d\x91\x14\+  \\x96\x84\x00\x06\xed\x79\x2a\x23\xd1\xa7\x22\xdf\xdd\x7d\x74\x10\+  \\x56\x07\x34\xa3\xe1\x8f\xdd\xd1\x81\x0c\xd1\x31\x96\xfc\x53\x1a\+  \\x45\x6c\xf6\xe8\x1a\x73\xe4\xa7\x34\x3d\xa7\xf4\x44\xfd\x0f\x15\+  \\x9e\x56\xf8\x53\xe2\x28\x1d\x53\x5d\x97\x52\x5d\x6a\x97\xd9\x10\+  \\x62\x57\x8d\xb9\x03\xdb\x61\xeb\x2e\xf2\x50\x95\x10\xbf\xf5\x1a\+  \\xe8\x45\xa4\xc7\xcf\x48\x4e\xbc\x58\x5b\xda\xdd\xa6\x65\x91\x15\+  \\x20\x6b\x83\x6c\xd9\xd3\x71\x63\xad\xe2\xe1\x17\x1f\x1e\x41\x11\+  \\xcd\x11\x9f\xad\x28\x86\x1c\x9f\x48\x04\x03\xf3\x64\x63\x9b\x1b\+  \\x0b\xdb\x18\xbe\x53\x6b\xb0\xe5\x06\x9d\x35\x8f\x1d\xe9\x15\x16\+  \\xa2\x15\x47\xcb\x0f\x89\xf3\xea\x6b\x4a\x91\x72\xe4\x20\xab\x11\+  \\x37\xbc\x71\x78\x4c\xdb\xb8\x44\x46\xaa\x1b\x84\x6d\x01\x45\x1c\+  \\x5f\x63\xc1\xc6\xd6\x15\xc7\x03\x05\x55\x49\x03\xbe\x9a\x9d\x16\+  \\x19\xe9\xcd\x6b\x45\xde\x38\x36\x37\x77\x07\x69\xfe\xae\x17\x12\+  \\xc1\x41\x16\x46\xa2\x63\xc1\x56\x58\x58\x72\x0e\x97\xb1\xf2\x1c\+  \\xce\x67\xab\xd1\x81\x1c\x01\xdf\x79\x13\xf5\x71\x12\x8e\x28\x17\+  \\xa5\xec\x55\x41\xce\x16\x34\x7f\x61\xdc\x90\xc1\x0e\xd8\x86\x12\+  \\x6e\x47\x56\x35\x7d\x24\x20\x65\x02\xc7\xe7\x68\xe4\x8c\xa4\x1d\+  \\x25\x39\x78\xf7\x30\x1d\x80\xea\x01\x6c\xb9\x20\x1d\xd7\xb6\x17\+  \\x84\xfa\x2c\xf9\xf3\xb0\x99\xbb\x34\x23\x61\x4d\x17\xac\xf8\x12\+  \\x39\xf7\x47\x28\x53\x4e\x5c\x5f\x54\x38\x68\x15\xf2\xac\x5a\x1e\+  \\x2e\x2c\xd3\xb9\x75\x0b\x7d\x7f\x43\x60\x53\x44\x5b\x8a\x48\x18\+  \\x58\x23\xdc\xc7\xf7\xd5\x30\x99\xcf\x19\xa9\x36\x7c\x3b\x6d\x13\+  \\x26\xd2\xf9\x72\x8c\x89\xb4\x8e\xb2\x8f\x0e\xf1\xf9\x2b\x15\x1f\+  \\xb8\x41\x2e\x8f\xa3\x07\x2a\x72\x28\xa6\x0b\xf4\xc7\xbc\xdd\x18\+  \\xfa\x9a\xbe\xa5\x4f\x39\xbb\xc1\x86\x1e\xd6\x5c\x06\x97\xe4\x13\+  \\xf6\xf7\x30\x09\x19\xc2\x5e\x9c\xd7\x30\xf0\xfa\xd6\x24\xd4\x1f\+  \\xf8\x5f\x5a\x07\x14\x68\xe5\x49\x79\x8d\x26\x2f\xdf\x83\x76\x19\+  \\x60\xe6\xe1\x05\x10\x20\x51\x6e\xc7\x0a\x52\xbf\xe5\xcf\x5e\x14\+  \\x1a\x85\x81\xd1\x0c\x80\xda\xf1\x05\x6f\x0e\x99\x84\xd9\x4b\x10\+  \\xf5\xd4\x68\x82\x14\x00\xc4\x4f\xd6\xe4\xe3\xf4\xa0\xf5\x12\x1a\+  \\x2b\x77\xed\x01\xaa\x99\x69\xd9\x11\xb7\x1c\xf7\xb3\xf7\xdb\x14\+  \\xbc\xc5\x8a\x01\x88\x14\xee\xad\x74\x92\xb0\xc5\x5c\xf9\xaf\x10\+  \\x2c\x09\xde\x68\xa6\xed\x7c\x49\x54\xea\x80\x6f\x94\x28\xb3\x1a\+  \\x24\xd4\xe4\x53\xb8\x57\xca\x3a\x10\x55\x9a\xbf\x76\x20\x5c\x15\+  \\x83\x76\x1d\x43\x60\x79\x3b\x62\x73\xaa\xae\xff\x5e\x80\x16\x11\+  \\x9e\xbd\xc8\xd1\x66\xf5\x2b\x9d\xb8\x10\xb1\x32\xcb\x33\x57\x1b\+  \\x7f\x64\x6d\x41\x52\xc4\xbc\x7d\x60\x0d\xf4\x8e\xa2\x5c\xdf\x15\+  \\xcc\xb6\x8a\x67\xdb\x69\xfd\xca\xe6\x3d\xc3\xd8\x4e\x7d\x7f\x11\+  \\xdf\x8a\x77\x72\xc5\x0f\x2f\xab\xd7\x2f\x05\x8e\xe4\x2e\xff\x1b\+  \\x80\xd5\x92\x5b\x04\x73\xf2\x88\xac\x8c\x6a\x3e\x1d\xbf\x65\x16\+  \\x66\x44\x42\x49\xd0\x28\xf5\xd3\x56\x3d\x55\x98\x4a\xff\xea\x11\+  \\xa3\xa0\x03\x42\x4d\x41\x88\xb9\x57\x95\xbb\xf3\x10\x32\xab\x1c\+  \\xe9\xe6\x02\x68\xd7\xcd\x39\x61\x79\x77\xfc\xc2\x40\x5b\xef\x16\+  \\x54\x52\x02\x20\x79\x71\x61\xe7\x2d\xf9\xc9\x68\xcd\x15\x59\x12\+  \\x86\x50\x9d\x99\x8e\xb5\x68\xa5\x7c\x5b\x76\x74\x15\x56\x5b\x1d\+  \\xd2\xa6\x4a\xe1\x3e\x91\x20\x51\xfd\x15\xc5\xf6\xdd\x44\x7c\x17\+  \\x0e\x1f\xa2\x1a\xff\x40\x4d\xa7\xca\x44\x37\x92\xb1\xd0\xc9\x12\+  \\x4a\xcb\x69\xf7\x64\xce\xae\x0b\x11\x6e\x58\x50\x4f\xb4\x0f\x1e\+  \\x3b\x3c\xee\xc5\x50\xd8\x8b\x3c\xa7\xf1\x79\x73\x3f\x90\x0c\x18\+  \\xc9\xc9\xf1\x37\xda\x79\x09\xca\x85\xf4\xc7\xc2\x32\x40\x3d\x13\+  \\xdb\x42\xe9\xbf\xf6\xc2\xa8\xa9\x6f\xba\x0c\x9e\xb7\x66\xc8\x1e\+  \\xe3\x9b\xba\xcc\x2b\xcf\x53\x21\x26\x95\x70\x7e\x2c\x52\xa0\x18\+  \\x82\x49\x95\x70\x89\x72\xa9\x1a\xb8\xdd\x26\x65\xf0\x74\xb3\x13\+  \\x9d\x75\x88\x1a\x0f\x84\x75\xf7\x8c\x2f\x3e\x08\xe7\x87\x85\x1f\+  \\x17\x5e\xa0\x7b\x72\x36\x91\x5f\x0a\x26\x98\x06\xec\x9f\x37\x19\+  \\xdf\xe4\x19\x96\x5b\xf8\x40\x19\xd5\x84\x46\x05\xf0\x7f\x2c\x14\+  \\x4c\xea\x47\xab\xaf\xc6\x00\xe1\x10\x37\x05\xd1\x8c\x99\x23\x10\+  \\x47\xdd\x3f\x45\x4c\xa4\x67\xce\xe7\x24\xd5\xb4\x47\x8f\xd2\x19\+  \\x06\xb1\xcc\x9d\xd6\xe9\x52\xd8\x1f\xb7\xdd\xc3\x9f\x72\xa8\x14\+  \\x38\x27\x0a\x4b\x45\xee\xdb\x79\x19\x2c\x7e\x69\x19\xc2\x86\x10\+  \\x59\xd8\xa9\x11\xa2\xe3\x5f\x29\x8f\x46\x30\x0f\x8f\x36\x71\x1a\+  \\x7a\x13\xbb\xa7\x81\x1c\xb3\xba\xa5\x6b\xf3\xd8\xd8\x5e\x27\x15\+  \\x2f\xa9\x95\xec\x9a\xe3\x28\x62\x51\x89\x8f\xad\xe0\x4b\xec\x10\+  \\x17\x75\xef\xe0\xf7\x38\x0e\x9d\xe8\x0e\x4c\xaf\x9a\xac\x13\x1b\+  \\x79\x2a\x59\x1a\x93\x2d\xd8\xb0\x53\x72\xd6\x25\xe2\x56\xa9\x15\+  \\x2e\x55\x47\x48\x0f\xbe\x79\x8d\xdc\xc1\xde\xb7\x81\x45\x54\x11\+  \\x7c\xbb\x0b\xda\x7e\x96\x8f\x15\x94\x9c\x97\x8c\xcf\x08\xba\x1b\+  \\x97\x2f\xd6\x14\xff\x11\xa6\x77\x76\xb0\xdf\xd6\x72\x6d\x2e\x16\+  \\x79\x8c\xde\x43\xff\xa7\x51\xf9\x91\xf3\xb2\x78\xf5\xbd\xbe\x11\+  \\x8e\xad\xfd\xd2\xfe\x3f\x1c\xc2\x1c\xec\xb7\x5a\x22\x63\x64\x1c\+  \\xd8\x8a\x64\x42\x32\x33\xb0\x01\x17\xf0\x5f\x15\xb5\xb5\xb6\x16\+  \\x46\xa2\x83\x9b\x8e\xc2\x59\x01\xac\x59\xe6\xdd\x90\xc4\x2b\x12\+  \\xa3\x03\x39\x5f\x17\x04\xf6\xce\xac\xc2\xa3\xfc\x1a\xd4\x12\x1d\+  \\x83\x9c\x2d\x4c\xac\x69\x5e\x72\xbd\x9b\x1c\xca\x48\x43\x42\x17\+  \\x9c\xe3\x8a\xd6\x89\x54\x18\xf5\xfd\xe2\x16\x08\x07\x69\x9b\x12\+  \\xc6\x05\xab\xbd\x0f\x54\x8d\xee\x2f\x6b\xf1\x0c\xd8\x74\xc5\x1d\+  \\x05\x6b\x22\xfe\x72\x76\xd7\xbe\x8c\x22\xc1\x70\x46\x2a\xd1\x17\+  \\x04\xbc\x4e\xcb\x28\xc5\x12\xff\xd6\x4e\x67\x8d\x6b\xbb\x0d\x13\+  \\xa0\xf9\x7d\x78\x74\x3b\x51\xcb\x24\x7e\xd8\x7b\x12\x5f\x7c\x1e\+  \\x4d\x61\xfe\xf9\x29\xc9\x0d\x09\xb7\x31\xad\xfc\x41\x7f\x63\x18\+  \\x0a\x81\xcb\x94\x21\xd4\xd7\xa0\xc5\x27\x24\xca\x34\xcc\x82\x13\+  \\x77\xce\x78\x54\xcf\xb9\xbf\x67\x6f\x0c\x6d\x43\x21\xad\x37\x1f\+  \\xf9\x71\x2d\xdd\xa5\x94\xcc\x1f\x59\x70\x8a\xcf\x4d\x57\xf9\x18\+  \\xc7\xf4\xbd\x7d\x51\xdd\xd6\x7f\x7a\xf3\xa1\x3f\x3e\xac\xfa\x13\+  \\x0b\xee\x2f\xc9\xe8\x2e\xbe\xff\xc3\xb8\x9c\x32\xfd\x79\xf7\x1f\+  \\xd6\x24\xf3\xa0\x20\xbf\x31\x66\x36\xfa\x16\xc2\xfd\xc7\x92\x19\+  \\x78\x1d\x5c\x1a\x1a\xcc\x27\xb8\x5e\xfb\xab\x01\xcb\x6c\x75\x14\+  \\x60\xe4\x7c\x7b\xae\x09\x53\x93\x18\xc9\xbc\x67\xa2\xf0\x5d\x10\+  \\x99\xa0\x94\xc5\xb0\x42\xeb\x1e\xf4\x74\x94\x3f\x6a\xe7\x2f\x1a\+  \\xe1\xe6\x76\x04\x27\x02\x89\xe5\x5c\x2a\xdd\x32\x88\x1f\xf3\x14\+  \\xe7\xeb\x2b\x9d\x85\xce\xa0\xb7\xb0\xee\xb0\x28\xa0\x7f\xc2\x10\+  \\xd8\xdf\xdf\x61\x6f\x4a\x01\x59\xb4\x4a\x4e\x74\x33\xcc\xd0\x1a\+  \\xad\x4c\xe6\xe7\x25\xd5\xcd\xe0\x29\xa2\x3e\x90\x8f\xd6\x73\x15\+  \\xf1\xd6\x51\x86\x51\x77\x71\x4d\xee\xb4\xcb\xd9\x72\x78\x29\x11\+  \\xe8\x57\xe9\xd6\xe8\xbe\xe8\x7b\xb0\x54\xac\x8f\x84\x8d\x75\x1b\+  \\x20\x13\x21\xdf\x53\x32\xba\xfc\x59\xdd\x89\x0c\x6a\xa4\xf7\x15\+  \\x80\x42\xe7\x18\x43\x28\xc8\x63\xae\x4a\x6e\x70\xee\xe9\x92\x11\+  \\x66\x6a\xd8\x27\x38\x0d\x0d\x06\x17\x11\x4a\x1a\x17\x43\x1e\x1c\+  \\xeb\x21\xad\xec\x2c\xa4\x3d\x6b\x12\x74\x6e\x7b\x12\x9c\x7e\x16\+  \\x56\x4e\x57\xbd\xf0\x1c\xfe\x88\xdb\x5c\x58\xfc\x41\xe3\xfe\x11\+  \\x23\x4a\x25\x62\xb4\x94\x96\x41\x5f\x61\x8d\x60\x36\x05\xcb\x1c\+  \\xe9\xd4\x1d\xe8\x29\xaa\xab\x67\x7f\xe7\x3d\x4d\xf8\xd0\x08\x17\+  \\x87\xdd\x17\x20\xbb\x21\x56\xb9\x32\xb9\x64\xd7\xf9\x73\x6d\x12\+  \\xa5\x95\x8c\x66\x2b\x69\x23\xc2\xea\xc1\x3a\xf2\xc2\xec\x7b\x1d\+  \\x1d\xde\xd6\x1e\x89\xba\x82\xce\xbb\x34\x62\x5b\x02\x57\x96\x17\+  \\x18\x18\xdf\x4b\x07\x62\x35\xa5\xfc\xf6\xb4\xe2\x01\xac\xde\x12\+  \\x59\xf3\x64\x79\xd8\x9c\x88\x3b\x94\xf1\x87\x37\x36\x13\x31\x1e\+  \\xe1\xf5\x83\xc7\x46\x4a\x6d\xfc\xdc\x5a\x06\xc6\x91\x42\x27\x18\+  \\x1a\x2b\x03\x06\x9f\x6e\x57\x30\x17\xaf\x9e\xd1\xa7\x9b\x52\x13\+  \\x90\xde\xd1\x3c\xcb\x7d\x25\x1a\x25\x18\x31\x1c\xa6\x92\xea\x1e\+  \\x40\xe5\xa7\x30\x3c\xfe\x1d\x48\xb7\x79\x5a\xe3\x84\xa8\xbb\x18\+  \\x00\x51\x86\xc0\xc9\x31\x4b\xd3\xc5\xc7\xae\x82\x9d\x53\xc9\x13\+  \\xcd\xb4\xa3\xcd\x42\xe9\x11\x52\x09\xa6\x17\xd1\xc8\x85\xa8\x1f\+  \\xa4\x90\x1c\x3e\x02\x21\xdb\x74\x07\xb8\xdf\x40\x3a\x9e\x53\x19\+  \\x50\x0d\x4a\xcb\x01\xb4\x15\xf7\x05\x60\x19\x67\xfb\xe4\x42\x14\+  \\xa7\x0a\x08\x09\x9b\x29\xde\xf8\x37\xb3\x7a\x52\xfc\x83\x35\x10\+  \\xd7\xdd\x0c\xa8\x91\x42\x30\x8e\x59\xb8\x2a\xb7\x93\x39\xef\x19\+  \\x13\x4b\x0a\x20\x0e\x02\x8d\x3e\xe1\xf9\xee\xf8\x42\x61\xbf\x14\+  \\x0f\x3c\x08\x80\x3e\x9b\x3d\x65\xe7\xc7\x58\xfa\x9b\x1a\x99\x10\+  \\xe4\x2c\x0d\x00\x64\xf8\xc8\x6e\xa5\x0c\x8e\x90\xf9\x90\x8e\x1a\+  \\xea\x23\xa4\x99\xe9\xf9\xd3\x8b\xb7\xa3\x71\x40\x61\xda\x3e\x15\+  \\xbb\x1c\x50\xe1\xba\x94\xa9\x3c\xf9\x82\xf4\x99\x1a\x15\xff\x10\+  \\x2b\x61\xb3\x9b\xc4\xba\x75\xc7\x8e\xd1\x20\xc3\x5d\xbb\x31\x1b\+  \\x89\x1a\x29\x16\x6a\x95\xc4\xd2\x0b\x0e\xe7\x68\xb1\x62\xc1\x15\+  \\xa1\x7b\xba\x11\x88\x77\xd0\xdb\x6f\x3e\x1f\x87\x27\x82\x67\x11\+  \\x9b\x92\x5d\x1c\x40\xbf\x80\x2c\xe6\x63\x98\x3e\x3f\xd0\xd8\x1b\+  \\x49\x75\xe4\x49\x33\xcc\x33\xbd\x51\xb6\x46\x65\xff\x0c\x47\x16\+  \\xd4\x5d\x50\x6e\x8f\xd6\x8f\xca\xa7\x5e\x05\x51\xcc\x70\xd2\x11\+  \\x53\xc9\xb3\xe3\x4b\x57\x19\x44\xd9\xfd\x6e\x4e\xad\xe7\x83\x1c\+  \\xa9\x3a\xf6\x82\x09\x79\x47\x03\xe1\x97\x25\xa5\x8a\xec\xcf\x16\+  \\xba\xfb\xc4\x68\xd4\x60\x6c\xcf\x80\x79\x84\xea\x6e\xf0\x3f\x12\+  \\x2a\xf9\x07\x0e\x87\x34\x7a\xe5\x9a\xf5\xd3\x10\x4b\x1a\x33\x1d\+  \\x22\x94\x39\x0b\x6c\x90\x2e\x51\xe2\x2a\x43\xda\x08\x15\x5c\x17\+  \\xb5\xa9\xc7\xd5\xbc\xa6\x8b\xda\x81\x55\xcf\xe1\xd3\x10\xb0\x12\+  \\x87\x0f\xd9\x22\x2e\x71\xdf\x90\x9c\x55\xe5\x02\x53\x81\xe6\x1d\+  \\x6c\x0c\x14\x4f\x8b\x5a\x4c\xda\x16\xde\x1d\xcf\xa8\x9a\xeb\x17\+  \\x8a\xa3\xa9\xa5\xa2\x7b\xa3\xae\x78\x7e\xb1\xa5\x20\xe2\x22\x13\+  \\xa9\x05\xa9\xa2\x6a\x5f\xd2\x7d\x27\x97\xb5\xa2\x9a\x36\x9e\x1e\+  \\x54\xd1\x20\x82\x88\x7f\xdb\x97\x1f\xac\xf7\x4e\x15\x92\x7e\x18\+  \\x77\xa7\x80\xce\x06\x66\x7c\x79\x4c\x23\xc6\xd8\xdd\x74\x98\x13\+  \\xf1\x0b\x01\xe4\x0a\x70\x2d\x8f\xad\x6b\xa3\x27\x96\x54\x5a\x1f\+  \\x5a\xd6\x00\x50\xa2\x59\x24\x0c\xbe\xef\xb5\x1f\x78\x10\x15\x19\+  \\x15\x45\x9a\xd9\x81\x14\x1d\x70\xfe\xf2\xf7\xb2\xf9\xd9\x10\x14\+  \\x77\x6a\x7b\x14\x9b\x43\x17\xc0\xfe\x5b\xc6\x28\x2e\x7b\x0d\x10\+  \\xf2\x43\x92\xed\xc4\x05\xf2\xcc\xca\x2c\x0a\x0e\x7d\x2b\xaf\x19\+  \\xc2\x9c\x0e\xbe\xd0\x37\x5b\x0a\x6f\xbd\xa1\x71\xca\x22\x8c\x14\+  \\xce\xe3\x3e\xcb\x73\xf9\x48\x08\x8c\x97\xb4\x27\xd5\x1b\x70\x10\+  \\xb0\x9f\x64\x78\xec\x5b\x0e\xda\xac\x25\x54\x0c\x55\xf9\x4c\x1a\+  \\xc0\x7f\x50\x60\xf0\xaf\x3e\x7b\xbd\xb7\xa9\xd6\x10\x61\x0a\x15\+  \\x33\x66\x40\x80\xf3\xbf\xcb\x95\x97\x2c\xee\xde\x73\x1a\xd5\x10\+  \\x52\x70\xcd\x66\x52\x66\xac\xef\x58\x47\xb0\x64\xb9\x90\xee\x1a\+  \\xdb\x59\xa4\xb8\x0e\x85\x23\x26\x47\x6c\xf3\xb6\xfa\xa6\x8b\x15\+  \\x49\xae\xb6\x93\xd8\xd0\x82\x1e\x6c\x23\x29\x5f\x95\x85\x3c\x11\+  \\x75\xb0\x8a\x1f\xf4\x1a\x9e\xfd\xac\x38\xa8\xfe\xee\x08\x94\x1b\+  \\xf7\x59\xd5\xb2\x29\xaf\xb1\x97\xbd\x93\x86\x98\x25\x07\x10\x16\+  \\x2c\x7b\x77\xf5\xba\x25\x8e\xac\x97\xdc\x9e\x13\x1e\x6c\xa6\x11\+  \\x13\xc5\x58\x22\x2b\x09\x7d\x7a\xbf\x2d\xfe\xb8\xc9\x79\x3d\x1c\+  \\x76\x6a\xad\x4e\xef\xa0\xfd\x61\xcc\x57\xcb\x60\xa1\x94\x97\x16\+  \\xc5\xee\xbd\x0b\x59\x1a\xfe\xe7\x09\x13\x09\xe7\x4d\xdd\x12\x12\+  \\x3a\xb1\xfc\x45\x5b\x5d\x63\xa6\xdc\x84\x0e\xd8\xaf\xfb\xea\x1c\+  \\xc8\x8d\x30\x6b\xaf\x4a\x1c\x85\xb0\xd0\x3e\x13\xf3\x62\x22\x17\+  \\xd4\xd7\x26\xbc\xf2\x6e\xe3\xd0\x26\xda\xcb\x75\xc2\xe8\x81\x12\+  \\x86\x8c\xa4\xc6\xea\x17\x9f\xb4\xd7\x29\x46\x89\x9d\xa7\x9c\x1d\+  \\x6b\x70\x50\x05\xef\xdf\x18\x2a\x46\xee\x04\xa1\x17\x86\xb0\x17\+  \\x89\xf3\xd9\x9d\x25\xb3\xe0\x54\x6b\x8b\x9d\x4d\x79\x9e\xf3\x12\+  \\x74\x52\xf6\x62\x6f\xeb\xcd\x87\x78\x45\x2f\x7c\x28\x97\x52\x1e\+  \\x5d\xa8\x5e\x82\xbf\x22\x0b\xd3\xc6\x6a\xbf\xc9\x86\x12\x42\x18\+  \\xe4\xb9\x4b\x68\xcc\x1b\x3c\x0f\x9f\x88\xff\x3a\xd2\x0e\x68\x13\+  \\x6d\x29\x79\x40\x7a\x2c\x60\x18\x98\xda\x98\x91\x83\xe4\x0c\x1f\+  \\x24\x21\x94\x33\xc8\x56\xb3\x46\x13\xe2\x13\x0e\x36\x1d\xd7\x18\+  \\xb6\x4d\x43\x29\xa0\x78\x8f\x38\xdc\xb4\xdc\xa4\x91\x4a\xdf\x13\+  \\x8a\xaf\x6b\xa8\x66\x27\x7f\x5a\x60\x21\x61\xa1\x82\xaa\xcb\x1f\+  \\xa2\xbf\xef\xb9\xeb\x85\x32\x15\x4d\xb4\x4d\xb4\x9b\xbb\x6f\x19\+  \\x4e\x99\x8c\x61\x89\xd1\x8e\xaa\x3d\x90\xa4\xf6\xe2\x62\x59\x14\+  \\x0c\xe1\xd6\x1a\xa1\xa7\xd8\xee\xca\xd9\xb6\x2b\x4f\x82\x47\x10\+  \\x45\x9b\x24\x5e\x9b\x72\x27\x7e\x11\xf6\x8a\xdf\xb1\x03\x0c\x1a\+  \\x04\x49\x1d\x18\x49\xf5\x85\xfe\x0d\xf8\x3b\x19\x5b\x69\xd6\x14\+  \\xd0\xa0\x4a\x13\xd4\x5d\x9e\xcb\xa4\xf9\x2f\x14\x7c\x87\xab\x10\+  \\x4d\x01\x11\x52\x53\xc9\x63\xdf\x3a\x5c\xe6\xb9\xf9\x0b\xac\x1a\+  \\x71\x67\xda\x74\x0f\xa1\x1c\x19\x2f\xb0\x1e\xfb\xfa\x6f\x56\x15\+  \\xc1\x52\x48\x2a\xd9\x80\xb0\xad\x25\xc0\x4b\x2f\x2f\xf3\x11\x11\+  \\x34\x51\x0d\xaa\x8e\x34\xe7\x15\x09\xcd\x12\xb2\x7e\xeb\x4f\x1b\+  \\xc4\x0d\x71\xee\x3e\x5d\x1f\xab\x6d\x0a\x0f\x28\x32\x89\xd9\x15\+  \\x9d\xa4\x8d\x8b\x65\x17\x19\xbc\x57\x08\x0c\x20\x28\xd4\x7a\x11\+  \\x94\x3a\x7c\x12\x3c\xf2\xf4\x2c\x59\x0d\xe0\xcc\xd9\xb9\xf7\x1b\+  \\x43\x95\x96\xdb\xfc\xf4\xc3\xf0\xe0\x3d\xb3\x70\xe1\xc7\x5f\x16\+  \\x03\x11\x12\x16\x97\x5d\x36\x5a\x1a\xcb\xf5\x26\x81\x39\xe6\x11\+  \\x04\xe8\x1c\xf0\x24\xfc\x56\x90\x90\xde\x22\x0b\x35\x8f\xa3\x1c\+  \\xd0\xec\xe3\x8c\x1d\x30\xdf\xd9\xa6\x4b\x82\xa2\x5d\x3f\xe9\x16\+  \\xda\x23\x83\x3d\xb1\x59\x7f\xe1\xeb\xa2\xce\x4e\xb1\x32\x54\x12\+  \\x5c\x39\x38\x2f\xb5\xc2\xcb\x68\x79\xd1\x7d\xe4\x4e\x84\x53\x1d\+  \\xe3\x2d\x60\xbf\x5d\x35\xd6\x53\x94\xa7\x64\x50\x72\x03\x76\x17\+  \\x1c\x8b\xe6\x65\xb1\x2a\x78\xa9\x76\xec\xb6\xa6\x8e\xcf\xc4\x12\+  \\xfa\x44\xd7\x6f\xb5\xaa\x26\x0f\xf1\x13\x8b\xd7\x7d\xb2\x07\x1e\+  \\x62\x6a\xdf\xbf\x2a\x22\x52\x3f\x27\x43\x6f\xac\x64\x28\x06\x18\+  \\x4e\x88\x7f\x99\x88\x4e\xdb\x65\x1f\x9c\xf2\x89\x50\x20\x38\x13\+  \\x4a\x0d\xcc\x28\x74\x4a\xc5\x6f\x65\x93\xea\x0f\xb4\x33\xc0\x1e\+  \\x3b\xa4\x09\x87\xf6\xa1\x6a\x59\x84\x0f\x22\x73\xf6\xc2\x99\x18\+  \\x96\xb6\x07\x6c\xf8\xe7\xee\xad\x36\xd9\xb4\xf5\x91\x35\xae\x13\+  \\x56\x57\x0c\xe0\xf3\x3f\x7e\x49\x24\xf5\xba\x22\x83\x22\x7d\x1f\+  \\x45\xac\xd6\x4c\xf6\xff\x64\xd4\xe9\x90\x95\xe8\x68\xe8\x30\x19\+  \\xd1\x89\x78\x3d\xf8\xff\x83\x43\xee\x73\x44\xed\x53\x20\x27\x14\+  \\x74\xa1\x93\x97\xc6\xcc\x9c\xcf\xf1\x8f\x03\xf1\x0f\x4d\x1f\x10\+  \\x52\x02\xb9\x25\xa4\x47\x61\x7f\x1c\xb3\x05\xe8\x7f\xae\xcb\x19\+  \\x0f\x35\xc7\xb7\xe9\xd2\x4d\xcc\x16\x5c\xd1\xec\xff\xf1\xa2\x14\+  \\xd9\x90\xd2\x5f\x21\x0f\x0b\x3d\x12\xb0\xda\x23\x33\x5b\x82\x10\+  \\xc1\xe7\x50\x99\x68\x4b\xab\x61\x50\xb3\x2a\x06\x85\x2b\x6a\x1a\+  \\x67\xb9\x40\x14\xba\xa2\x22\x4e\x40\x5c\x55\x6b\x6a\xbc\x21\x15\+  \\x53\x94\x00\xdd\x94\xe8\x4e\x0b\xcd\x49\x44\xbc\xee\xc9\xe7\x10\+  \\x51\xed\x00\xc8\x87\xda\x17\x12\x48\xa9\xd3\xc6\x4a\x76\x0c\x1b\+  \\xda\xbd\x00\xa0\x6c\x48\x46\xdb\x6c\x87\xdc\x6b\xd5\x91\xa3\x15\+  \\xaf\x64\xcd\x4c\xbd\x06\x05\x49\x8a\x9f\xe3\xef\xdd\xa7\x4f\x11\+  \\xb1\x3a\xe2\x7a\xc8\x0a\x08\xa8\x43\xff\x38\xe6\x2f\xa6\xb2\x1b\+  \\xf4\x2e\xe8\xfb\x39\xa2\x39\x53\x69\xff\x93\x1e\xf3\x84\x28\x16\+  \\x5d\xf2\xec\x2f\xfb\xb4\xc7\x75\x87\xff\x0f\xb2\xf5\x03\xba\x11\+  \\x2e\xea\x47\xe6\x91\x21\xd9\x22\x3f\xff\x7f\xb6\x22\xd3\x5c\x1c\+  \\xf2\x54\x06\x85\x41\x81\x7a\xb5\x65\xff\xff\x91\xe8\xa8\xb0\x16\+  \\xf5\x43\x38\x37\x01\x01\x62\xc4\xb7\x32\x33\xdb\x86\xed\x26\x12\+  \\xee\x9f\xf3\xf1\x01\x68\x36\x3a\x59\x84\xeb\x91\xa4\x15\x0b\x1d\+  \\x8b\x19\xf6\x27\x9b\xb9\x5e\xfb\xe0\x69\xbc\x74\x50\x11\x3c\x17\+  \\xd6\x7a\x5e\x86\xe2\xfa\x7e\x2f\xe7\x87\x63\x5d\x40\x74\x96\x12\+  \\x56\x91\xfd\xd6\xd0\xf7\x97\xe5\x71\xd9\x38\x62\xcd\x86\xbd\x1d\+  \\xab\xda\xca\x78\x0d\x93\x79\x84\xc1\x7a\x2d\xe8\x3d\xd2\xca\x17\+  \\x56\x15\x6f\x2d\x71\x42\x61\xd0\x9a\xc8\x8a\x86\x31\xa8\x08\x13\+  \\x22\x22\x18\xaf\x4e\x6a\x68\x4d\x91\xda\xaa\x3d\x4f\x40\x74\x1e\+  \\xe8\xb4\x79\xf2\x3e\x88\x53\xa4\xda\xae\x88\x64\x3f\x00\x5d\x18\+  \\x87\x5d\x61\x28\xff\x6c\xdc\xe9\xae\x58\x6d\x50\xcc\x99\x7d\x13\+  \\xa4\x95\x68\x0d\x65\xae\x60\xa9\xe4\x8d\x48\x1a\x7a\x5c\x2f\x1f\+  \\x83\x44\xed\x3d\xb7\xbe\xb3\xba\x83\x71\xa0\xae\x61\xb0\xf2\x18\+  \\x36\x9d\x8a\x31\x2c\x32\xf6\x2e\x36\xc1\xe6\xbe\xe7\x59\xf5\x13"#++-- | Table of 5^(-e2-q) / 2^k + 1+-- Byte-swapped version of+-- > fmap (fnorm double_pow5_bitcount) [0..double_max_split]+double_pow5_split :: Addr+double_pow5_split = Addr+  "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10\+  \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x14\+  \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x19\+  \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x40\x1f\+  \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x88\x13\+  \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x6a\x18\+  \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x84\x1e\+  \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd0\x12\x13\+  \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x84\xd7\x17\+  \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x65\xcd\x1d\+  \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20\x5f\xa0\x12\+  \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe8\x76\x48\x17\+  \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa2\x94\x1a\x1d\+  \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x40\xe5\x9c\x30\x12\+  \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x90\x1e\xc4\xbc\x16\+  \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x34\x26\xf5\x6b\x1c\+  \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\xe0\x37\x79\xc3\x11\+  \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa0\xd8\x85\x57\x34\x16\+  \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc8\x4e\x67\x6d\xc1\x1b\+  \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x3d\x91\x60\xe4\x58\x11\+  \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x40\x8c\xb5\x78\x1d\xaf\x15\+  \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x50\xef\xe2\xd6\xe4\x1a\x1b\+  \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x92\xd5\x4d\x06\xcf\xf0\x10\+  \\x00\x00\x00\x00\x00\x00\x00\x00\x80\xf6\x4a\xe1\xc7\x02\x2d\x15\+  \\x00\x00\x00\x00\x00\x00\x00\x00\x20\xb4\x9d\xd9\x79\x43\x78\x1a\+  \\x00\x00\x00\x00\x00\x00\x00\x00\x94\x90\x02\x28\x2c\x2a\x8b\x10\+  \\x00\x00\x00\x00\x00\x00\x00\x00\xb9\x34\x03\x32\xb7\xf4\xad\x14\+  \\x00\x00\x00\x00\x00\x00\x00\x40\xe7\x01\x84\xfe\xe4\x71\xd9\x19\+  \\x00\x00\x00\x00\x00\x00\x00\x88\x30\x81\x12\x1f\x2f\xe7\x27\x10\+  \\x00\x00\x00\x00\x00\x00\x00\xaa\x7c\x21\xd7\xe6\xfa\xe0\x31\x14\+  \\x00\x00\x00\x00\x00\x00\x80\xd4\xdb\xe9\x8c\xa0\x39\x59\x3e\x19\+  \\x00\x00\x00\x00\x00\x00\xa0\xc9\x52\x24\xb0\x08\x88\xef\x8d\x1f\+  \\x00\x00\x00\x00\x00\x00\x04\xbe\xb3\x16\x6e\x05\xb5\xb5\xb8\x13\+  \\x00\x00\x00\x00\x00\x00\x85\xad\x60\x9c\xc9\x46\x22\xe3\xa6\x18\+  \\x00\x00\x00\x00\x00\x40\xe6\xd8\x78\x03\x7c\xd8\xea\x9b\xd0\x1e\+  \\x00\x00\x00\x00\x00\xe8\x8f\x87\x2b\x82\x4d\xc7\x72\x61\x42\x13\+  \\x00\x00\x00\x00\x00\xe2\x73\x69\xb6\xe2\x20\x79\xcf\xf9\x12\x18\+  \\x00\x00\x00\x00\x80\xda\xd0\x03\x64\x1b\x69\x57\x43\xb8\x17\x1e\+  \\x00\x00\x00\x00\x90\x88\x62\x82\x1e\xb1\xa1\x16\x2a\xd3\xce\x12\+  \\x00\x00\x00\x00\xb4\x2a\xfb\x22\x66\x1d\x4a\x9c\xf4\x87\x82\x17\+  \\x00\x00\x00\x00\x61\xf5\xb9\xab\xbf\xa4\x5c\xc3\xf1\x29\x63\x1d\+  \\x00\x00\x00\xa0\x5c\x39\x54\xcb\xf7\xe6\x19\x1a\x37\xfa\x5d\x12\+  \\x00\x00\x00\xc8\xb3\x47\x29\xbe\xb5\x60\xa0\xe0\xc4\x78\xf5\x16\+  \\x00\x00\x00\xba\xa0\x99\xb3\x2d\xe3\x78\xc8\x18\xf6\xd6\xb2\x1c\+  \\x00\x00\x40\x74\x04\x40\x90\xfc\x8d\x4b\x7d\xcf\x59\xc6\xef\x11\+  \\x00\x00\x50\x91\x05\x50\xb4\x7b\x71\x9e\x5c\x43\xf0\xb7\x6b\x16\+  \\x00\x00\xa4\xf5\x06\x64\xa1\xda\x0d\xc6\x33\x54\xec\xa5\x06\x1c\+  \\x00\x80\x86\x59\x84\xde\xa4\xa8\xc8\x5b\xa0\xb4\xb3\x27\x84\x11\+  \\x00\x20\xe8\x6f\x25\x16\xce\xd2\xba\x72\xc8\xa1\xa0\x31\xe5\x15\+  \\x00\x28\xe2\xcb\xae\x9b\x81\x87\x69\x8f\x3a\xca\x08\x7e\x5e\x1b\+  \\x00\x59\x6d\x3f\x4d\x01\xb1\xf4\xa1\x99\x64\x7e\xc5\x0e\x1b\x11\+  \\x40\xaf\x48\x8f\xa0\x41\xdd\x71\x0a\xc0\xfd\xdd\x76\xd2\x61\x15\+  \\x10\xdb\x1a\xb3\x08\x92\x54\x0e\x0d\x30\x7d\x95\x14\x47\xba\x1a\+  \\xea\xc8\xf0\x6f\x45\xdb\xf4\x28\x08\x3e\x6e\xdd\x6c\x6c\xb4\x10\+  \\x24\xfb\xec\xcb\x16\x12\x32\x33\x8a\xcd\xc9\x14\x88\x87\xe1\x14\+  \\xed\x39\xe8\x7e\x9c\x96\xfe\xbf\xec\x40\xfc\x19\x6a\xe9\x19\x1a\+  \\x34\x24\x51\xcf\x21\x1e\xff\xf7\x93\xa8\x3d\x50\xe2\x31\x50\x10\+  \\x41\x6d\x25\x43\xaa\xe5\xfe\xf5\xb8\x12\x4d\xe4\x5a\x3e\x64\x14\+  \\x92\xc8\xee\xd3\x14\x9f\x7e\x33\x67\x57\x60\x9d\xf1\x4d\x7d\x19\+  \\xb6\x7a\xea\x08\xda\x46\x5e\x00\x41\x6d\xb8\x04\x6e\xa1\xdc\x1f\+  \\xb2\x8c\x92\x45\x48\xec\x3a\xa0\x48\x44\xf3\xc2\xe4\xe4\xe9\x13\+  \\xde\x2f\xf7\x56\x5a\xa7\x49\xc8\x5a\x15\xb0\xf3\x1d\x5e\xe4\x18\+  \\xd6\xfb\xb4\xec\x30\x11\x5c\x7a\xb1\x1a\x9c\x70\xa5\x75\x1d\x1f\+  \\x65\x1d\xf1\x93\xbe\x8a\x79\xec\xae\x90\x61\x66\x87\x69\x72\x13\+  \\xbf\x64\xed\x38\x6e\xed\x97\xa7\xda\xf4\xf9\x3f\xe9\x03\x4f\x18\+  \\xef\xbd\x28\xc7\xc9\xe8\x7d\x51\x11\x72\xf8\x8f\xe3\xc4\x62\x1e\+  \\xb5\x76\x79\x1c\x7e\xb1\xee\xd2\x4a\x47\xfb\x39\x0e\xbb\xfd\x12\+  \\x62\xd4\x97\xa3\xdd\x5d\xaa\x87\x1d\x19\x7a\xc8\xd1\x29\xbd\x17\+  \\x7b\xc9\x7d\x0c\x55\xf5\x94\xe9\x64\x9f\x98\x3a\x46\x74\xac\x1d\+  \\xed\x9d\xce\x27\x55\x19\xfd\x11\x9f\x63\x9f\xe4\xab\xc8\x8b\x12\+  \\x68\x45\xc2\x71\xaa\x5f\x7c\xd6\x86\x3c\xc7\xdd\xd6\xba\x2e\x17\+  \\xc2\xd6\x32\x0e\x95\x77\x1b\x8c\xa8\x0b\x39\x95\x8c\x69\xfa\x1c\+  \\x39\xc6\xdf\x28\xbd\x2a\x91\x57\x49\xa7\x43\xdd\xf7\x81\x1c\x12\+  \\xc8\xb7\x17\x73\x6c\x75\x75\xad\x1b\x91\x94\xd4\x75\xa2\xa3\x16\+  \\xba\xa5\xdd\x8f\xc7\xd2\xd2\x98\x62\xb5\xb9\x49\x13\x8b\x4c\x1c\+  \\x94\x87\xea\xb9\xbc\xc3\x83\x9f\x5d\x11\x14\x0e\xec\xd6\xaf\x11\+  \\x79\x29\x65\xe8\xab\xb4\x64\x07\xb5\x15\x99\x11\xa7\xcc\x1b\x16\+  \\xd7\x73\x7e\xe2\xd6\xe1\x3d\x49\x22\x5b\xff\xd5\xd0\xbf\xa2\x1b\+  \\x66\x08\x8f\x4d\x26\xad\xc6\x6d\xf5\x98\xbf\x85\xe2\xb7\x45\x11\+  \\x80\xca\xf2\xe0\x6f\x58\x38\xc9\x32\x7f\x2f\x27\xdb\x25\x97\x15\+  \\x20\x7d\x2f\xd9\x8b\x6e\x86\x7b\xff\x5e\xfb\xf0\x51\xef\xfc\x1a\+  \\x34\xae\xbd\x67\x17\x05\x34\xad\x5f\x1b\x9d\x36\x93\x15\xde\x10\+  \\xc1\x19\xad\x41\x5d\x06\x81\x98\x37\x62\x44\x04\xf8\x9a\x15\x15\+  \\x32\x60\x18\x92\xf4\x47\xa1\x7e\xc5\x7a\x55\x05\xb6\x01\x5b\x1a\+  \\x1f\x3c\x4f\xdb\xf8\xcc\x24\x6f\xbb\x6c\x55\xc3\x11\xe1\x78\x10\+  \\x27\x0b\x23\x12\x37\x00\xee\x4a\xea\xc7\x2a\x34\x56\x19\x97\x14\+  \\xf0\xcd\xab\xd6\x44\x80\xa9\xdd\xe4\x79\x35\xc1\xab\xdf\xbc\x19\+  \\xb6\x60\x2b\x06\x2b\xf0\x89\x0a\x2f\x6c\xc1\x58\xcb\x0b\x16\x10\+  \\xe4\x38\xb6\xc7\x35\x6c\x2c\xcd\x3a\xc7\xf1\x2e\xbe\x8e\x1b\x14\+  \\x1d\xc7\xa3\x39\x43\x87\x77\x80\x09\x39\xae\xba\x6d\x72\x22\x19\+  \\xe4\xb8\x0c\x08\x14\x69\x95\xe0\x4b\xc7\x59\x29\x09\x0f\x6b\x1f\+  \\x8e\xf3\x07\x85\xac\x61\x5d\x6c\x8f\x1c\xd8\xb9\x65\xe9\xa2\x13\+  \\x72\xf0\x49\xa6\x17\xba\x74\x47\xb3\x23\x4e\x28\xbf\xa3\x8b\x18\+  \\x8f\x6c\xdc\x8f\x9d\xe8\x51\x19\xa0\xac\x61\xf2\xae\x8c\xae\x1e\+  \\xd9\xc3\xe9\x79\x62\x31\xd3\x0f\xe4\x0b\x7d\x57\xed\x17\x2d\x13\+  \\xcf\x34\x64\x18\xbb\xfd\xc7\x13\xdd\x4e\x5c\xad\xe8\x5d\xf8\x17\+  \\x03\x42\x7d\xde\x29\xfd\xb9\x58\x94\x62\xb3\xd8\x62\x75\xf6\x1d\+  \\x42\x49\x0e\x2b\x3a\x3e\x74\xb7\x9c\x1d\x70\xc7\x5d\x09\xba\x12\+  \\x92\xdb\xd1\xb5\xc8\x4d\x51\xe5\x03\x25\x4c\x39\xb5\x8b\x68\x17\+  \\x77\x52\x46\xe3\x3a\xa1\xa5\xde\x44\x2e\x9f\x87\xa2\xae\x42\x1d\+  \\x8a\xf3\x0b\xce\xc4\x84\x27\x0b\xeb\x7c\xc3\x94\x25\xad\x49\x12\+  \\x6d\xf0\x8e\x01\xf6\x65\xf1\xcd\x25\x5c\xf4\xf9\x6e\x18\xdc\x16\+  \\x88\xac\xf2\x81\x73\xbf\x6d\x41\x2f\x73\x71\xb8\x8a\x1e\x93\x1c\+  \\xd5\xab\x37\x31\xa8\x97\xe4\x88\xfd\xe7\x46\xb3\x16\xf3\xdb\x11\+  \\xca\x96\x85\x3d\x92\xbd\x1d\xeb\xfc\xa1\x18\x60\xdc\xef\x52\x16\+  \\x7d\xfc\xe6\xcc\xf6\x2c\xe5\x25\x7c\xca\x1e\x78\xd3\xab\xe7\x1b\+  \\xce\x5d\x10\x40\x1a\x3c\xaf\x97\x8d\x3e\x13\x2b\x64\xcb\x70\x11\+  \\x42\x75\x14\xd0\x20\x0b\x9b\xfd\x30\x0e\xd8\x35\x3d\xfe\xcc\x15\+  \\x92\x92\x19\x04\xe9\xcd\x01\x3d\xbd\x11\x4e\x83\xcc\x3d\x40\x1b\+  \\x9b\xfb\x8f\xa2\xb1\x20\x21\x46\x16\xcb\x10\xd2\x9f\x26\x08\x11\+  \\x82\xfa\x33\x0b\xde\x68\xa9\xd7\xdb\xfd\x94\xc6\x47\x30\x4a\x15\+  \\x23\xf9\x00\x8e\x15\xc3\x93\xcd\x52\x3d\x3a\xb8\x59\xbc\x9c\x1a\+  \\xb6\x9b\xc0\x78\xed\x59\x7c\xc0\x53\x66\x24\x13\xb8\xf5\xa1\x10\+  \\xa3\xc2\xf0\xd6\x68\x70\x9b\xb0\xe8\x7f\xed\x17\x26\x73\xca\x14\+  \\x4c\xf3\xac\x0c\x83\x4c\xc2\xdc\xe2\xdf\xe8\x9d\xef\x0f\xfd\x19\+  \\x0f\x18\xec\xe7\xd1\x6f\xf9\xc9\xed\x8b\xb1\xc2\xf5\x29\x3e\x10\+  \\x13\x1e\xe7\x61\xc6\xcb\x77\x3c\xe9\xee\x5d\x33\x73\xb4\x4d\x14\+  \\x98\xe5\x60\xfa\xb7\xbe\x95\x8b\xa3\x6a\x35\x00\x90\x21\x61\x19\+  \\xfe\x1e\xf9\xf8\x65\x2e\x7b\x6e\x4c\xc5\x42\x00\xf4\x69\xb9\x1f\+  \\x5f\xb3\x9b\xbb\xff\xfc\x0c\xc5\x4f\xbb\x29\x80\x38\xe2\xd3\x13\+  \\x37\xa0\x82\xaa\x3f\x3c\x50\xb6\x23\x2a\x34\xa0\xc6\xda\xc8\x18\+  \\x44\x48\x23\x95\x4f\x4b\xe4\xa3\xac\x34\x41\x48\x78\x11\xfb\x1e\+  \\x2b\x0d\x36\xbd\x11\xaf\x6e\xe6\xeb\xc0\x28\x2d\xeb\xea\x5c\x13\+  \\x75\x90\x83\x2c\xd6\x5a\x0a\xe0\x26\xf1\x72\xf8\xa5\x25\x34\x18\+  \\x93\x74\xa4\xb7\x8b\xf1\x0c\x98\x70\xad\x8f\x76\x0f\x2f\x41\x1e\+  \\xdc\xc8\xc6\x52\xf7\x16\x08\x5f\x66\xcc\x19\xaa\x69\xbd\xe8\x12\+  \\x13\x7b\x78\x27\xb5\x1c\xca\xf6\x7f\x3f\xa0\x14\xc4\xec\xa2\x17\+  \\xd7\x99\x56\x71\xe2\xa3\x7c\xf4\x5f\x4f\xc8\x19\xf5\xa7\x8b\x1d\+  \\x26\x20\xd6\x86\x6d\xe6\xcd\xf8\x9b\x31\x1d\x30\xf9\x48\x77\x12\+  \\x30\xa8\x8b\xe8\x08\x60\x01\xf7\x02\x7e\x24\x7c\x37\x1b\x15\x17\+  \\x3c\x92\xae\x22\x0b\xb8\xc1\xb4\x83\x9d\x2d\x5b\x05\x62\xda\x1c\+  \\x65\x1b\xad\xf5\x06\x13\xf9\x50\x72\x82\xfc\x58\x43\x7d\x08\x12\+  \\x3f\x62\x18\xb3\xc8\x57\x37\xe5\x0e\xa3\x3b\x2f\x94\x9c\x8a\x16\+  \\xcf\x7a\xde\xdf\xba\x2d\x85\x9e\xd2\x8b\x0a\x3b\xb9\x43\x2d\x1c\+  \\xc1\x0c\xeb\xcb\x94\x3c\x13\xa3\x63\x97\xe6\xc4\x53\x4a\x9c\x11\+  \\xf1\xcf\xe5\xfe\xb9\x0b\xd8\x8b\x3c\x3d\x20\xb6\xe8\x5c\x03\x16\+  \\xee\x43\x9f\x7e\xa8\x0e\xce\xae\x8b\x4c\xa8\xe3\x22\x34\x84\x1b\+  \\x75\x8a\x23\x4f\x29\xc9\x40\x4d\xd7\x2f\x49\xce\x95\xa0\x32\x11\+  \\x12\x6d\xec\xa2\x73\xfb\x90\x20\xcd\x7b\xdb\x41\xbb\x48\x7f\x15\+  \\x56\x88\xa7\x8b\x50\x3a\xb5\x68\xc0\x5a\x52\x12\xea\x1a\xdf\x1a\+  \\x36\xb5\x48\x57\x72\x44\x71\x41\xb8\x78\x73\x4b\xd2\x70\xcb\x10\+  \\x83\xe2\x1a\xed\x8e\x95\xcd\x51\xe6\x56\x50\xde\x06\x4d\xfe\x14\+  \\x24\x9b\x61\xa8\xf2\xfa\x40\xe6\x9f\x6c\xe4\x95\x48\xe0\x3d\x1a\+  \\xf7\x00\x3d\xa9\xd7\x9c\xe8\xef\xe3\xc3\xae\x5d\x2d\xac\x66\x10\+  \\x34\x41\x8c\x93\x0d\xc4\xe2\xeb\xdc\x74\x1a\xb5\x38\x57\x80\x14\+  \\x81\x51\x6f\xf8\x10\x75\xdb\x26\x14\x12\x61\xe2\x06\x6d\xa0\x19\+  \\xf1\x92\x45\x9b\x2a\x29\x49\x98\x4c\xab\x7c\x4d\x24\x44\x04\x10\+  \\xad\xf7\x16\x42\x75\x73\x5b\xbe\x1f\xd6\xdb\x60\x2d\x55\x05\x14\+  \\x98\xb5\x9c\x92\x52\x50\xf2\xad\xa7\xcb\x12\xb9\x78\xaa\x06\x19\+  \\xff\xe2\x43\x37\x67\xe4\x6e\x99\x91\x7e\x57\xe7\x16\x55\x48\x1f\+  \\xdf\x6d\x8a\x82\xc0\x4e\xe5\xff\x1a\xaf\x96\x50\x2e\x35\x8d\x13\+  \\x57\x09\x2d\xa3\x70\xa2\xde\xbf\xe1\x5a\xbc\xe4\x79\x82\x70\x18\+  \\xad\x4b\xf8\xcb\x0c\x4b\xd6\x2f\x9a\x71\xeb\x5d\x18\xa3\x8c\x1e\+  \\x4c\x2f\x7b\xff\xe7\xee\xe5\x5d\x00\x27\xb3\x3a\xef\xe5\x17\x13\+  \\x1f\xfb\x59\xff\xa1\x6a\x5f\x75\xc0\xf0\x5f\x09\x6b\xdf\xdd\x17\+  \\xe7\x79\x30\x7f\x4a\x45\xb7\x92\xf0\xec\xb7\xcb\x45\x57\xd5\x1d\+  \\x30\x4c\x7e\x8f\x4e\x8b\xb2\x5b\x16\xf4\x52\x9f\x8b\x56\xa5\x12\+  \\x3c\xdf\x5d\x33\x22\x2e\x9f\xf2\x1b\xb1\x27\x87\x2e\xac\x4e\x17\+  \\x0b\x57\x35\xc0\xaa\xf9\x46\xef\x62\x9d\xf1\x28\x3a\x57\x22\x1d\+  \\x67\x56\x21\xb8\x0a\x5c\x8c\xd5\x5d\x02\x97\x59\x84\x76\x35\x12\+  \\x01\xac\x29\x66\x0d\x73\xef\x4a\xf5\xc2\xfc\x6f\x25\xd4\xc2\x16\+  \\x01\x17\xb4\xbf\xd0\x4f\xab\x9d\xb2\xf3\xfb\xcb\x2e\x89\x73\x1c\+  \\x60\x8e\xd0\x77\xe2\x11\x8b\xa2\x4f\x78\x7d\x3f\xbd\x35\xc8\x11\+  \\xf9\xb1\xc4\x15\x5b\xd6\x2d\x8b\x63\xd6\x5c\x8f\x2c\x43\x3a\x16\+  \\x77\xde\x35\xdb\xf1\x4b\xf9\x6d\xfc\x0b\x34\xb3\xf7\xd3\xc8\x1b\+  \\x0a\xab\x01\x29\x77\xcf\xbb\xc4\x7d\x87\x00\xd0\x7a\x84\x5d\x11\+  \\xcd\x15\x42\xf3\x54\xc3\xea\x35\x5d\xa9\x00\x84\x99\xe5\xb4\x15\+  \\x40\x9b\x12\x30\x2a\x74\x65\x83\xb4\xd3\x00\xe5\xff\x1e\x22\x1b\+  \\x08\xa1\x0b\x5e\x9a\x68\x1f\xd2\x50\x84\x20\xef\x5f\x53\xf5\x10\+  \\x4a\x89\x8e\xf5\xc0\x42\xa7\x06\x65\xa5\xe8\xea\x37\xa8\x32\x15\+  \\x9d\x2b\xf2\x32\x71\x13\x51\x48\xbe\xce\xa2\xe5\x45\x52\x7f\x1a\+  \\x42\x5b\xd7\xbf\x26\xac\x32\xed\x36\xc1\x85\xaf\x6b\x93\x8f\x10\+  \\x12\x32\xcd\x6f\x30\x57\x7f\xa8\x84\x31\x67\x9b\x46\x78\xb3\x14\+  \\x97\x7e\xc0\x8b\xfc\x2c\x9f\xd2\xe5\xfd\x40\x42\x58\x56\xe0\x19\+  \\x1e\x4f\x58\xd7\x1d\x7c\xa3\xa3\xaf\x9e\x68\x29\xf7\x35\x2c\x10\+  \\xe6\x62\x2e\x4d\x25\x5b\x8c\x8c\x5b\xc6\xc2\xf3\x74\x43\x37\x14\+  \\x9f\xfb\x79\xa0\xee\x71\xaf\x6f\xf2\x77\xb3\x30\x52\x14\x45\x19\+  \\x87\x7a\x98\x48\x6a\x4e\x9b\x0b\xef\x55\xe0\xbc\x66\x59\x96\x1f\+  \\x94\x4c\x5f\x6d\x02\x11\x41\x67\xb5\x35\x0c\x36\xe0\xf7\xbd\x13\+  \\xba\x1f\xb7\x08\x43\x55\x11\xc1\x22\x43\x8f\x43\xd8\x75\xad\x18\+  \\xa8\xe7\xe4\xca\x93\xaa\x55\x71\xeb\x13\x73\x54\x4e\xd3\xd8\x1e\+  \\xc9\x10\xcf\x5e\x9c\x8a\xd5\x26\x73\xec\xc7\xf4\x10\x84\x47\x13\+  \\xfb\xd4\x82\x76\x43\xed\x8a\xf0\x8f\xe7\xf9\x31\x15\x65\x19\x18\+  \\x3a\x8a\x23\x54\x94\xa8\xad\xec\x73\x61\x78\x7e\x5a\xbe\x1f\x1e\+  \\x64\x36\x96\xb4\x5c\x89\xec\x73\xe8\x3c\x0b\x8f\xf8\xd6\xd3\x12\+  \\xfd\xc3\xbb\xe1\xb3\xab\xe7\x90\x22\x0c\xce\xb2\xb6\xcc\x88\x17\+  \\xfd\xb4\x2a\xda\xa0\x96\x21\x35\x2b\x8f\x81\x5f\xe4\xff\x6a\x1d\+  \\x1e\xb1\x5a\x88\x24\xfe\x34\x01\x7b\xf9\xb0\xbb\xee\xdf\x62\x12\+  \\x65\x5d\x71\xaa\xad\x3d\x82\xc1\xd9\x37\x9d\x6a\xea\x97\xfb\x16\+  \\xbf\xb4\x0d\x15\x19\xcd\xe2\x31\xd0\x85\x44\x05\xe5\x7d\xba\x1c\+  \\xf7\x90\x28\xad\x2f\xc0\x2d\x1f\xa2\xd3\x4a\x23\xaf\x8e\xf4\x11\+  \\x35\xb5\x72\x98\x3b\x30\xf9\xa6\x8a\x88\x1d\xec\x5a\xb2\x71\x16\+  \\x82\x62\x8f\x7e\x4a\x7c\xb7\x50\xad\xea\x24\xa7\xf1\x1e\x0e\x1c\+  \\x91\x9d\x19\x8f\xae\xad\x72\x52\xac\x12\x77\x08\x57\xd3\x88\x11\+  \\xf6\x04\xe0\x32\x1a\x59\x0f\x67\x57\xd7\x94\xca\x2c\x08\xeb\x15\+  \\x33\x06\x98\xbf\x60\x2f\xd3\x40\x2d\x0d\x3a\xfd\x37\xca\x65\x1b\+  \\xe0\x03\xbf\x77\x9c\xfd\x83\x48\x3c\x48\x44\xfe\x62\x9e\x1f\x11\+  \\xd8\xc4\xae\x95\x03\xfd\xa4\x5a\x4b\x5a\xd5\xbd\xfb\x85\x67\x15\+  \\x0e\x76\x1a\x7b\x44\x3c\x4e\x31\xde\xb0\x4a\xad\x7a\x67\xc1\x1a\+  \\xc9\x89\xf0\xcc\xaa\xe5\xd0\xde\x8a\xae\x4e\xac\xac\xe0\xb8\x10\+  \\x3b\xac\x2c\x80\x15\x1f\x85\x96\x2d\x5a\x62\xd7\xd7\x18\xe7\x14\+  \\x4a\xd7\x37\xe0\xda\x66\x26\xfc\xb8\xf0\x3a\xcd\x0d\xdf\x20\x1a\+  \\x8e\xe6\x22\xcc\x48\x00\x98\x9d\x73\xd6\x44\xa0\x68\x8b\x54\x10\+  \\x32\xa0\x2b\xff\x5a\x00\xfe\x84\x10\x0c\x56\xc8\x42\xae\x69\x14\+  \\x3e\x88\xf6\xbe\x71\x80\x3d\xa6\x14\x8f\x6b\x7a\xd3\x19\x84\x19\+  \\x4e\x2a\xb4\x2e\x8e\xe0\xcc\xcf\xd9\x72\x06\x59\x48\x20\xe5\x1f\+  \\x70\x9a\x30\xdd\x58\x0c\xe0\x21\xc8\x07\xa4\x37\x2d\x34\xef\x13\+  \\x0d\xc1\x7c\x14\x6f\x0f\x58\x2a\xba\x09\x8d\x85\x38\x01\xeb\x18\+  \\x50\xf1\x9b\xd9\x4a\x13\xee\xb4\x28\x4c\xf0\xa6\x86\xc1\x25\x1f\+  \\xd2\x76\x01\xc8\x0e\xcc\x14\x71\x99\x2f\x56\x28\xf4\x98\x77\x13\+  \\x86\xd4\x01\x7a\x12\xff\x59\xcd\x7f\xbb\x6b\x32\x31\x7f\x55\x18\+  \\xa8\x49\x82\x18\xd7\x7e\xb0\xc0\x5f\xaa\x06\x7f\xfd\xde\x6a\x1e\+  \\x09\x6e\x51\x6f\x46\x4f\x6e\xd8\x7b\x2a\x64\x6f\x5e\xcb\x02\x13\+  \\x8b\xc9\x25\x0b\x18\xe3\x89\xce\x1a\x35\x3d\x0b\x36\x7e\xc3\x17\+  \\xee\x3b\xef\x0d\xde\x5b\x2c\x82\x61\x82\x0c\x8e\xc3\x5d\xb4\x1d\+  \\x75\x85\xb5\xc8\x6a\xb9\x5b\xf1\x7c\xd1\xc7\x38\x9a\xba\x90\x12\+  \\xd2\xe6\xe2\x7a\xc5\xa7\xb2\x2d\xdc\xc5\xf9\xc6\x40\xe9\x34\x17\+  \\x86\xa0\x9b\xd9\xb6\x51\x1f\x39\x53\x37\xb8\xf8\x90\x23\x02\x1d\+  \\x54\x44\x01\x48\x12\x93\xb3\x03\x94\x22\x73\x9b\x3a\x56\x21\x12\+  \\x69\x95\x01\xda\xd6\x77\xa0\x04\x39\xeb\x4f\x42\xc9\xab\xa9\x16\+  \\xc3\xfa\x81\x90\xcc\x95\xc8\x45\x07\xe6\xe3\x92\xbb\x16\x54\x1c\+  \\xba\x3c\x51\xda\x9f\x5d\x9d\x8b\xc4\x6f\xce\x3b\x35\x8e\xb4\x11\+  \\xe8\x8b\xe5\xd0\x07\xb5\x84\xae\xb5\x0b\xc2\x8a\xc2\xb1\x21\x16\+  \\xe3\xee\x1e\xc5\x49\xe2\x25\x1a\xa3\x8e\x72\x2d\x33\x1e\xaa\x1b\+  \\x4d\x55\x33\x1b\x6e\xad\x57\xf0\x25\x99\x67\xfc\xdf\x52\x4a\x11\+  \\xa1\x2a\x00\xa2\xc9\x98\x6d\x6c\x6f\x7f\x81\xfb\x97\xe7\x9c\x15\+  \\x49\x35\x80\x0a\xfc\xfe\x88\x47\x4b\xdf\x61\xfa\x7d\x21\x04\x1b\+  \\x4e\x21\x90\x86\x5d\x9f\xb5\x0c\x8f\x2b\x7d\xbc\xee\x94\xe2\x10\+  \\xa1\x29\x34\xe8\x34\x07\xe3\xcf\x72\x76\x9c\x6b\x2a\x3a\x1b\x15\+  \\x0a\x34\x41\x22\x02\xc9\xdb\x83\x0f\x94\x83\x06\xb5\x08\x62\x1a\+  \\x86\xc0\x68\x55\xa1\x5d\x69\xb2\x89\x3c\x12\x24\x71\x45\x7d\x10\+  \\xa7\xf0\xc2\xaa\x09\xb5\x03\x1f\xac\xcb\x16\x6d\xcd\x96\x9c\x14\+  \\xd1\xac\x73\x15\x4c\xa2\xc4\x26\x97\x7e\x5c\xc8\x80\xbc\xc3\x19\+  \\x03\x4c\x68\x8d\x6f\xe5\x3a\x78\x1e\xcf\x39\x7d\xd0\x55\x1a\x10\+  \\x03\x5f\xc2\x70\xcb\x9e\x49\x16\xe6\x42\x88\x9c\x44\xeb\x20\x14\+  \\xc4\xf6\xf2\x4c\x7e\x06\xdc\x9b\x9f\x53\xaa\xc3\x15\x26\x29\x19\+  \\x76\xb4\x2f\xe0\x1d\x08\xd3\x82\x87\xe8\x94\x34\x9b\x6f\x73\x1f\+  \\xc9\xd0\x1d\xac\x12\xe5\xc3\xb1\x54\x11\xdd\x00\xc1\x25\xa8\x13\+  \\xfc\x44\x25\x57\x57\xde\x34\xde\xa9\x55\x14\x41\x31\x2f\x92\x18\+  \\x3b\x96\xee\x2c\xed\x15\xc2\x55\x14\x6b\x59\x91\xfd\xba\xb6\x1e\+  \\xe5\x1d\x15\x3c\xb4\x4d\x99\xb5\xec\xe2\xd7\x7a\xde\x34\x32\x13\+  \\x5e\x65\x1a\x4b\x21\xa1\xff\xe2\xa7\xdb\x8d\x19\x16\xc2\xfe\x17\+  \\xb6\xfe\xe0\x9d\x69\x89\xbf\xdb\x91\x52\xf1\x9f\x9b\x72\xfe\x1d\+  \\x31\x9f\xac\x02\xe2\xb5\x57\x29\x9b\xd3\xf6\x43\xa1\x07\xbf\x12\+  \\xfe\xc6\x57\x83\x5a\xa3\xad\xf3\x81\x88\xf4\x94\x89\xc9\x6e\x17\+  \\xbd\xb8\x2d\x24\x31\x0c\x99\x70\xa2\xaa\x31\xfa\xeb\x7b\x4a\x1d\+  \\x76\x93\x9c\xb6\x9e\xa7\x5f\x86\xa5\x0a\x5f\x7c\x73\x8d\x4e\x12\+  \\x54\xb8\x43\x64\x86\x91\xf7\xe7\x4e\xcd\x76\x5b\xd0\x30\xe2\x16\+  \\x69\xa6\x54\xfd\xe7\x75\xf5\xa1\xa2\x80\x54\x72\x04\xbd\x9a\x1c\+  \\x01\xe8\x54\xfe\xb0\x69\x39\xa5\x65\xd0\x74\xc7\x22\xb6\xe0\x11\+  \\x02\x22\xea\x3d\x1d\xc4\x87\x0e\x7f\x04\x52\x79\xab\xe3\x58\x16\+  \\x82\xaa\x64\x8d\x24\xb5\x29\xd2\x9e\x85\xa6\x57\x96\x1c\xef\x1b\+  \\x91\xea\x5e\xd8\x36\x11\x5a\x43\x83\x13\xc8\xf6\xdd\x71\x75\x11\+  \\x36\xa5\x76\x8e\x84\x95\x30\x14\x64\x18\x7a\x74\x55\xce\xd2\x15\+  \\x83\x4e\x14\xb2\xe5\xba\x3c\x19\x7d\x9e\x98\xd1\xea\x81\x47\x1b\+  \\x12\xb1\x4c\x8f\xcf\xf4\xc5\x2f\x0e\x63\xff\xc2\x32\xb1\x0c\x11\+  \\x56\xdd\x1f\x73\x03\x72\xb7\xbb\xd1\x3b\xbf\x73\x7f\xdd\x4f\x15\+  \\xac\xd4\xe7\x4f\x84\x4e\xa5\x2a\xc6\x0a\xaf\x50\xdf\xd4\xa3\x1a\+  \\xeb\xe4\xf0\xb1\x12\x51\xa7\xda\xbb\x66\x6d\x92\x0b\x65\xa6\x10\+  \\x26\x1e\x6d\x5e\x57\x25\x51\xd1\x6a\xc0\x08\x77\x4e\xfe\xcf\x14\+  \\xb0\x65\x08\x36\xad\x6e\xa5\x85\x85\xf0\xca\x14\xe2\xfd\x03\x1a\+  \\x8e\x3f\xc5\x41\x2c\x65\x87\x73\x53\xd6\xfe\x4c\xad\x7e\x42\x10\+  \\x71\x8f\x36\x52\x77\x3e\x69\x50\xe8\x8b\x3e\xa0\x58\x1e\x53\x14\+  \\x4e\x33\xc4\x26\x15\x8e\x83\x64\xe2\x2e\x4e\xc8\xee\xe5\x67\x19\+  \\x22\x40\x75\x70\x9a\x71\xa4\xfd\x9a\xba\x61\x7a\x6a\xdf\xc1\x1f\+  \\x15\x48\x49\x86\x00\xc7\x86\xde\xa0\x14\x7d\x8c\xa2\x2b\xd9\x13\+  \\x1a\x9a\xdb\xa7\xc0\x78\x28\x16\xc9\x59\x9c\x2f\x8b\x76\xcf\x18\+  \\xa1\x80\xd2\xd1\xf0\x96\xb2\x5b\x3b\x70\x83\xfb\x2d\x54\x03\x1f\+  \\x64\x90\x23\x83\x56\x9e\x4f\x19\x25\x26\x32\xbd\x9c\x14\x62\x13\+  \\x7e\x74\xec\x23\xec\x85\xa3\x5f\xae\xaf\x7e\xec\xc3\x99\x3a\x18\+  \\x9d\x91\xe7\x2c\x67\x67\x8c\xf7\x99\x5b\x9e\xe7\x34\x40\x49\x1e\+  \\x02\xbb\x10\x7c\xa0\xc0\xb7\x3a\x40\xf9\xc2\x10\x21\xc8\xed\x12\+  \\xc3\xe9\x14\x9b\xc8\xb0\x65\x49\x90\xb7\xf3\x54\x29\x3a\xa9\x17\+  \\x33\x24\xda\xc1\xfa\x1c\xbf\x5b\x74\xa5\x30\xaa\xb3\x88\x93\x1d\+  \\xa0\x56\x28\xb9\x1c\x72\x57\xb9\x68\x67\x5e\x4a\x70\x35\x7c\x12\+  \\x48\x6c\x72\xe7\xa3\x4e\xad\xe7\x42\x01\xf6\x5c\xcc\x42\x1b\x17\+  \\x5a\x07\x4f\xe1\x4c\xa2\x98\xa1\x93\x81\x33\x74\x7f\x13\xe2\x1c\+  \\x98\x64\xd1\x0c\x70\x65\xff\x44\xfc\x30\xa0\xa8\x2f\x4c\x0d\x12\+  \\xbe\xbd\x05\x10\xcc\x3e\x3f\x56\x3b\x3d\xc8\x92\x3b\x9f\x90\x16\+  \\x2e\x2d\x07\x14\x7f\x0e\xcf\x2b\x8a\x4c\x7a\x77\x0a\xc7\x34\x1c\+  \\x3d\x7c\x84\x6c\x0f\x69\x61\x5b\xd6\x6f\xac\x8a\x66\xfc\xa0\x11\+  \\x4c\x9b\xa5\x47\x53\xc3\x39\xf2\xcb\x8b\x57\x2d\x80\x3b\x09\x16\+  \\x1f\x02\x8f\x19\x28\x34\xc8\xee\xbe\x6e\xad\x38\x60\x8a\x8b\x1b\+  \\x53\x61\xf9\x0f\x99\x20\x3d\x55\x37\x65\x6c\x23\x7c\x36\x37\x11\+  \\xa8\xb9\xf7\x53\xbf\x68\x8c\x2a\x85\x7e\x47\x2c\x1b\x04\x85\x15\+  \\x12\xa8\xf5\x28\xef\x82\x2f\x75\x26\x5e\x59\xf7\x21\x45\xe6\x1a\+  \\x0b\x89\x99\x79\xd5\xb1\x3d\x09\xd8\xda\x97\x3a\x35\xeb\xcf\x10\+  \\x4e\xeb\xff\xd7\x4a\x1e\x8d\x0b\x8e\xd1\x3d\x89\x02\xe6\x03\x15\+  \\x22\xe6\xff\x8d\xdd\x65\x70\x8e\xf1\x45\x8d\x2b\x83\xdf\x44\x1a\+  \\xd5\xef\xbf\x78\xaa\x3f\x06\xf9\xb6\x4b\x38\xfb\xb1\x0b\x6b\x10\+  \\xca\xeb\xef\x16\x95\xcf\x47\xb7\xa4\x5e\x06\x7a\x9e\xce\x85\x14\+  \\xbd\xe6\xab\x5c\x7a\xc3\x19\xe5\x4d\xf6\x87\x18\x46\x42\xa7\x19\+  \\x36\x70\xeb\x79\x2c\x1a\x30\xaf\xf0\xf9\x54\xcf\x6b\x89\x08\x10\+  \\x43\x4c\x66\x98\xb7\x20\xfc\xda\x6c\x38\x2a\xc3\xc6\xab\x0a\x14\+  \\x54\xdf\x7f\x7e\xe5\x28\xbb\x11\x88\xc6\xf4\x73\xb8\x56\x0d\x19\+  \\x2a\xd7\x1f\xde\x1e\xf3\x29\x16\x2a\xf8\xf1\x90\x66\xac\x50\x1f\+  \\x7a\xe6\xd3\x4a\xf3\x37\xda\x4d\x1a\x3b\x97\x1a\xc0\x6b\x92\x13\+  \\x19\xe0\x88\x1d\xf0\xc5\x50\xe1\xe0\x09\x3d\x21\xb0\x06\x77\x18\+  \\x1f\x18\xeb\x24\x6c\xf7\xa4\x19\x59\x4c\x8c\x29\x5c\xc8\x94\x1e\+  \\x13\xef\x12\x97\xa3\x1a\x07\xb0\xb7\xaf\xf7\x99\x39\xfd\x1c\x13\+  \\xd8\xaa\xd7\x7c\x4c\xe1\x08\x9c\xa5\x9b\x75\x00\x88\x3c\xe4\x17\+  \\x8e\x95\x0d\x9c\x9f\x19\x0b\x03\x8f\x02\x93\x00\xaa\x4b\xdd\x1d\+  \\x79\x7d\x88\xc1\x03\xf0\xe6\x61\x99\xe1\x5b\x40\x4a\x4f\xaa\x12\+  \\xd7\x9c\xea\xb1\x04\xac\x60\xba\xff\xd9\x72\xd0\x1c\xe3\x54\x17\+  \\x0d\x44\x65\xde\x05\xd7\xf8\xa8\x7f\x90\x8f\x04\xe4\x1b\x2a\x1d\+  \\x88\x4a\xff\xaa\x63\x86\x9b\xc9\x4f\xba\xd9\x82\x6e\x51\x3a\x12\+  \\x2a\x1d\xbf\x95\xfc\x67\x02\xbc\xe3\x28\x90\x23\xca\xe5\xc8\x16\+  \\x74\xe4\x2e\xbb\xfb\x01\x03\xab\x1c\x33\x74\xac\x3c\x1f\x7b\x1c\+  \\xc9\x4e\xfd\x54\x3d\xe1\xe1\xea\xf1\x9f\xc8\xeb\x85\xf3\xcc\x11\+  \\x7b\xa2\x3c\xaa\x8c\x59\x9a\x65\xee\xc7\xba\x66\x67\x30\x40\x16\+  \\x1a\xcb\xcb\xd4\xef\xef\x00\xff\xe9\x79\x69\x40\x81\x3c\xd0\x1b\+  \\xf0\x5e\xff\xe4\xf5\x95\x60\x3f\x32\xec\x41\xc8\xd0\x25\x62\x11\+  \\xac\x36\x3f\x5e\x73\xbb\x38\xcf\x3e\x67\x52\xfa\x44\xaf\xba\x15\+  \\x57\x04\xcf\x35\x50\xea\x06\x83\x0e\x01\xe7\x38\x16\x5b\x29\x1b\+  \\xb6\x62\xa1\x21\x72\x52\xe4\x11\xa9\x60\x90\xe3\xed\xd8\xf9\x10\+  \\x64\xbb\x09\xaa\x0e\x67\x5d\x56\xd3\x78\x74\x5c\x29\x4f\x38\x15\+  \\x3d\x2a\x8c\x54\xd2\xc0\xf4\x2b\x08\x97\x91\xb3\xf3\x62\x86\x1a\+  \\x66\x9a\xd7\x74\x83\xf8\x78\x1b\x65\xfe\x3a\x50\xd8\xfd\x93\x10\+  \\x00\x81\x0d\x52\xa4\x36\x57\x62\xfe\xbd\x49\x64\x4e\xfd\xb8\x14\+  \\x40\xe1\x90\x66\x4d\x04\xed\xfa\x7d\x2d\x5c\xfd\xa1\x3c\xe7\x19\+  \\xc8\x8c\x1a\x60\xb0\x22\xd4\xbc\x6e\x9c\x59\x3e\xe5\x85\x30\x10\+  \\xfa\x2f\x21\x78\x5c\x2b\x09\x6c\x8a\x03\xf0\x8d\x5e\xa7\x3c\x14\+  \\xf8\x7b\x29\x96\x33\x76\x0b\x07\x6d\x04\x6c\x31\x36\xd1\x4b\x19\+  \\xf6\xda\xb3\x7b\xc0\x53\xce\x48\x88\x05\xc7\xbd\x83\xc5\x9e\x1f\+  \\xda\x68\x50\x4d\x58\xf4\x80\x2d\x75\x63\x9c\x56\x72\x3b\xc3\x13\+  \\x10\x83\xa4\x60\x6e\x31\xe1\x78\x52\x7c\x43\xec\x4e\x0a\xb4\x18"#++-- | Number of mantissa bits of a 64-bit float. The number of significant bits+-- (floatDigits (undefined :: Double)) is 53 since we have a leading 1 for+-- normal floats and 0 for subnormal floats+double_mantissa_bits :: Int+double_mantissa_bits = 52++-- | Number of exponent bits of a 64-bit float+double_exponent_bits :: Int+double_exponent_bits = 11++-- | Bias in encoded 64-bit float representation (2^10 - 1)+double_bias :: Int+double_bias = 1023++data FloatingDecimal = FloatingDecimal+  { dmantissa :: !Word64+  , dexponent :: !Int32+  } deriving (Show, Eq)++-- | Quick check for small integers+d2dSmallInt :: Word64 -> Word64 -> Maybe FloatingDecimal+d2dSmallInt m e =+  let m2 = (1 `unsafeShiftL` double_mantissa_bits) .|. m+      e2 = word64ToInt e - (double_bias + double_mantissa_bits)+      fraction = m2 .&. mask (-e2)+   in case () of+        _ -- f = m2 * 2^e2 >= 2^53 is an integer.+          -- Ignore this case for now.+          | e2 > 0 -> Nothing+          -- f < 1+          | e2 < -52 -> Nothing+          -- Since 2^52 <= m2 < 2^53 and 0 <= -e2 <= 52:+          --    1 <= f = m2 / 2^-e2 < 2^53.+          -- Test if the lower -e2 bits of the significand are 0, i.e.+          -- whether the fraction is 0.+          | fraction /= 0 -> Nothing+          -- f is an integer in the range [1, 2^53).+          -- Note: mantissa might contain trailing (decimal) 0's.+          -- Note: since 2^53 < 10^16, there is no need to adjust decimalLength17().+          | otherwise -> Just $ FloatingDecimal (m2 `unsafeShiftR` (-e2)) 0+++-- | Removes trailing (decimal) zeros for small integers in the range [1, 2^53)+unifySmallTrailing :: FloatingDecimal -> FloatingDecimal+unifySmallTrailing fd@(FloatingDecimal m e) =+  let !(q, r) = dquotRem10 m+   in if r == 0+        then unifySmallTrailing $ FloatingDecimal q (e + 1)+        else fd++-- TODO: 128-bit intrinsics+-- | Multiply a 64-bit number with a 128-bit number while keeping the upper 64+-- bits. Then shift by specified amount minus 64+mulShift64 :: Word64 -> (Word64, Word64) -> Int -> Word64+mulShift64 m (factorHi, factorLo) shift =+  let !(b0Hi, _   ) = m `timesWord2` factorLo+      !(b1Hi, b1Lo) = m `timesWord2` factorHi+      total = b0Hi + b1Lo+      high  = b1Hi + boolToWord64 (total < b0Hi)+      dist  = shift - 64+   in (high `unsafeShiftL` (64 - dist)) .|. (total `unsafeShiftR` dist)++-- | Index into the 128-bit word lookup table double_pow5_inv_split+get_double_pow5_inv_split :: Int -> (Word64, Word64)+get_double_pow5_inv_split =+  let !(Addr arr) = double_pow5_inv_split+   in getWord128At arr++-- | Index into the 128-bit word lookup table double_pow5_split+get_double_pow5_split :: Int -> (Word64, Word64)+get_double_pow5_split =+  let !(Addr arr) = double_pow5_split+   in getWord128At arr++-- | Take the high bits of m * 5^-e2-q / 2^k / 2^q-k+mulPow5DivPow2 :: Word64 -> Int -> Int -> Word64+mulPow5DivPow2 m i j = mulShift64 m (get_double_pow5_split i) j++-- | Take the high bits of m * 2^k / 5^q / 2^-e2+q+k+mulPow5InvDivPow2 :: Word64 -> Int -> Int -> Word64+mulPow5InvDivPow2 m q j = mulShift64 m (get_double_pow5_inv_split q) j++-- | Handle case e2 >= 0+d2dGT :: Int32 -> Word64 -> Word64 -> Word64 -> (BoundsState Word64, Int32)+d2dGT e2' u v w =+  let e2 = int32ToInt e2'+      q = log10pow2 e2 - fromEnum (e2 > 3)+      -- k = B0 + log_2(5^q)+      k = double_pow5_inv_bitcount + pow5bits q - 1+      i = -e2 + q + k+      -- (u, v, w) * 2^k / 5^q / 2^-e2+q+k+      u' = mulPow5InvDivPow2 u q i+      v' = mulPow5InvDivPow2 v q i+      w' = mulPow5InvDivPow2 w q i+      !(vvTrailing, vuTrailing, vw') =+        case () of+          _ | q <= 21 && (drem5 v == 0)+                -> (multipleOfPowerOf5 v q, False, w')+            | q <= 21 && acceptBounds v+                -> (False, multipleOfPowerOf5 u q, w')+            | q <= 21+                -> (False, False, w' - boolToWord64 (multipleOfPowerOf5 w q))+            | otherwise+                -> (False, False, w')+   in (BoundsState u' v' vw' 0 vuTrailing vvTrailing, intToInt32 q)++-- | Handle case e2 < 0+d2dLT :: Int32 -> Word64 -> Word64 -> Word64 -> (BoundsState Word64, Int32)+d2dLT e2' u v w =+  let e2 = int32ToInt e2'+      q = log10pow5 (-e2) - fromEnum (-e2 > 1)+      e10 = q + e2+      i = -e2 - q+      -- k = log_2(5^-e2-q) - B1+      k = pow5bits i - double_pow5_bitcount+      j = q - k+      -- (u, v, w) * 5^-e2-q / 2^k / 2^q-k+      u' = mulPow5DivPow2 u i j+      v' = mulPow5DivPow2 v i j+      w' = mulPow5DivPow2 w i j+      !(vvTrailing, vuTrailing, vw') =+        case () of+          _ | q <= 1 && acceptBounds v+                -> (True, v - u == 2, w') -- mmShift == 1+            | q <= 1+                -> (True, False, w' - 1)+            | q < 63+                -> (multipleOfPowerOf2 v (q - 1), False, w')+            | otherwise+                -> (False, False, w')+   in (BoundsState u' v' vw' 0 vuTrailing vvTrailing, intToInt32 e10)++-- | Returns the decimal representation of the given mantissa and exponent of a+-- 64-bit Double using the ryu algorithm.+d2d :: Word64 -> Word64 -> FloatingDecimal+d2d m e =+  let !mf = if e == 0+              then m+              else (1 `unsafeShiftL` double_mantissa_bits) .|. m+      !ef = intToInt32 $ if e == 0+              then 1 - (double_bias + double_mantissa_bits)+              else word64ToInt e - (double_bias + double_mantissa_bits)+      !e2 = ef - 2+      -- Step 2. 3-tuple (u, v, w) * 2**e2+      !u = 4 * mf - 1 - boolToWord64 (m /= 0 || e <= 1)+      !v = 4 * mf+      !w = 4 * mf + 2+      -- Step 3. convert to decimal power base+      !(state, e10) =+        if e2 >= 0+           then d2dGT e2 u v w+           else d2dLT e2 u v w+      -- Step 4: Find the shortest decimal representation in the interval of+      -- valid representations.+      !(output, removed) =+        let rounded = closestCorrectlyRounded (acceptBounds v)+         in first rounded $ if vvIsTrailingZeros state || vuIsTrailingZeros state+           then trimTrailing state+           else trimNoTrailing state+      !e' = e10 + removed+   in FloatingDecimal output e'++-- | Split a Double into (sign, mantissa, exponent)+breakdown :: Double -> (Bool, Word64, Word64)+breakdown f =+  let bits = castDoubleToWord64 f+      sign = ((bits `unsafeShiftR` (double_mantissa_bits + double_exponent_bits)) .&. 1) /= 0+      mantissa = bits .&. mask double_mantissa_bits+      expo = (bits `unsafeShiftR` double_mantissa_bits) .&. mask double_exponent_bits+   in (sign, mantissa, expo)++-- | Dispatches to `d2d` or `d2dSmallInt` and applies the given formatters+{-# INLINE d2s' #-}+d2s' :: (Bool -> Word64 -> Int32 -> a) -> (NonNumbersAndZero -> a) -> Double -> a+d2s' formatter specialFormatter d =+  let (sign, mantissa, expo) = breakdown d+   in if (expo == mask double_exponent_bits) || (expo == 0 && mantissa == 0)+         then specialFormatter NonNumbersAndZero+                  { negative=sign+                  , exponent_all_one=expo > 0+                  , mantissa_non_zero=mantissa > 0 }+         else let v = unifySmallTrailing <$> d2dSmallInt mantissa expo+                  FloatingDecimal m e = fromMaybe (d2d mantissa expo) v+               in formatter sign m e++-- | Render a Double in scientific notation+d2s :: Double -> Builder+d2s d = primBounded (d2s' toCharsScientific toCharsNonNumbersAndZero d) ()++-- | Returns the decimal representation of a Double. NaN and Infinity will+-- return `FloatingDecimal 0 0`+d2Intermediate :: Double -> FloatingDecimal+d2Intermediate = d2s' (const FloatingDecimal) (const $ FloatingDecimal 0 0)
+ Data/ByteString/Builder/RealFloat/F2S.hs view
@@ -0,0 +1,258 @@+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE BangPatterns, MagicHash #-}+-- |+-- Module      : Data.ByteString.Builder.RealFloat.F2S+-- Copyright   : (c) Lawrence Wu 2021+-- License     : BSD-style+-- Maintainer  : lawrencejwu@gmail.com+--+-- Implementation of float-to-string conversion++module Data.ByteString.Builder.RealFloat.F2S+    ( FloatingDecimal(..)+    , f2s+    , f2Intermediate+    ) where++import Control.Arrow (first)+import Data.Bits ((.|.), (.&.), unsafeShiftL, unsafeShiftR)+import Data.ByteString.Builder.Internal (Builder)+import Data.ByteString.Builder.Prim (primBounded)+import Data.ByteString.Builder.RealFloat.Internal+import GHC.Int (Int32(..))+import GHC.Word (Word32(..), Word64(..))++-- See Data.ByteString.Builder.RealFloat.TableGenerator for a high-level+-- explanation of the ryu algorithm++-- | Table of 2^k / 5^q + 1+-- Byte-swapped version of+-- > fmap (finv float_pow5_inv_bitcount) [0..float_max_inv_split]+--+-- Displayed here as 2 Word64 table values per line+float_pow5_inv_split :: Addr+float_pow5_inv_split = Addr+  "\x01\x00\x00\x00\x00\x00\x00\x08\x67\x66\x66\x66\x66\x66\x66\x06\+  \\xb9\x1e\x85\xeb\x51\xb8\x1e\x05\xfa\x7e\x6a\xbc\x74\x93\x18\x04\+  \\x2a\xcb\x10\xc7\xba\xb8\x8d\x06\x22\x3c\xda\x38\x62\x2d\x3e\x05\+  \\x4e\x63\x7b\x2d\xe8\xbd\x31\x04\x16\xd2\x2b\xaf\xa6\xfc\xb5\x06\+  \\x78\x0e\x23\x8c\xb8\x63\x5e\x05\x2d\xa5\xb5\x09\xfa\x82\x4b\x04\+  \\xae\x6e\xef\x75\xf6\x37\xdf\x06\x58\x25\x59\x5e\xf8\x5f\x7f\x05\+  \\x47\x84\x7a\x4b\x60\xe6\x65\x04\x71\xa0\x5d\x12\x9a\x70\x09\x07\+  \\xc1\xe6\x4a\xa8\xe1\x26\xa1\x05\x67\x85\xd5\xb9\xe7\xeb\x80\x04\+  \\x0b\x6f\x22\xf6\xa5\xac\x34\x07\xa3\x25\xb5\x91\x51\xbd\xc3\x05\+  \\xe9\xea\x90\x74\x74\x97\x9c\x04\x0e\xab\xb4\xed\x53\xf2\x60\x07\+  \\xd8\x88\x90\x24\x43\x28\xe7\x05\xe0\xd3\xa6\x83\x02\xed\xb8\x04\+  \\x66\xb9\xd7\x05\x04\x48\x8e\x07\x52\x94\xac\x04\xd0\x6c\x0b\x06\+  \\xdb\xa9\x23\x6a\xa6\xf0\xd5\x04\x2b\x76\x9f\x76\x3d\xb4\xbc\x07\+  \\xef\xc4\xb2\x2b\x31\x90\x30\x06\xf3\x03\x8f\xbc\x8d\xa6\xf3\x04\+  \\x51\x06\x18\x94\xaf\x3d\xec\x07\xda\xd1\xac\xa9\xbf\x97\x56\x06\+  \\xe2\xa7\xf0\xba\xff\x12\x12\x05"#++-- | Table of 5^(-e2-q) / 2^k + 1+-- Byte-swapped version of+-- > fmap (fnorm float_pow5_bitcount) [0..float_max_split]+--+-- Displayed here as 2 Word64 table values per line+float_pow5_split :: Addr+float_pow5_split = Addr+  "\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x14\+  \\x00\x00\x00\x00\x00\x00\x00\x19\x00\x00\x00\x00\x00\x00\x40\x1f\+  \\x00\x00\x00\x00\x00\x00\x88\x13\x00\x00\x00\x00\x00\x00\x6a\x18\+  \\x00\x00\x00\x00\x00\x80\x84\x1e\x00\x00\x00\x00\x00\xd0\x12\x13\+  \\x00\x00\x00\x00\x00\x84\xd7\x17\x00\x00\x00\x00\x00\x65\xcd\x1d\+  \\x00\x00\x00\x00\x20\x5f\xa0\x12\x00\x00\x00\x00\xe8\x76\x48\x17\+  \\x00\x00\x00\x00\xa2\x94\x1a\x1d\x00\x00\x00\x40\xe5\x9c\x30\x12\+  \\x00\x00\x00\x90\x1e\xc4\xbc\x16\x00\x00\x00\x34\x26\xf5\x6b\x1c\+  \\x00\x00\x80\xe0\x37\x79\xc3\x11\x00\x00\xa0\xd8\x85\x57\x34\x16\+  \\x00\x00\xc8\x4e\x67\x6d\xc1\x1b\x00\x00\x3d\x91\x60\xe4\x58\x11\+  \\x00\x40\x8c\xb5\x78\x1d\xaf\x15\x00\x50\xef\xe2\xd6\xe4\x1a\x1b\+  \\x00\x92\xd5\x4d\x06\xcf\xf0\x10\x80\xf6\x4a\xe1\xc7\x02\x2d\x15\+  \\x20\xb4\x9d\xd9\x79\x43\x78\x1a\x94\x90\x02\x28\x2c\x2a\x8b\x10\+  \\xb9\x34\x03\x32\xb7\xf4\xad\x14\xe7\x01\x84\xfe\xe4\x71\xd9\x19\+  \\x30\x81\x12\x1f\x2f\xe7\x27\x10\x7c\x21\xd7\xe6\xfa\xe0\x31\x14\+  \\xdb\xe9\x8c\xa0\x39\x59\x3e\x19\x52\x24\xb0\x08\x88\xef\x8d\x1f\+  \\xb3\x16\x6e\x05\xb5\xb5\xb8\x13\x60\x9c\xc9\x46\x22\xe3\xa6\x18\+  \\x78\x03\x7c\xd8\xea\x9b\xd0\x1e\x2b\x82\x4d\xc7\x72\x61\x42\x13\+  \\xb6\xe2\x20\x79\xcf\xf9\x12\x18\x64\x1b\x69\x57\x43\xb8\x17\x1e\+  \\x1e\xb1\xa1\x16\x2a\xd3\xce\x12\x66\x1d\x4a\x9c\xf4\x87\x82\x17\+  \\xbf\xa4\x5c\xc3\xf1\x29\x63\x1d\xf7\xe6\x19\x1a\x37\xfa\x5d\x12\+  \\xb5\x60\xa0\xe0\xc4\x78\xf5\x16\xe3\x78\xc8\x18\xf6\xd6\xb2\x1c\+  \\x8d\x4b\x7d\xcf\x59\xc6\xef\x11\x71\x9e\x5c\x43\xf0\xb7\x6b\x16\+  \\x0d\xc6\x33\x54\xec\xa5\x06\x1c"#++-- | Number of mantissa bits of a 32-bit float. The number of significant bits+-- (floatDigits (undefined :: Float)) is 24 since we have a leading 1 for+-- normal floats and 0 for subnormal floats+float_mantissa_bits :: Int+float_mantissa_bits = 23++-- | Number of exponent bits of a 32-bit float+float_exponent_bits :: Int+float_exponent_bits = 8++-- | Bias in encoded 32-bit float representation (2^7 - 1)+float_bias :: Int+float_bias = 127++data FloatingDecimal = FloatingDecimal+  { fmantissa :: !Word32+  , fexponent :: !Int32+  } deriving (Show, Eq)++-- | Multiply a 32-bit number with a 64-bit number while keeping the upper 64+-- bits. Then shift by specified amount minus 32+mulShift32 :: Word32 -> Word64 -> Int -> Word32+mulShift32 m factor shift =+  let factorLo = factor .&. mask 32+      factorHi = factor `unsafeShiftR` 32+      bits0 = word32ToWord64 m * factorLo+      bits1 = word32ToWord64 m * factorHi+      total  = (bits0 `unsafeShiftR` 32) + bits1+   in word64ToWord32 $ total `unsafeShiftR` (shift - 32)++-- | Index into the 64-bit word lookup table float_pow5_inv_split+get_float_pow5_inv_split :: Int -> Word64+get_float_pow5_inv_split =+  let !(Addr arr) = float_pow5_inv_split+   in getWord64At arr++-- | Index into the 64-bit word lookup table float_pow5_split+get_float_pow5_split :: Int -> Word64+get_float_pow5_split =+  let !(Addr arr) = float_pow5_split+   in getWord64At arr++-- | Take the high bits of m * 2^k / 5^q / 2^-e2+q+k+mulPow5InvDivPow2 :: Word32 -> Int -> Int -> Word32+mulPow5InvDivPow2 m q j = mulShift32 m (get_float_pow5_inv_split q) j++-- | Take the high bits of m * 5^-e2-q / 2^k / 2^q-k+mulPow5DivPow2 :: Word32 -> Int -> Int -> Word32+mulPow5DivPow2 m i j = mulShift32 m (get_float_pow5_split i) j++-- | Handle case e2 >= 0+f2dGT :: Int32 -> Word32 -> Word32 -> Word32 -> (BoundsState Word32, Int32)+f2dGT e2' u v w =+  let e2 = int32ToInt e2'+      -- q = e10 = log_10(2^e2)+      q = log10pow2 e2+      -- k = B0 + log_2(5^q)+      k = float_pow5_inv_bitcount + pow5bits q - 1+      i = -e2 + q + k+      -- (u, v, w) * 2^k / 5^q / 2^-e2+q+k+      u' = mulPow5InvDivPow2 u q i+      v' = mulPow5InvDivPow2 v q i+      w' = mulPow5InvDivPow2 w q i+      !lastRemoved =+        if q /= 0 && fquot10 (w' - 1) <= fquot10 u'+          -- We need to know one removed digit even if we are not going to loop+          -- below. We could use q = X - 1 above, except that would require 33+          -- bits for the result, and we've found that 32-bit arithmetic is+          -- faster even on 64-bit machines.+          then let l = float_pow5_inv_bitcount + pow5bits (q - 1) - 1+                in frem10 (mulPow5InvDivPow2 v (q - 1) (-e2 + q - 1 + l))+          else 0+      !(vvTrailing, vuTrailing, vw') =+        case () of+          _ | q < 9 && frem5 v == 0+                -> (multipleOfPowerOf5 v q, False, w')+            | q < 9 && acceptBounds v+                -> (False, multipleOfPowerOf5 u q, w')+            | q < 9+                -> (False, False, w' - boolToWord32 (multipleOfPowerOf5 w q))+            | otherwise+                -> (False, False, w')+   in (BoundsState u' v' vw' lastRemoved vuTrailing vvTrailing, intToInt32 q)++-- | Handle case e2 < 0+f2dLT :: Int32 -> Word32 -> Word32 -> Word32 -> (BoundsState Word32, Int32)+f2dLT e2' u v w =+  let e2 = int32ToInt e2'+      q = log10pow5 (-e2)+      e10 = q + e2+      i = (-e2) - q+      -- k = log_2(5^-e2-q) - B1+      k = pow5bits i - float_pow5_bitcount+      j = q - k+      -- (u, v, w) * 5^-e2-q / 2^k / 2^q-k+      u' = mulPow5DivPow2 u i j+      v' = mulPow5DivPow2 v i j+      w' = mulPow5DivPow2 w i j+      !lastRemoved =+        if q /= 0 && fquot10 (w' - 1) <= fquot10 u'+          then let j' = q - 1 - (pow5bits (i + 1) - float_pow5_bitcount)+                in frem10 (mulPow5DivPow2 v (i + 1) j')+          else 0+      !(vvTrailing , vuTrailing, vw') =+        case () of+          _ | q <= 1 && acceptBounds v+                -> (True, v - u == 2, w') -- mmShift == 1+            | q <= 1+                -> (True, False, w' - 1)+            | q < 31+                -> (multipleOfPowerOf2 v (q - 1), False, w')+            | otherwise+                -> (False, False, w')+   in (BoundsState u' v' vw' lastRemoved vuTrailing vvTrailing, intToInt32 e10)++-- | Returns the decimal representation of the given mantissa and exponent of a+-- 32-bit Float using the ryu algorithm.+f2d :: Word32 -> Word32 -> FloatingDecimal+f2d m e =+  let !mf = if e == 0+              then m+              else (1 `unsafeShiftL` float_mantissa_bits) .|. m+      !ef = intToInt32 $ if e == 0+              then 1 - (float_bias + float_mantissa_bits)+              else word32ToInt e - (float_bias + float_mantissa_bits)+      !e2 = ef - 2+      -- Step 2. 3-tuple (u, v, w) * 2**e2+      !u = 4 * mf - 1 - boolToWord32 (m /= 0 || e <= 1)+      !v = 4 * mf+      !w = 4 * mf + 2+      -- Step 3. convert to decimal power base+      !(state, e10) =+        if e2 >= 0+           then f2dGT e2 u v w+           else f2dLT e2 u v w+      -- Step 4: Find the shortest decimal representation in the interval of+      -- valid representations.+      !(output, removed) =+        let rounded = closestCorrectlyRounded (acceptBounds v)+         in first rounded $ if vvIsTrailingZeros state || vuIsTrailingZeros state+           then trimTrailing state+           else trimNoTrailing state+      !e' = e10 + removed+   in FloatingDecimal output e'++-- | Split a Float into (sign, mantissa, exponent)+breakdown :: Float -> (Bool, Word32, Word32)+breakdown f =+  let bits = castFloatToWord32 f+      sign = ((bits `unsafeShiftR` (float_mantissa_bits + float_exponent_bits)) .&. 1) /= 0+      mantissa = bits .&. mask float_mantissa_bits+      expo = (bits `unsafeShiftR` float_mantissa_bits) .&. mask float_exponent_bits+   in (sign, mantissa, expo)++-- | Dispatches to `f2d` and applies the given formatters+{-# INLINE f2s' #-}+f2s' :: (Bool -> Word32 -> Int32 -> a) -> (NonNumbersAndZero -> a) -> Float -> a+f2s' formatter specialFormatter f =+  let (sign, mantissa, expo) = breakdown f+   in if (expo == mask float_exponent_bits) || (expo == 0 && mantissa == 0)+         then specialFormatter NonNumbersAndZero+                  { negative=sign+                  , exponent_all_one=expo > 0+                  , mantissa_non_zero=mantissa > 0 }+         else let FloatingDecimal m e = f2d mantissa expo+               in formatter sign m e++-- | Render a Float in scientific notation+f2s :: Float -> Builder+f2s f = primBounded (f2s' toCharsScientific toCharsNonNumbersAndZero f) ()++-- | Returns the decimal representation of a Float. NaN and Infinity will+-- return `FloatingDecimal 0 0`+f2Intermediate :: Float -> FloatingDecimal+f2Intermediate = f2s' (const FloatingDecimal) (const $ FloatingDecimal 0 0)
+ Data/ByteString/Builder/RealFloat/Internal.hs view
@@ -0,0 +1,905 @@+{-# LANGUAGE ScopedTypeVariables, ExplicitForAll #-}+{-# LANGUAGE BangPatterns, MagicHash, UnboxedTuples #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE RecordWildCards #-}+-- |+-- Module      : Data.ByteString.Builder.RealFloat.Internal+-- Copyright   : (c) Lawrence Wu 2021+-- License     : BSD-style+-- Maintainer  : lawrencejwu@gmail.com+--+-- Various floating-to-string conversion helpers that are somewhat+-- floating-size agnostic+--+-- This module includes+--+-- - Efficient formatting for scientific floating-to-string+-- - Trailing zero handling when converting to decimal power base+-- - Approximations for logarithms of powers+-- - Fast-division by reciprocal multiplication+-- - Prim-op bit-wise peek++module Data.ByteString.Builder.RealFloat.Internal+    ( mask+    , NonNumbersAndZero(..)+    , toCharsNonNumbersAndZero+    , decimalLength9+    , decimalLength17+    , Mantissa+    , pow5bits+    , log10pow2+    , log10pow5+    , pow5_factor+    , multipleOfPowerOf5+    , multipleOfPowerOf2+    , acceptBounds+    , BoundsState(..)+    , trimTrailing+    , trimNoTrailing+    , closestCorrectlyRounded+    , toCharsScientific+    -- hand-rolled division and remainder for f2s and d2s+    , fquot10+    , frem10+    , fquot5+    , frem5+    , dquot10+    , dquotRem10+    , dquot5+    , drem5+    , dquot100+    -- prim-op helpers+    , timesWord2+    , Addr(..)+    , ByteArray(..)+    , castDoubleToWord64+    , castFloatToWord32+    , getWord64At+    , getWord128At+    -- monomorphic conversions+    , boolToWord32+    , boolToWord64+    , int32ToInt+    , intToInt32+    , word32ToInt+    , word64ToInt+    , word32ToWord64+    , word64ToWord32++    , module Data.ByteString.Builder.RealFloat.TableGenerator+    ) where++import Control.Monad (foldM)+import Data.Bits (Bits(..), FiniteBits(..))+import Data.ByteString.Internal (c2w)+import Data.ByteString.Builder.Prim.Internal (BoundedPrim, boundedPrim)+import Data.ByteString.Builder.RealFloat.TableGenerator+import Data.Char (ord)+import GHC.Int (Int(..), Int32(..))+import GHC.Prim+import GHC.Ptr (Ptr(..), plusPtr)+import GHC.ST (ST(..), runST)+import GHC.Types (isTrue#)+import GHC.Word (Word8, Word32(..), Word64(..))+import qualified Foreign.Storable as S (poke)++#include <ghcautoconf.h>+#include "MachDeps.h"++#if WORD_SIZE_IN_BITS < 64 && __GLASGOW_HASKELL__ < 903+import GHC.IntWord64+#endif++#if __GLASGOW_HASKELL__ >= 804+import GHC.Float (castFloatToWord32, castDoubleToWord64)+#else+import System.IO.Unsafe (unsafePerformIO)+import Foreign.Marshal.Utils (with)+import Foreign.Ptr (castPtr)+import Foreign.Storable (peek)++-- | Interpret a 'Float' as a 'Word32' as if through a bit-for-bit copy.+-- (fallback if not available through GHC.Float)+--+-- e.g+--+-- > showHex (castFloatToWord32 1.0) [] = "3f800000"+{-# NOINLINE castFloatToWord32 #-}+castFloatToWord32 :: Float -> Word32+castFloatToWord32 x = unsafePerformIO (with x (peek . castPtr))++-- | Interpret a 'Double' as a 'Word64' as if through a bit-for-bit copy.+-- (fallback if not available through GHC.Float)+--+-- e.g+--+-- > showHex (castDoubleToWord64 1.0) [] = "3ff0000000000000"+{-# NOINLINE castDoubleToWord64 #-}+castDoubleToWord64 :: Double -> Word64+castDoubleToWord64 x = unsafePerformIO (with x (peek . castPtr))+#endif++-- | Build a full bit-mask of specified length.+--+-- e.g+--+-- > showHex (mask 12) [] = "fff"+{-# INLINABLE mask #-}+mask :: (Bits a, Integral a) => Int -> a+mask = flip (-) 1 . unsafeShiftL 1++-- | Convert boolean false to 0 and true to 1+{-# INLINABLE boolToWord32 #-}+boolToWord32 :: Bool -> Word32+boolToWord32 = fromIntegral . fromEnum++-- | Convert boolean false to 0 and true to 1+{-# INLINABLE boolToWord64 #-}+boolToWord64 :: Bool -> Word64+boolToWord64 = fromIntegral . fromEnum++-- | Monomorphic conversion for @Int32 -> Int@+{-# INLINABLE int32ToInt #-}+int32ToInt :: Int32 -> Int+int32ToInt = fromIntegral++-- | Monomorphic conversion for @Int -> Int32@+{-# INLINABLE intToInt32 #-}+intToInt32 :: Int -> Int32+intToInt32 = fromIntegral++-- | Monomorphic conversion for @Word32 -> Int@+{-# INLINABLE word32ToInt #-}+word32ToInt :: Word32 -> Int+word32ToInt = fromIntegral++-- | Monomorphic conversion for @Word64 -> Int@+{-# INLINABLE word64ToInt #-}+word64ToInt :: Word64 -> Int+word64ToInt = fromIntegral++-- | Monomorphic conversion for @Word32 -> Word64@+{-# INLINABLE word32ToWord64 #-}+word32ToWord64 :: Word32 -> Word64+word32ToWord64 = fromIntegral++-- | Monomorphic conversion for @Word64 -> Word32@+{-# INLINABLE word64ToWord32 #-}+word64ToWord32 :: Word64 -> Word32+word64ToWord32 = fromIntegral+++-- | Returns the number of decimal digits in v, which must not contain more than 9 digits.+decimalLength9 :: Word32 -> Int+decimalLength9 v+  | v >= 100000000 = 9+  | v >= 10000000 = 8+  | v >= 1000000 = 7+  | v >= 100000 = 6+  | v >= 10000 = 5+  | v >= 1000 = 4+  | v >= 100 = 3+  | v >= 10 = 2+  | otherwise = 1++-- | Returns the number of decimal digits in v, which must not contain more than 17 digits.+decimalLength17 :: Word64 -> Int+decimalLength17 v+  | v >= 10000000000000000 = 17+  | v >= 1000000000000000 = 16+  | v >= 100000000000000 = 15+  | v >= 10000000000000 = 14+  | v >= 1000000000000 = 13+  | v >= 100000000000 = 12+  | v >= 10000000000 = 11+  | v >= 1000000000 = 10+  | v >= 100000000 = 9+  | v >= 10000000 = 8+  | v >= 1000000 = 7+  | v >= 100000 = 6+  | v >= 10000 = 5+  | v >= 1000 = 4+  | v >= 100 = 3+  | v >= 10 = 2+  | otherwise = 1++-- From 'In-and-Out Conversions' https://dl.acm.org/citation.cfm?id=362887, we+-- have that a conversion from a base-b n-digit number to a base-v m-digit+-- number such that the round-trip conversion is identity requires+--+--    v^(m-1) > b^n+--+-- Specifically for binary floating point to decimal conversion, we must have+--+--    10^(m-1) > 2^n+-- => log(10^(m-1)) > log(2^n)+-- => (m-1) * log(10) > n * log(2)+-- => m-1 > n * log(2) / log(10)+-- => m-1 >= ceil(n * log(2) / log(10))+-- => m >= ceil(n * log(2) / log(10)) + 1+--+-- And since 32 and 64-bit floats have 23 and 52 bits of mantissa (and then an+-- implicit leading-bit), we need+--+--    ceil(24 * log(2) / log(10)) + 1 => 9+--    ceil(53 * log(2) / log(10)) + 1 => 17+--+-- In addition, the exponent range from floats is [-45,38] and doubles is+-- [-324,308] (including subnormals) which are 3 and 4 digits respectively+--+-- Thus we have,+--+--    floats: 1 (sign) + 9 (mantissa) + 1 (.) + 1 (e) + 3 (exponent) = 15+--    doubles: 1 (sign) + 17 (mantissa) + 1 (.) + 1 (e) + 4 (exponent) = 24+--+maxEncodedLength :: Int+maxEncodedLength = 32++-- | Storable.poke a String into a Ptr Word8, converting through c2w+pokeAll :: String -> Ptr Word8 -> IO (Ptr Word8)+pokeAll s ptr = foldM pokeOne ptr s+  where pokeOne p c = S.poke p (c2w c) >> return (p `plusPtr` 1)++-- | Unsafe creation of a bounded primitive of String at most length+-- `maxEncodedLength`+boundString :: String -> BoundedPrim ()+boundString s = boundedPrim maxEncodedLength $ const (pokeAll s)++-- | Special rendering for NaN, positive\/negative 0, and positive\/negative+-- infinity. These are based on the IEEE representation of non-numbers.+--+-- Infinity+--+--   * sign = 0 for positive infinity, 1 for negative infinity.+--   * biased exponent = all 1 bits.+--   * fraction = all 0 bits.+--+-- NaN+--+--   * sign = either 0 or 1 (ignored)+--   * biased exponent = all 1 bits.+--   * fraction = anything except all 0 bits.+--+-- We also handle 0 specially here so that the exponent rendering is more+-- correct.+--+--   * sign = either 0 or 1.+--   * biased exponent = all 0 bits.+--   * fraction = all 0 bits.+data NonNumbersAndZero = NonNumbersAndZero+  { negative :: Bool+  , exponent_all_one :: Bool+  , mantissa_non_zero :: Bool+  }++-- | Renders NonNumbersAndZero into bounded primitive+toCharsNonNumbersAndZero :: NonNumbersAndZero -> BoundedPrim ()+toCharsNonNumbersAndZero NonNumbersAndZero{..}+  | mantissa_non_zero = boundString "NaN"+  | exponent_all_one = boundString $ signStr ++ "Infinity"+  | otherwise = boundString $ signStr ++ "0.0e0"+  where signStr = if negative then "-" else ""++-- | Part of the calculation on whether to round up the decimal representation.+-- This is currently a constant function to match behavior in Base `show` and+-- is implemented as+--+-- @+-- acceptBounds _ = False+-- @+--+-- For round-to-even and correct shortest, use+--+-- @+-- acceptBounds v = ((v \`quot\` 4) .&. 1) == 0+-- @+acceptBounds :: Mantissa a => a -> Bool+acceptBounds _ = False++-------------------------------------------------------------------------------+-- Logarithm Approximations+--+-- These are based on the same transformations.+--+-- e.g+--+--      log_2(5^e)                              goal function+--    = e * log_2(5)                            log exponenation+--   ~= e * floor(10^7 * log_2(5)) / 10^7       integer operations+--   ~= e * 1217359 / 2^19                      approximation into n / 2^m+--+-- These are verified in the unit tests for the given input ranges+-------------------------------------------------------------------------------++-- | Returns e == 0 ? 1 : ceil(log_2(5^e)); requires 0 <= e <= 3528.+pow5bitsUnboxed :: Int# -> Int#+pow5bitsUnboxed e = (e *# 1217359#) `uncheckedIShiftRL#` 19# +# 1#++-- | Returns floor(log_10(2^e)); requires 0 <= e <= 1650.+log10pow2Unboxed :: Int# -> Int#+log10pow2Unboxed e = (e *# 78913#) `uncheckedIShiftRL#` 18#++-- | Returns floor(log_10(5^e)); requires 0 <= e <= 2620.+log10pow5Unboxed :: Int# -> Int#+log10pow5Unboxed e = (e *# 732923#) `uncheckedIShiftRL#` 20#++-- | Boxed versions of the functions above+pow5bits, log10pow2, log10pow5 :: Int -> Int+pow5bits  = wrapped pow5bitsUnboxed+log10pow2 = wrapped log10pow2Unboxed+log10pow5 = wrapped log10pow5Unboxed++-------------------------------------------------------------------------------+-- Fast Division+--+-- Division is slow. We leverage fixed-point arithmetic to calculate division+-- by a constant as multiplication by the inverse. This could potentially be+-- handled by an aggressive compiler, but to ensure that the optimization+-- happens, we hard-code the expected divisions / remainders by 5, 10, 100, etc+--+-- e.g+--+--     x / 5                                      goal function+--   = x * (1 / 5)                                reciprocal+--   = x * (4 / 5) / 4+--   = x * 0b0.110011001100.. / 4                 recurring binary representation+--  ~= x * (0xCCCCCCCD / 2^32) / 4                approximation with integers+--   = (x * 0xCCCCCCCD) >> 34+--+-- Look for `Reciprocal Multiplication, a tutorial` by Douglas W. Jones for a+-- more detailed explanation.+-------------------------------------------------------------------------------++-- | Returns @w / 10@+fquot10 :: Word32 -> Word32+fquot10 w = word64ToWord32 ((word32ToWord64 w * 0xCCCCCCCD) `unsafeShiftR` 35)++-- | Returns @w % 10@+frem10 :: Word32 -> Word32+frem10 w = w - fquot10 w * 10++-- | Returns @(w / 10, w % 10)@+fquotRem10 :: Word32 -> (Word32, Word32)+fquotRem10 w =+  let w' = fquot10 w+   in (w', w - fquot10 w * 10)++-- | Returns @w / 100@+fquot100 :: Word32 -> Word32+fquot100 w = word64ToWord32 ((word32ToWord64 w * 0x51EB851F) `unsafeShiftR` 37)++-- | Returns @(w / 10000, w % 10000)@+fquotRem10000 :: Word32 -> (Word32, Word32)+fquotRem10000 w =+  let w' = word64ToWord32 ((word32ToWord64 w * 0xD1B71759) `unsafeShiftR` 45)+    in (w', w - w' * 10000)++-- | Returns @w / 5@+fquot5 :: Word32 -> Word32+fquot5 w = word64ToWord32 ((word32ToWord64 w * 0xCCCCCCCD) `unsafeShiftR` 34)++-- | Returns @w % 5@+frem5 :: Word32 -> Word32+frem5 w = w - fquot5 w * 5++-- | Returns @w / 10@+dquot10 :: Word64 -> Word64+dquot10 w =+  let !(rdx, _) = w `timesWord2` 0xCCCCCCCCCCCCCCCD+    in rdx `unsafeShiftR` 3++-- | Returns @w / 100@+dquot100 :: Word64 -> Word64+dquot100 w =+  let !(rdx, _) = (w `unsafeShiftR` 2) `timesWord2` 0x28F5C28F5C28F5C3+    in rdx `unsafeShiftR` 2++-- | Returns @(w / 10000, w % 10000)@+dquotRem10000 :: Word64 -> (Word64, Word64)+dquotRem10000 w =+  let !(rdx, _) = w `timesWord2` 0x346DC5D63886594B+      w' = rdx `unsafeShiftR` 11+   in (w', w - w' * 10000)++-- | Returns @(w / 10, w % 10)@+dquotRem10 :: Word64 -> (Word64, Word64)+dquotRem10 w =+  let w' = dquot10 w+   in (w', w - w' * 10)++-- | Returns @w / 5@+dquot5 :: Word64 -> Word64+dquot5 w =+  let !(rdx, _) = w `timesWord2` 0xCCCCCCCCCCCCCCCD+    in rdx `unsafeShiftR` 2++-- | Returns @w % 5@+drem5 :: Word64 -> Word64+drem5 w = w - dquot5 w * 5++-- | Returns @(w / 5, w % 5)@+dquotRem5 :: Word64 -> (Word64, Word64)+dquotRem5 w =+  let w' = dquot5 w+   in (w', w - w' * 5)++-- | Wrap a unboxed function on Int# into the boxed equivalent+wrapped :: (Int# -> Int#) -> Int -> Int+wrapped f (I# w) = I# (f w)++#if WORD_SIZE_IN_BITS == 32+-- | Packs 2 32-bit system words (hi, lo) into a Word64+packWord64 :: Word# -> Word# -> Word64#+packWord64 hi lo =+#if defined(WORDS_BIGENDIAN)+    ((wordToWord64# lo) `uncheckedShiftL64#` 32#) `or64#` (wordToWord64# hi)+#else+    ((wordToWord64# hi) `uncheckedShiftL64#` 32#) `or64#` (wordToWord64# lo)+#endif++-- | Unpacks a Word64 into 2 32-bit words (hi, lo)+unpackWord64 :: Word64# -> (# Word#, Word# #)+unpackWord64 w =+#if defined(WORDS_BIGENDIAN)+    (# word64ToWord# w+     , word64ToWord# (w `uncheckedShiftRL64#` 32#)+     #)+#else+    (# word64ToWord# (w `uncheckedShiftRL64#` 32#)+     , word64ToWord# w+     #)+#endif++-- | Adds 2 Word64's with 32-bit addition and manual carrying+plusWord64 :: Word64# -> Word64# -> Word64#+plusWord64 x y =+  let !(# x_h, x_l #) = unpackWord64 x+      !(# y_h, y_l #) = unpackWord64 y+      lo = x_l `plusWord#` y_l+      carry = int2Word# (lo `ltWord#` x_l)+      hi = x_h `plusWord#` y_h `plusWord#` carry+   in packWord64 hi lo+#endif++-- | Boxed version of `timesWord2#` for 64 bits+timesWord2 :: Word64 -> Word64 -> (Word64, Word64)+timesWord2 a b =+  let ra = raw a+      rb = raw b+#if WORD_SIZE_IN_BITS >= 64+#if __GLASGOW_HASKELL__ < 903+      !(# hi, lo #) = ra `timesWord2#` rb+#else+      !(# hi_, lo_ #) = word64ToWord# ra `timesWord2#` word64ToWord# rb+      hi = wordToWord64# hi_+      lo = wordToWord64# lo_+#endif+#else+      !(# x_h, x_l #) = unpackWord64 ra+      !(# y_h, y_l #) = unpackWord64 rb++      !(# phh_h, phh_l #) = x_h `timesWord2#` y_h+      !(# phl_h, phl_l #) = x_h `timesWord2#` y_l+      !(# plh_h, plh_l #) = x_l `timesWord2#` y_h+      !(# pll_h, pll_l #) = x_l `timesWord2#` y_l++      --          x1 x0+      --  X       y1 y0+      --  -------------+      --             00  LOW PART+      --  -------------+      --          00+      --       10 10     MIDDLE PART+      --  +       01+      --  -------------+      --       01+      --  + 11 11        HIGH PART+      --  -------------++      phh = packWord64 phh_h phh_l+      phl = packWord64 phl_h phl_l++      !(# mh, ml #) = unpackWord64 (phl+        `plusWord64` (wordToWord64# pll_h)+        `plusWord64` (wordToWord64# plh_l))++      hi = phh+        `plusWord64` (wordToWord64# mh)+        `plusWord64` (wordToWord64# plh_h)++      lo = packWord64 ml pll_l+#endif+   in (W64# hi, W64# lo)++-- | #ifdef for 64-bit word that seems to work on both 32- and 64-bit platforms+type WORD64 =+#if WORD_SIZE_IN_BITS < 64 || __GLASGOW_HASKELL__ >= 903+  Word64#+#else+  Word#+#endif++-- | Returns the number of times @w@ is divisible by @5@+pow5_factor :: WORD64 -> Int# -> Int#+pow5_factor w count =+  let !(W64# q, W64# r) = dquotRem5 (W64# w)+#if WORD_SIZE_IN_BITS >= 64 && __GLASGOW_HASKELL__ < 903+   in case r `eqWord#` 0## of+#else+   in case r `eqWord64#` wordToWord64# 0## of+#endif+        0# -> count+        _  -> pow5_factor q (count +# 1#)++-- | Returns @True@ if value is divisible by @5^p@+multipleOfPowerOf5 :: Mantissa a => a -> Int -> Bool+multipleOfPowerOf5 value (I# p) = isTrue# (pow5_factor (raw value) 0# >=# p)++-- | Returns @True@ if value is divisible by @2^p@+multipleOfPowerOf2 :: Mantissa a => a -> Int -> Bool+multipleOfPowerOf2 value p = (value .&. mask p) == 0++-- | Wrapper for polymorphic handling of 32- and 64-bit floats+class (FiniteBits a, Integral a) => Mantissa a where+  -- NB: might truncate!+  -- Use this when we know the value fits in 32-bits+  unsafeRaw :: a -> Word#+  raw :: a -> WORD64++  decimalLength :: a -> Int+  boolToWord :: Bool -> a+  quotRem10 :: a -> (a, a)+  quot10  :: a -> a+  quot100 :: a -> a+  quotRem100 :: a -> (a, a)+  quotRem10000 :: a -> (a, a)++instance Mantissa Word32 where+#if __GLASGOW_HASKELL__ >= 902+  unsafeRaw (W32# w) = word32ToWord# w+#else+  unsafeRaw (W32# w) = w+#endif+#if WORD_SIZE_IN_BITS >= 64 && __GLASGOW_HASKELL__ < 903+  raw = unsafeRaw+#else+  raw w = wordToWord64# (unsafeRaw w)+#endif++  decimalLength = decimalLength9+  boolToWord = boolToWord32++  {-# INLINE quotRem10 #-}+  quotRem10 = fquotRem10++  {-# INLINE quot10 #-}+  quot10 = fquot10++  {-# INLINE quot100 #-}+  quot100 = fquot100++  quotRem100 w =+    let w' = fquot100 w+      in (w', (w - w' * 100))++  quotRem10000 = fquotRem10000++instance Mantissa Word64 where+#if WORD_SIZE_IN_BITS >= 64 && __GLASGOW_HASKELL__ < 903+  unsafeRaw (W64# w) = w+#else+  unsafeRaw (W64# w) = word64ToWord# w+#endif+  raw (W64# w) = w++  decimalLength = decimalLength17+  boolToWord = boolToWord64++  {-# INLINE quotRem10 #-}+  quotRem10 = dquotRem10++  {-# INLINE quot10 #-}+  quot10 = dquot10++  {-# INLINE quot100 #-}+  quot100 = dquot100++  quotRem100 w =+    let w' = dquot100 w+     in (w', (w - w' * 100))++  quotRem10000 = dquotRem10000++-- | Bookkeeping state for finding the shortest, correctly-rounded+-- representation. The same trimming algorithm is similar enough for 32- and+-- 64-bit floats+data BoundsState a = BoundsState+    { vu :: !a+    , vv :: !a+    , vw :: !a+    , lastRemovedDigit :: !a+    , vuIsTrailingZeros :: !Bool+    , vvIsTrailingZeros :: !Bool+    }++-- | Trim digits and update bookkeeping state when the table-computed+-- step results in trailing zeros (the general case, happens rarely)+--+-- NB: This function isn't actually necessary so long as acceptBounds is always+-- @False@ since we don't do anything different with the trailing-zero+-- information directly:+-- - vuIsTrailingZeros is always False.  We can see this by noting that in all+--   places where vuTrailing can possible be True, we must have acceptBounds be+--   True (accept_smaller)+-- - The final result doesn't change the lastRemovedDigit for rounding anyway+trimTrailing :: (Show a, Mantissa a) => BoundsState a -> (BoundsState a, Int32)+trimTrailing !initial = (res, r + r')+  where+    !(d', r) = trimTrailing' initial+    !(d'', r') = if vuIsTrailingZeros d' then trimTrailing'' d' else (d', 0)+    res = if vvIsTrailingZeros d'' && lastRemovedDigit d'' == 5 && vv d'' `rem` 2 == 0+             -- set `{ lastRemovedDigit = 4 }` to round-even+             then d''+             else d''++    trimTrailing' !d+      | vw' > vu' =+         fmap ((+) 1) . trimTrailing' $+          d { vu = vu'+            , vv = vv'+            , vw = vw'+            , lastRemovedDigit = vvRem+            , vuIsTrailingZeros = vuIsTrailingZeros d && vuRem == 0+            , vvIsTrailingZeros = vvIsTrailingZeros d && lastRemovedDigit d == 0+            }+      | otherwise = (d, 0)+      where+        !(vv', vvRem) = quotRem10 $ vv d+        !(vu', vuRem) = quotRem10 $ vu d+        !(vw', _    ) = quotRem10 $ vw d++    trimTrailing'' !d+      | vuRem == 0 =+         fmap ((+) 1) . trimTrailing'' $+          d { vu = vu'+            , vv = vv'+            , vw = vw'+            , lastRemovedDigit = vvRem+            , vvIsTrailingZeros = vvIsTrailingZeros d && lastRemovedDigit d == 0+            }+      | otherwise = (d, 0)+      where+        !(vu', vuRem) = quotRem10 $ vu d+        !(vv', vvRem) = quotRem10 $ vv d+        !(vw', _    ) = quotRem10 $ vw d+++-- | Trim digits and update bookkeeping state when the table-computed+-- step results has no trailing zeros (common case)+trimNoTrailing :: Mantissa a => BoundsState a -> (BoundsState a, Int32)+trimNoTrailing !(BoundsState u v w ld _ _) =+  (BoundsState ru' rv' 0 ld' False False, c)+  where+    !(ru', rv', ld', c) = trimNoTrailing' u v w ld 0++    trimNoTrailing' u' v' w' lastRemoved count+      -- Loop iterations below (approximately), without div 100 optimization:+      -- 0: 0.03%, 1: 13.8%, 2: 70.6%, 3: 14.0%, 4: 1.40%, 5: 0.14%, 6+: 0.02%+      -- Loop iterations below (approximately), with div 100 optimization:+      -- 0: 70.6%, 1: 27.8%, 2: 1.40%, 3: 0.14%, 4+: 0.02%+      | vw' > vu' =+          trimNoTrailing'' vu' vv' vw' (quot10 (v' - (vv' * 100))) (count + 2)+      | otherwise =+          trimNoTrailing'' u' v' w' lastRemoved count+      where+        !vw' = quot100 w'+        !vu' = quot100 u'+        !vv' = quot100 v'++    trimNoTrailing'' u' v' w' lastRemoved count+      | vw' > vu' = trimNoTrailing' vu' vv' vw' lastRemoved' (count + 1)+      | otherwise = (u', v', lastRemoved, count)+      where+        !(vv', lastRemoved') = quotRem10 v'+        !vu' = quot10 u'+        !vw' = quot10 w'++-- | Returns the correctly rounded decimal representation mantissa based on if+-- we need to round up (next decimal place >= 5) or if we are outside the+-- bounds+{-# INLINE closestCorrectlyRounded #-}+closestCorrectlyRounded :: Mantissa a => Bool -> BoundsState a -> a+closestCorrectlyRounded acceptBound s = vv s + boolToWord roundUp+  where+    outsideBounds = not (vuIsTrailingZeros s) || not acceptBound+    roundUp = (vv s == vu s && outsideBounds) || lastRemovedDigit s >= 5++-- Wrappe around int2Word#+asciiRaw :: Int -> Word#+asciiRaw (I# i) = int2Word# i++asciiZero :: Int+asciiZero = ord '0'++asciiDot :: Int+asciiDot = ord '.'++asciiMinus :: Int+asciiMinus = ord '-'++ascii_e :: Int+ascii_e = ord 'e'++-- | Convert a single-digit number to the ascii ordinal e.g '1' -> 0x31+toAscii :: Word# -> Word#+toAscii a = a `plusWord#` asciiRaw asciiZero++data Addr = Addr Addr#++-- | Index into the 64-bit word lookup table provided+{-# INLINE getWord64At #-}+getWord64At :: Addr# -> Int -> Word64+getWord64At arr (I# i) =+#if defined(WORDS_BIGENDIAN)+   W64# (byteSwap64# (indexWord64OffAddr# arr i))+#else+   W64# (indexWord64OffAddr# arr i)+#endif++-- | Index into the 128-bit word lookup table provided+-- Return (# high-64-bits , low-64-bits #)+-- NB: really just swaps the bytes and doesn't reorder the words+{-# INLINE getWord128At #-}+getWord128At :: Addr# -> Int -> (Word64, Word64)+getWord128At arr (I# i) =+#if defined(WORDS_BIGENDIAN)+   ( W64# (byteSwap64# (indexWord64OffAddr# arr (i *# 2# +# 1#)))+   , W64# (byteSwap64# (indexWord64OffAddr# arr (i *# 2#)))+   )+#else+   ( W64# (indexWord64OffAddr# arr (i *# 2# +# 1#))+   , W64# (indexWord64OffAddr# arr (i *# 2#))+   )+#endif+++data ByteArray = ByteArray ByteArray#++-- | Packs 2 bytes [lsb, msb] into 16-bit word+packWord16 :: Word# -> Word# -> Word#+packWord16 l h =+#if defined(WORDS_BIGENDIAN)+    (h `uncheckedShiftL#` 8#) `or#` l+#else+    (l `uncheckedShiftL#` 8#) `or#` h+#endif++-- | Unpacks a 16-bit word into 2 bytes [lsb, msb]+unpackWord16 :: Word# -> (# Word#, Word# #)+unpackWord16 w =+#if defined(WORDS_BIGENDIAN)+    (# w `and#` 0xff##, w `uncheckedShiftRL#` 8# #)+#else+    (# w `uncheckedShiftRL#` 8#, w `and#` 0xff## #)+#endif+++-- | ByteArray of 2-digit pairs 00..99 for faster ascii rendering+digit_table :: ByteArray+digit_table = runST (ST $ \s1 ->+  let !(# s2, marr #) = newByteArray# 200# s1+      go y r = \i s ->+        let !(h, l) = fquotRem10 y+            e' = packWord16 (toAscii (unsafeRaw l)) (toAscii (unsafeRaw h))+#if __GLASGOW_HASKELL__ >= 902+            s' = writeWord16Array# marr i (wordToWord16# e') s+#else+            s' = writeWord16Array# marr i e' s+#endif+         in if isTrue# (i ==# 99#) then s' else r (i +# 1#) s'+      !(# s3, bs #) = unsafeFreezeByteArray# marr (foldr go (\_ s -> s) [0..99] 0# s2)+   in (# s3, ByteArray bs #))++-- | Unsafe index a ByteArray for the 16-bit word at the index+unsafeAt :: ByteArray -> Int# -> Word#+unsafeAt (ByteArray bs) i =+#if __GLASGOW_HASKELL__ >= 902+    word16ToWord# (indexWord16Array# bs i)+#else+    indexWord16Array# bs i+#endif++-- | Write a 16-bit word into the given address+copyWord16 :: Word# -> Addr# -> State# d -> State# d+copyWord16 w a s =+#if __GLASGOW_HASKELL__ >= 902+    writeWord16OffAddr# a 0# (wordToWord16# w) s+#else+    writeWord16OffAddr# a 0# w s+#endif++-- | Write an 8-bit word into the given address+poke :: Addr# -> Word# -> State# d -> State# d+poke a w s =+#if __GLASGOW_HASKELL__ >= 902+    writeWord8OffAddr# a 0# (wordToWord8# w) s+#else+    writeWord8OffAddr# a 0# w s+#endif++-- | Write the mantissa into the given address. This function attempts to+-- optimize this by writing pairs of digits simultaneously when the mantissa is+-- large enough+{-# SPECIALIZE writeMantissa :: Addr# -> Int# -> Word32 -> State# d -> (# Addr#, State# d #) #-}+{-# SPECIALIZE writeMantissa :: Addr# -> Int# -> Word64 -> State# d -> (# Addr#, State# d #) #-}+writeMantissa :: forall a d. (Mantissa a) => Addr# -> Int# -> a -> State# d -> (# Addr#, State# d #)+writeMantissa ptr olength = go (ptr `plusAddr#` olength)+  where+    go p mantissa s1+      | mantissa >= 10000 =+          let !(m', c) = quotRem10000 mantissa+              !(c1, c0) = quotRem100 c+              s2 = copyWord16 (digit_table `unsafeAt` word2Int# (unsafeRaw c0)) (p `plusAddr#` (-1#)) s1+              s3 = copyWord16 (digit_table `unsafeAt` word2Int# (unsafeRaw c1)) (p `plusAddr#` (-3#)) s2+           in go (p `plusAddr#` (-4#)) m' s3+      | mantissa >= 100 =+          let !(m', c) = quotRem100 mantissa+              s2 = copyWord16 (digit_table `unsafeAt` word2Int# (unsafeRaw c)) (p `plusAddr#` (-1#)) s1+           in finalize m' s2+      | otherwise = finalize mantissa s1+    finalize mantissa s1+      | mantissa >= 10 =+        let !bs = digit_table `unsafeAt` word2Int# (unsafeRaw mantissa)+            !(# lsb, msb #) = unpackWord16 bs+            s2 = poke (ptr `plusAddr#` 2#) lsb s1+            s3 = poke (ptr `plusAddr#` 1#) (asciiRaw asciiDot) s2+            s4 = poke ptr msb s3+           in (# ptr `plusAddr#` (olength +# 1#), s4 #)+      | (I# olength) > 1 =+          let s2 = copyWord16 (packWord16 (asciiRaw asciiDot) (toAscii (unsafeRaw mantissa))) ptr s1+           in (# ptr `plusAddr#` (olength +# 1#), s2 #)+      | otherwise =+          let s2 = poke (ptr `plusAddr#` 2#) (asciiRaw asciiZero) s1+              s3 = poke (ptr `plusAddr#` 1#) (asciiRaw asciiDot) s2+              s4 = poke ptr (toAscii (unsafeRaw mantissa)) s3+           in (# ptr `plusAddr#` 3#, s4 #)++-- | Write the exponent into the given address.+writeExponent :: Addr# -> Int32 -> State# d -> (# Addr#, State# d #)+writeExponent ptr !expo s1+  | expo >= 100 =+      let !(e1, e0) = fquotRem10 (fromIntegral expo) -- TODO+          s2 = copyWord16 (digit_table `unsafeAt` word2Int# (unsafeRaw e1)) ptr s1+          s3 = poke (ptr `plusAddr#` 2#) (toAscii (unsafeRaw e0)) s2+       in (# ptr `plusAddr#` 3#, s3 #)+  | expo >= 10 =+      let s2 = copyWord16 (digit_table `unsafeAt` e) ptr s1+       in (# ptr `plusAddr#` 2#, s2 #)+  | otherwise =+      let s2 = poke ptr (toAscii (int2Word# e)) s1+       in (# ptr `plusAddr#` 1#, s2 #)+  where !(I# e) = int32ToInt expo++-- | Write the sign into the given address.+writeSign :: Addr# -> Bool -> State# d -> (# Addr#, State# d #)+writeSign ptr True s1 =+  let s2 = poke ptr (asciiRaw asciiMinus) s1+   in (# ptr `plusAddr#` 1#, s2 #)+writeSign ptr False s = (# ptr, s #)++-- | Returns the decimal representation of a floating point number in+-- scientific (exponential) notation+{-# INLINABLE toCharsScientific #-}+{-# SPECIALIZE toCharsScientific :: Bool -> Word32 -> Int32 -> BoundedPrim () #-}+{-# SPECIALIZE toCharsScientific :: Bool -> Word64 -> Int32 -> BoundedPrim () #-}+toCharsScientific :: (Mantissa a) => Bool -> a -> Int32 -> BoundedPrim ()+toCharsScientific !sign !mantissa !expo = boundedPrim maxEncodedLength $ \_ !(Ptr p0)-> do+  let !olength@(I# ol) = decimalLength mantissa+      !expo' = expo + intToInt32 olength - 1+  return $ runST (ST $ \s1 ->+    let !(# p1, s2 #) = writeSign p0 sign s1+        !(# p2, s3 #) = writeMantissa p1 ol mantissa s2+        s4 = poke p2 (asciiRaw ascii_e) s3+        !(# p3, s5 #) = writeSign (p2 `plusAddr#` 1#) (expo' < 0) s4+        !(# p4, s6 #) = writeExponent p3 (abs expo') s5+     in (# s6, (Ptr p4) #))
+ Data/ByteString/Builder/RealFloat/TableGenerator.hs view
@@ -0,0 +1,185 @@+{-# LANGUAGE ExplicitForAll #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE BangPatterns, MagicHash, UnboxedTuples #-}+-- |+-- Module      : Data.ByteString.Builder.RealFloat.TableGenerator+-- Copyright   : (c) Lawrence Wu 2021+-- License     : BSD-style+-- Maintainer  : lawrencejwu@gmail.com+--+-- Constants and overview for compile-time table generation for Ryu internals+--+-- This module uses Haskell's arbitrary-precision `Integer` types to compute+-- the necessary multipliers for efficient conversion to a decimal power base.+--+-- It also exposes constants relevant to the 32- and 64-bit tables (e.g maximum+-- number of bits required to store the table values).++module Data.ByteString.Builder.RealFloat.TableGenerator+  ( float_pow5_inv_bitcount+  , float_pow5_bitcount+  , double_pow5_bitcount+  , double_pow5_inv_bitcount+  , float_max_split+  , float_max_inv_split+  , double_max_split+  , double_max_inv_split+  ) where++import GHC.Float (int2Double)+++-- The basic floating point conversion algorithm is as such:+--+-- Given floating point+--+--   f = (-1)^s * m_f * 2^e_f+--+-- which is IEEE encoded by `[s] [.. e ..] [.. m ..]`. `s` is the sign bit, `e`+-- is the biased exponent, and `m` is the mantissa, let+--+--       | e /= 0            | e == 0+--  -----+-------------------+-----------+--   m_f | 2^len(m) + m      | m+--   e_f | e - bias - len(m) | 1 - bias - len(m)+--+-- we compute the halfway points to the next smaller (`f-`) and larger (`f+`)+-- floating point numbers as+--+--  lower halfway point u * 2^e2, u = 4 * m_f - (if m == 0 then 1 else 2)+--                      v * 2^e2, v = 4 * m_f+--  upper halfway point w * 2^e2, u = 4 * m_f + 2+--  where e2 = ef - 2 (so u, v, w are integers)+--+--+-- Then we compute (a, b, c) * 10^e10 = (u, v, w) * 2^e2 which is split into+-- the case of+--+--   e2 >= 0   ==>    e10 = 0 , (a, b, c) = (u, v, w) * 2^e2+--   e2 <  0   ==>    e10 = e2, (a, b, c) = (u, v, w) * 5^-e2+--+-- And finally we find the shortest representation from integers d0 and e0 such+-- that+--+--  a * 10^e10 < d0 * 10^(e0+e10) < c * 10^e10+--+-- such that e0 is maximal (we allow equality to smaller or larger halfway+-- point depending on rounding mode). This is found through iteratively+-- dividing by 10 while a/10^j < c/10^j and doing some bookkeeping around+-- zeros.+--+--+--+--+-- The ryu algorithm removes the requirement for arbitrary precision arithmetic+-- and improves the runtime significantly by skipping most of the iterative+-- division by carefully selecting a point where certain invariants hold and+-- precomputing a few tables.+--+-- Specifically, define `q` such that the correspondings values of a/10^q <+-- c/10^q - 1. We can prove (not shown) that+--+--    if e2 >= 0, q = e2 * log_10(2)+--    if e2 <  0, q = -e2 * log_10(5)+--+-- Then we can compute (a, b, c) / 10^q. Starting from (u, v, w) we have+--+--      (a, b, c) / 10^q                  (a, b, c) / 10^q+--    = (u, v, w) * 2^e2 / 10^q    OR   = (u, v, w) * 5^-e2 / 10^q+--+-- And since q < e2,+--+--    = (u, v, w) * 2^e2-q / 5^q   OR   = (u, v, w) * 5^-e2-q / 2^q+--+-- While (u, v, w) are n-bit numbers, 5^q and whatnot are significantly larger,+-- but we only need the top-most n bits of the result so we can choose `k` that+-- reduce the number of bits required to ~2n. We then multiply by either+--+--    2^k / 5^q                    OR   5^-e2-q / 2^k+--+-- The required `k` is roughly linear in the exponent (we need more of the+-- multiplication to be precise) but the number of bits to store the+-- multiplicands above stays fixed.+--+-- Since the number of bits needed is relatively small for IEEE 32- and 64-bit+-- floating types, we can compute appropriate values for `k` for the+-- floating-point-type-specific bounds instead of each e2.+--+-- Finally, we need to do some final manual iterations potentially to do a+-- final fixup of the skipped state+++-- | Bound for bits of @2^k / 5^q@ for floats+float_pow5_inv_bitcount :: Int+float_pow5_inv_bitcount = 59++-- | Bound for bits of @5^-e2-q / 2^k@ for floats+float_pow5_bitcount :: Int+float_pow5_bitcount = 61++-- | Bound for bits of @5^-e2-q / 2^k@ for doubles+double_pow5_bitcount :: Int+double_pow5_bitcount = 125++-- | Bound for bits of @2^k / 5^q@ for doubles+double_pow5_inv_bitcount :: Int+double_pow5_inv_bitcount = 125++-- NB: these tables are encoded directly into the source code in F2S and D2S+--+-- -- | Number of bits in a positive integer+-- blen :: Integer -> Int+-- blen 0 = 0+-- blen 1 = 1+-- blen n = 1 + blen (n `quot` 2)++-- -- | Used for table generation of 2^k / 5^q + 1+-- finv :: Int -> Int -> Integer+-- finv bitcount i =+--   let p = 5^i+--    in (1 `shiftL` (blen p - 1 + bitcount)) `div` p + 1++-- -- | Used for table generation of 5^-e2-q / 2^k+-- fnorm :: Int -> Int -> Integer+-- fnorm bitcount i =+--   let p = 5^i+--       s = blen p - bitcount+--    in if s < 0 then p `shiftL` (-s) else p `shiftR` s++-- -- | Generates a compile-time lookup table for floats as Word64+-- gen_table_f :: Int -> (Int -> Integer) -> Q Exp+-- gen_table_f n f = return $ ListE (fmap (LitE . IntegerL . f) [0..n])+--+-- -- | Generates a compile-time lookup table for doubles as Word128+-- gen_table_d :: Int -> (Int -> Integer) -> Q Exp+-- gen_table_d n f = return $ ListE (fmap ff [0..n])+--   where+--     ff :: Int -> Exp+--     ff c = let r = f c+--                hi = r `shiftR` 64+--                lo = r .&. ((1 `shiftL` 64) - 1)+--             in AppE (AppE (ConE 'Word128) (LitE . IntegerL $ hi)) (LitE . IntegerL $ lo)++-- Given a specific floating-point type, determine the range of q for the < 0+-- and >= 0 cases+get_range :: forall ff. (RealFloat ff) => ff -> (Int, Int)+get_range f =+  let (emin, emax) = floatRange f+      mantissaDigits = floatDigits f+      emin' = emin - mantissaDigits - 2+      emax' = emax - mantissaDigits - 2+   in ( (-emin') - floor (int2Double (-emin') * logBase 10 5)+      , floor (int2Double emax' * logBase 10 2))++float_max_split :: Int     -- = 46+float_max_inv_split :: Int -- = 30+(float_max_split, float_max_inv_split) = get_range (undefined :: Float)++-- we take a slightly different codepath s.t we need one extra entry+double_max_split :: Int     -- = 325+double_max_inv_split :: Int -- = 291+(double_max_split, double_max_inv_split) =+    let (m, mi) = get_range (undefined :: Double)+     in (m + 1, mi)+
Data/ByteString/Char8.hs view
@@ -1,8 +1,7 @@-{-# LANGUAGE CPP, BangPatterns #-}+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE MagicHash #-} {-# OPTIONS_HADDOCK prune #-}-#if __GLASGOW_HASKELL__ >= 701 {-# LANGUAGE Trustworthy #-}-#endif  -- | -- Module      : Data.ByteString.Char8@@ -44,162 +43,162 @@ module Data.ByteString.Char8 (          -- * The @ByteString@ type-        ByteString,             -- abstract, instances: Eq, Ord, Show, Read, Data, Typeable, Monoid+        ByteString,          -- * Introducing and eliminating 'ByteString's-        empty,                  -- :: ByteString-        singleton,              -- :: Char   -> ByteString-        pack,                   -- :: String -> ByteString-        unpack,                 -- :: ByteString -> String-        B.fromStrict,           -- :: ByteString -> Lazy.ByteString-        B.toStrict,             -- :: Lazy.ByteString -> ByteString+        empty,+        singleton,+        pack,+        unpack,+        B.fromStrict,+        B.toStrict,          -- * Basic interface-        cons,                   -- :: Char -> ByteString -> ByteString-        snoc,                   -- :: ByteString -> Char -> ByteString-        append,                 -- :: ByteString -> ByteString -> ByteString-        head,                   -- :: ByteString -> Char-        uncons,                 -- :: ByteString -> Maybe (Char, ByteString)-        unsnoc,                 -- :: ByteString -> Maybe (ByteString, Char)-        last,                   -- :: ByteString -> Char-        tail,                   -- :: ByteString -> ByteString-        init,                   -- :: ByteString -> ByteString-        null,                   -- :: ByteString -> Bool-        length,                 -- :: ByteString -> Int+        cons,+        snoc,+        append,+        head,+        uncons,+        unsnoc,+        last,+        tail,+        init,+        null,+        length,          -- * Transforming ByteStrings-        map,                    -- :: (Char -> Char) -> ByteString -> ByteString-        reverse,                -- :: ByteString -> ByteString-        intersperse,            -- :: Char -> ByteString -> ByteString-        intercalate,            -- :: ByteString -> [ByteString] -> ByteString-        transpose,              -- :: [ByteString] -> [ByteString]+        map,+        reverse,+        intersperse,+        intercalate,+        transpose,          -- * Reducing 'ByteString's (folds)-        foldl,                  -- :: (a -> Char -> a) -> a -> ByteString -> a-        foldl',                 -- :: (a -> Char -> a) -> a -> ByteString -> a-        foldl1,                 -- :: (Char -> Char -> Char) -> ByteString -> Char-        foldl1',                -- :: (Char -> Char -> Char) -> ByteString -> Char+        foldl,+        foldl',+        foldl1,+        foldl1', -        foldr,                  -- :: (Char -> a -> a) -> a -> ByteString -> a-        foldr',                 -- :: (Char -> a -> a) -> a -> ByteString -> a-        foldr1,                 -- :: (Char -> Char -> Char) -> ByteString -> Char-        foldr1',                -- :: (Char -> Char -> Char) -> ByteString -> Char+        foldr,+        foldr',+        foldr1,+        foldr1',          -- ** Special folds-        concat,                 -- :: [ByteString] -> ByteString-        concatMap,              -- :: (Char -> ByteString) -> ByteString -> ByteString-        any,                    -- :: (Char -> Bool) -> ByteString -> Bool-        all,                    -- :: (Char -> Bool) -> ByteString -> Bool-        maximum,                -- :: ByteString -> Char-        minimum,                -- :: ByteString -> Char+        concat,+        concatMap,+        any,+        all,+        maximum,+        minimum,          -- * Building ByteStrings         -- ** Scans-        scanl,                  -- :: (Char -> Char -> Char) -> Char -> ByteString -> ByteString-        scanl1,                 -- :: (Char -> Char -> Char) -> ByteString -> ByteString-        scanr,                  -- :: (Char -> Char -> Char) -> Char -> ByteString -> ByteString-        scanr1,                 -- :: (Char -> Char -> Char) -> ByteString -> ByteString+        scanl,+        scanl1,+        scanr,+        scanr1,          -- ** Accumulating maps-        mapAccumL,              -- :: (acc -> Char -> (acc, Char)) -> acc -> ByteString -> (acc, ByteString)-        mapAccumR,              -- :: (acc -> Char -> (acc, Char)) -> acc -> ByteString -> (acc, ByteString)+        mapAccumL,+        mapAccumR,          -- ** Generating and unfolding ByteStrings-        replicate,              -- :: Int -> Char -> ByteString-        unfoldr,                -- :: (a -> Maybe (Char, a)) -> a -> ByteString-        unfoldrN,               -- :: Int -> (a -> Maybe (Char, a)) -> a -> (ByteString, Maybe a)+        replicate,+        unfoldr,+        unfoldrN,          -- * Substrings          -- ** Breaking strings-        take,                   -- :: Int -> ByteString -> ByteString-        takeEnd,                -- :: Int -> ByteString -> ByteString-        drop,                   -- :: Int -> ByteString -> ByteString-        dropEnd,                -- :: Int -> ByteString -> ByteString-        splitAt,                -- :: Int -> ByteString -> (ByteString, ByteString)-        takeWhile,              -- :: (Char -> Bool) -> ByteString -> ByteString-        takeWhileEnd,           -- :: (Char -> Bool) -> ByteString -> ByteString-        dropWhile,              -- :: (Char -> Bool) -> ByteString -> ByteString-        dropWhileEnd,           -- :: (Char -> Bool) -> ByteString -> ByteString-        dropSpace,              -- :: ByteString -> ByteString-        span,                   -- :: (Char -> Bool) -> ByteString -> (ByteString, ByteString)-        spanEnd,                -- :: (Char -> Bool) -> ByteString -> (ByteString, ByteString)-        break,                  -- :: (Char -> Bool) -> ByteString -> (ByteString, ByteString)-        breakEnd,               -- :: (Char -> Bool) -> ByteString -> (ByteString, ByteString)-        group,                  -- :: ByteString -> [ByteString]-        groupBy,                -- :: (Char -> Char -> Bool) -> ByteString -> [ByteString]-        inits,                  -- :: ByteString -> [ByteString]-        tails,                  -- :: ByteString -> [ByteString]-        strip,                  -- :: ByteString -> ByteString-        stripPrefix,            -- :: ByteString -> ByteString -> Maybe ByteString-        stripSuffix,            -- :: ByteString -> ByteString -> Maybe ByteString+        take,+        takeEnd,+        drop,+        dropEnd,+        splitAt,+        takeWhile,+        takeWhileEnd,+        dropWhile,+        dropWhileEnd,+        dropSpace,+        span,+        spanEnd,+        break,+        breakEnd,+        group,+        groupBy,+        inits,+        tails,+        strip,+        stripPrefix,+        stripSuffix,          -- ** Breaking into many substrings-        split,                  -- :: Char -> ByteString -> [ByteString]-        splitWith,              -- :: (Char -> Bool) -> ByteString -> [ByteString]+        split,+        splitWith,          -- ** Breaking into lines and words-        lines,                  -- :: ByteString -> [ByteString]-        words,                  -- :: ByteString -> [ByteString]-        unlines,                -- :: [ByteString] -> ByteString-        unwords,                -- :: [ByteString] -> ByteString+        lines,+        words,+        unlines,+        unwords,          -- * Predicates-        isPrefixOf,             -- :: ByteString -> ByteString -> Bool-        isSuffixOf,             -- :: ByteString -> ByteString -> Bool-        isInfixOf,              -- :: ByteString -> ByteString -> Bool+        isPrefixOf,+        isSuffixOf,+        isInfixOf,          -- ** Search for arbitrary substrings-        breakSubstring,         -- :: ByteString -> ByteString -> (ByteString,ByteString)+        breakSubstring,          -- * Searching ByteStrings          -- ** Searching by equality-        elem,                   -- :: Char -> ByteString -> Bool-        notElem,                -- :: Char -> ByteString -> Bool+        elem,+        notElem,          -- ** Searching with a predicate-        find,                   -- :: (Char -> Bool) -> ByteString -> Maybe Char-        filter,                 -- :: (Char -> Bool) -> ByteString -> ByteString-        partition,              -- :: (Char -> Bool) -> ByteString -> (ByteString, ByteString)+        find,+        filter,+        partition,          -- * Indexing ByteStrings-        index,                  -- :: ByteString -> Int -> Char-        indexMaybe,             -- :: ByteString -> Int -> Maybe Char-        (!?),                   -- :: ByteString -> Int -> Maybe Char-        elemIndex,              -- :: Char -> ByteString -> Maybe Int-        elemIndices,            -- :: Char -> ByteString -> [Int]-        elemIndexEnd,           -- :: Char -> ByteString -> Maybe Int-        findIndex,              -- :: (Char -> Bool) -> ByteString -> Maybe Int-        findIndices,            -- :: (Char -> Bool) -> ByteString -> [Int]-        findIndexEnd,           -- :: (Char -> Bool) -> ByteString -> Maybe Int-        count,                  -- :: Char -> ByteString -> Int+        index,+        indexMaybe,+        (!?),+        elemIndex,+        elemIndices,+        elemIndexEnd,+        findIndex,+        findIndices,+        findIndexEnd,+        count,          -- * Zipping and unzipping ByteStrings-        zip,                    -- :: ByteString -> ByteString -> [(Char,Char)]-        zipWith,                -- :: (Char -> Char -> c) -> ByteString -> ByteString -> [c]-        packZipWith,            -- :: (Char -> Char -> Char) -> ByteString -> ByteString -> ByteString-        unzip,                  -- :: [(Char,Char)] -> (ByteString,ByteString)+        zip,+        zipWith,+        packZipWith,+        unzip,          -- * Ordered ByteStrings-        sort,                   -- :: ByteString -> ByteString+        sort,          -- * Reading from ByteStrings-        readInt,                -- :: ByteString -> Maybe (Int, ByteString)-        readInteger,            -- :: ByteString -> Maybe (Integer, ByteString)+        readInt,+        readInteger,          -- * Low level CString conversions          -- ** Copying ByteStrings-        copy,                   -- :: ByteString -> ByteString+        copy,          -- ** Packing CStrings and pointers-        packCString,            -- :: CString -> IO ByteString-        packCStringLen,         -- :: CStringLen -> IO ByteString+        packCString,+        packCStringLen,          -- ** Using ByteStrings as CStrings-        useAsCString,           -- :: ByteString -> (CString    -> IO a) -> IO a-        useAsCStringLen,        -- :: ByteString -> (CStringLen -> IO a) -> IO a+        useAsCString,+        useAsCStringLen,          -- * I\/O with 'ByteString's         -- | ByteString I/O uses binary mode, without any character decoding@@ -207,28 +206,28 @@         -- newline mode is considered a flaw and may be changed in a future version.          -- ** Standard input and output-        getLine,                -- :: IO ByteString-        getContents,            -- :: IO ByteString-        putStr,                 -- :: ByteString -> IO ()-        putStrLn,               -- :: ByteString -> IO ()-        interact,               -- :: (ByteString -> ByteString) -> IO ()+        getLine,+        getContents,+        putStr,+        putStrLn,+        interact,          -- ** Files-        readFile,               -- :: FilePath -> IO ByteString-        writeFile,              -- :: FilePath -> ByteString -> IO ()-        appendFile,             -- :: FilePath -> ByteString -> IO ()---      mmapFile,               -- :: FilePath -> IO ByteString+        readFile,+        writeFile,+        appendFile,+--      mmapFile,          -- ** I\/O with Handles-        hGetLine,               -- :: Handle -> IO ByteString-        hGetContents,           -- :: Handle -> IO ByteString-        hGet,                   -- :: Handle -> Int -> IO ByteString-        hGetSome,               -- :: Handle -> Int -> IO ByteString-        hGetNonBlocking,        -- :: Handle -> Int -> IO ByteString-        hPut,                   -- :: Handle -> ByteString -> IO ()-        hPutNonBlocking,        -- :: Handle -> ByteString -> IO ByteString-        hPutStr,                -- :: Handle -> ByteString -> IO ()-        hPutStrLn,              -- :: Handle -> ByteString -> IO ()+        hGetLine,+        hGetContents,+        hGet,+        hGetSome,+        hGetNonBlocking,+        hPut,+        hPutNonBlocking,+        hPutStr,+        hPutStrLn,    ) where @@ -266,15 +265,9 @@  import Data.ByteString.Internal -#if !(MIN_VERSION_base(4,8,0))-import Control.Applicative ((<$>))-#endif- import Data.Char    ( isSpace )-#if MIN_VERSION_base(4,9,0) -- See bytestring #70 import GHC.Char (eqChar)-#endif import qualified Data.List as List (intersperse)  import System.IO    (Handle,stdout)@@ -543,21 +536,12 @@ {-# INLINE [1] break #-}  -- See bytestring #70-#if MIN_VERSION_base(4,9,0) {-# RULES "ByteString specialise break (x==)" forall x.     break (x `eqChar`) = breakChar x "ByteString specialise break (==x)" forall x.     break (`eqChar` x) = breakChar x   #-}-#else-{-# RULES-"ByteString specialise break (x==)" forall x.-    break (x ==) = breakChar x-"ByteString specialise break (==x)" forall x.-    break (== x) = breakChar x-  #-}-#endif  -- INTERNAL: @@ -720,7 +704,6 @@ findIndices f = B.findIndices (f . w2c) {-# INLINE [1] findIndices #-} -#if MIN_VERSION_base(4,9,0) {-# RULES "ByteString specialise findIndex (x==)" forall x.     findIndex (x `eqChar`) = elemIndex x@@ -731,18 +714,6 @@ "ByteString specialise findIndices (==x)" forall x.     findIndices (`eqChar` x) = elemIndices x   #-}-#else-{-# RULES-"ByteString specialise findIndex (x==)" forall x.-    findIndex (x==) = elemIndex x-"ByteString specialise findIndex (==x)" forall x.-    findIndex (==x) = elemIndex x-"ByteString specialise findIndices (x==)" forall x.-    findIndices (x==) = elemIndices x-"ByteString specialise findIndices (==x)" forall x.-    findIndices (==x) = elemIndices x-  #-}-#endif   -- | count returns the number of times its argument appears in the ByteString
Data/ByteString/Internal.hs view
@@ -3,12 +3,9 @@             UnboxedTuples, DeriveDataTypeable #-} {-# LANGUAGE TupleSections #-} {-# LANGUAGE TypeFamilies #-}-#if __GLASGOW_HASKELL__ >= 800 {-# LANGUAGE PatternSynonyms, ViewPatterns #-}-#endif-#if __GLASGOW_HASKELL__ >= 703 {-# LANGUAGE Unsafe #-}-#endif+{-# LANGUAGE TemplateHaskellQuotes #-} {-# OPTIONS_HADDOCK not-home #-}  -- |@@ -33,11 +30,11 @@         -- * The @ByteString@ type and representation         ByteString         ( BS-#if __GLASGOW_HASKELL__ >= 800         , PS -- backwards compatibility shim-#endif-        ), -- instances: Eq, Ord, Show, Read, Data, Typeable+        ), +        StrictByteString,+         -- * Internal indexing         findIndexOrLength, @@ -46,51 +43,52 @@         packChars, packUptoLenChars, unsafePackLenChars,         unpackBytes, unpackAppendBytesLazy, unpackAppendBytesStrict,         unpackChars, unpackAppendCharsLazy, unpackAppendCharsStrict,-        unsafePackAddress, unsafePackLiteral,+        unsafePackAddress, unsafePackLenAddress,+        unsafePackLiteral, unsafePackLenLiteral,          -- * Low level imperative construction-        create,                 -- :: Int -> (Ptr Word8 -> IO ()) -> IO ByteString-        createUptoN,            -- :: Int -> (Ptr Word8 -> IO Int) -> IO ByteString-        createUptoN',           -- :: Int -> (Ptr Word8 -> IO (Int, a)) -> IO (ByteString, a)-        createAndTrim,          -- :: Int -> (Ptr Word8 -> IO Int) -> IO ByteString-        createAndTrim',         -- :: Int -> (Ptr Word8 -> IO (Int, Int, a)) -> IO (ByteString, a)-        unsafeCreate,           -- :: Int -> (Ptr Word8 -> IO ()) -> ByteString-        unsafeCreateUptoN,      -- :: Int -> (Ptr Word8 -> IO Int) -> ByteString-        unsafeCreateUptoN',     -- :: Int -> (Ptr Word8 -> IO (Int, a)) -> (ByteString, a)-        mallocByteString,       -- :: Int -> IO (ForeignPtr a)+        create,+        createUptoN,+        createUptoN',+        createAndTrim,+        createAndTrim',+        unsafeCreate,+        unsafeCreateUptoN,+        unsafeCreateUptoN',+        mallocByteString,          -- * 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)+        fromForeignPtr,+        toForeignPtr,+        fromForeignPtr0,+        toForeignPtr0,          -- * Utilities-        nullForeignPtr,         -- :: ForeignPtr Word8-        checkedAdd,             -- :: String -> Int -> Int -> Int+        nullForeignPtr,+        checkedAdd,          -- * Standard C Functions-        c_strlen,               -- :: CString -> IO CInt-        c_free_finalizer,       -- :: FunPtr (Ptr Word8 -> IO ())+        c_strlen,+        c_free_finalizer, -        memchr,                 -- :: Ptr Word8 -> Word8 -> CSize -> IO Ptr Word8-        memcmp,                 -- :: Ptr Word8 -> Ptr Word8 -> Int -> IO CInt-        memcpy,                 -- :: Ptr Word8 -> Ptr Word8 -> Int -> IO ()-        memset,                 -- :: Ptr Word8 -> Word8 -> CSize -> IO (Ptr Word8)+        memchr,+        memcmp,+        memcpy,+        memset,          -- * cbits functions-        c_reverse,              -- :: Ptr Word8 -> Ptr Word8 -> CSize -> IO ()-        c_intersperse,          -- :: Ptr Word8 -> Ptr Word8 -> CSize -> Word8 -> IO ()-        c_maximum,              -- :: Ptr Word8 -> CSize -> IO Word8-        c_minimum,              -- :: Ptr Word8 -> CSize -> IO Word8-        c_count,                -- :: Ptr Word8 -> CSize -> Word8 -> IO CSize-        c_sort,                 -- :: Ptr Word8 -> CSize -> IO ()+        c_reverse,+        c_intersperse,+        c_maximum,+        c_minimum,+        c_count,+        c_sort,          -- * Chars         w2c, c2w, isSpaceWord8, isSpaceChar8,          -- * Deprecated and unmentionable-        accursedUnutterablePerformIO, -- :: IO a -> a+        accursedUnutterablePerformIO,          -- * Exported compatibility shim         plusForeignPtr,@@ -105,27 +103,15 @@ import Foreign.ForeignPtr       (ForeignPtr, withForeignPtr) import Foreign.Ptr              (Ptr, FunPtr, plusPtr, minusPtr) import Foreign.Storable         (Storable(..))--#if MIN_VERSION_base(4,5,0) || __GLASGOW_HASKELL__ >= 703 import Foreign.C.Types          (CInt(..), CSize(..))-#else-import Foreign.C.Types          (CInt, CSize)-#endif- import Foreign.C.String         (CString)  #if MIN_VERSION_base(4,13,0) import Data.Semigroup           (Semigroup (sconcat, stimes))-import Data.List.NonEmpty       (NonEmpty ((:|)))-#elif MIN_VERSION_base(4,9,0)+#else import Data.Semigroup           (Semigroup ((<>), sconcat, stimes))-import Data.List.NonEmpty       (NonEmpty ((:|))) #endif--#if !(MIN_VERSION_base(4,8,0))-import Data.Monoid              (Monoid(..))-#endif-+import Data.List.NonEmpty       (NonEmpty ((:|)))  import Control.DeepSeq          (NFData(rnf)) @@ -141,21 +127,10 @@ import Data.Data                (Data(..), mkNoRepType)  import GHC.Base                 (nullAddr#,realWorld#,unsafeChr)--#if MIN_VERSION_base(4,7,0) import GHC.Exts                 (IsList(..))-#endif--#if MIN_VERSION_base(4,4,0) import GHC.CString              (unpackCString#)-#else-import GHC.Base                 (unpackCString#)-#endif- import GHC.Prim                 (Addr#)- import GHC.IO                   (IO(IO),unsafeDupablePerformIO)- import GHC.ForeignPtr           (ForeignPtr(ForeignPtr) #if __GLASGOW_HASKELL__ < 900                                 , newForeignPtr_@@ -172,7 +147,7 @@ import GHC.CString              (cstringLength#) import GHC.ForeignPtr           (ForeignPtrContents(FinalPtr)) #else-import GHC.Ptr                  (Ptr(..), castPtr)+import GHC.Ptr                  (Ptr(..)) #endif  #if (__GLASGOW_HASKELL__ < 802) || (__GLASGOW_HASKELL__ >= 811)@@ -183,6 +158,9 @@ import GHC.ForeignPtr           (unsafeWithForeignPtr) #endif +import qualified Language.Haskell.TH.Lib as TH+import qualified Language.Haskell.TH.Syntax as TH+ #if !MIN_VERSION_base(4,15,0) unsafeWithForeignPtr :: ForeignPtr a -> (Ptr a -> IO b) -> IO b unsafeWithForeignPtr = withForeignPtr@@ -221,10 +199,14 @@ -- data ByteString = BS {-# UNPACK #-} !(ForeignPtr Word8) -- payload                      {-# UNPACK #-} !Int                -- length+                     -- ^ @since 0.11.0.0     deriving (Typeable) +-- | Type synonym for the strict flavour of 'ByteString'.+--+-- @since 0.11.2.0+type StrictByteString = ByteString -#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@@ -235,7 +217,7 @@ -- 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',+-- /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@@ -244,7 +226,6 @@ #if __GLASGOW_HASKELL__ >= 802 {-# COMPLETE PS #-} #endif-#endif  instance Eq  ByteString where     (==)    = eq@@ -252,20 +233,14 @@ instance Ord ByteString where     compare = compareBytes -#if MIN_VERSION_base(4,9,0) instance Semigroup ByteString where     (<>)    = append     sconcat (b:|bs) = concat (b:bs)-    stimes = times-#endif+    stimes  = times  instance Monoid ByteString where     mempty  = BS nullForeignPtr 0-#if MIN_VERSION_base(4,9,0)     mappend = (<>)-#else-    mappend = append-#endif     mconcat = concat  instance NFData ByteString where@@ -277,13 +252,11 @@ instance Read ByteString where     readsPrec p str = [ (packChars x, y) | (x, y) <- readsPrec p str ] -#if MIN_VERSION_base(4,7,0) -- | @since 0.10.12.0 instance IsList ByteString where   type Item ByteString = Word8   fromList = packBytes   toList   = unpackBytes-#endif  -- | Beware: 'fromString' truncates multi-byte characters to octets. -- e.g. "枯朶に烏のとまりけり秋の暮" becomes �6k�nh~�Q��n�@@ -297,6 +270,24 @@   gunfold _ _    = error "Data.ByteString.ByteString.gunfold"   dataTypeOf _   = mkNoRepType "Data.ByteString.ByteString" +-- | @since 0.11.2.0+instance TH.Lift ByteString where+#if MIN_VERSION_template_haskell(2,16,0)+  lift (BS ptr len) = [| unsafePackLenLiteral |]+    `TH.appE` TH.litE (TH.integerL (fromIntegral len))+    `TH.appE` TH.litE (TH.BytesPrimL $ TH.Bytes ptr 0 (fromIntegral len))+#else+  lift bs@(BS _ len) = [| unsafePackLenLiteral |]+    `TH.appE` TH.litE (TH.integerL (fromIntegral len))+    `TH.appE` TH.litE (TH.StringPrimL $ unpackBytes bs)+#endif++#if MIN_VERSION_template_haskell(2,17,0)+  liftTyped = TH.unsafeCodeCoerce . TH.lift+#elif MIN_VERSION_template_haskell(2,16,0)+  liftTyped = TH.unsafeTExpCoerce . TH.lift+#endif+ ------------------------------------------------------------------------ -- Internal indexing @@ -304,7 +295,7 @@ -- of the string if no element is found, rather than Nothing. findIndexOrLength :: (Word8 -> Bool) -> ByteString -> Int findIndexOrLength k (BS x l) =-    accursedUnutterablePerformIO $ withForeignPtr x g+    accursedUnutterablePerformIO $ unsafeWithForeignPtr x g   where     g ptr = go 0       where@@ -370,33 +361,62 @@ unsafePackAddress :: Addr# -> IO ByteString unsafePackAddress addr# = do #if __GLASGOW_HASKELL__ >= 811-    return (BS (ForeignPtr addr# FinalPtr) (I# (cstringLength# addr#)))+    unsafePackLenAddress (I# (cstringLength# addr#)) addr# #else-    p <- newForeignPtr_ (castPtr cstr)-    l <- c_strlen cstr-    return $ BS p (fromIntegral l)-  where-    cstr :: CString-    cstr = Ptr addr#+    l <- c_strlen (Ptr addr#)+    unsafePackLenAddress (fromIntegral l) addr# #endif {-# INLINE unsafePackAddress #-} +-- | See 'unsafePackAddress'. This function is similar,+-- but takes an additional length argument rather then computing+-- it with @strlen@.+-- Therefore embedding @\'\\0\'@ characters is possible.+--+-- @since 0.11.2.0+unsafePackLenAddress :: Int -> Addr# -> IO ByteString+unsafePackLenAddress len addr# = do+#if __GLASGOW_HASKELL__ >= 811+    return (BS (ForeignPtr addr# FinalPtr) len)+#else+    p <- newForeignPtr_ (Ptr addr#)+    return $ BS p len+#endif+{-# INLINE unsafePackLenAddress #-}+ -- | See 'unsafePackAddress'. This function has similar behavior. Prefer -- this function when the address in known to be an @Addr#@ literal. In -- that context, there is no need for the sequencing guarantees that 'IO' -- provides. On GHC 9.0 and up, this function uses the @FinalPtr@ data -- constructor for @ForeignPtrContents@.+--+-- @since 0.11.1.0 unsafePackLiteral :: Addr# -> ByteString unsafePackLiteral addr# = #if __GLASGOW_HASKELL__ >= 811-  BS (ForeignPtr addr# FinalPtr) (I# (cstringLength# addr#))+  unsafePackLenLiteral (I# (cstringLength# addr#)) addr# #else   let len = accursedUnutterablePerformIO (c_strlen (Ptr addr#))-   in BS (accursedUnutterablePerformIO (newForeignPtr_ (Ptr addr#))) (fromIntegral len)+   in unsafePackLenLiteral (fromIntegral len) addr# #endif {-# INLINE unsafePackLiteral #-}  +-- | See 'unsafePackLiteral'. This function is similar,+-- but takes an additional length argument rather then computing+-- it with @strlen@.+-- Therefore embedding @\'\\0\'@ characters is possible.+--+-- @since 0.11.2.0+unsafePackLenLiteral :: Int -> Addr# -> ByteString+unsafePackLenLiteral len addr# =+#if __GLASGOW_HASKELL__ >= 811+  BS (ForeignPtr addr# FinalPtr) len+#else+  BS (accursedUnutterablePerformIO (newForeignPtr_ (Ptr addr#))) len+#endif+{-# INLINE unsafePackLenLiteral #-}+ packUptoLenBytes :: Int -> [Word8] -> (ByteString, [Word8]) packUptoLenBytes len xs0 =     unsafeCreateUptoN' len $ \p0 ->@@ -490,7 +510,7 @@  -- | /O(1)/ Build a ByteString from a ForeignPtr. ----- If you do not need the offset parameter then you do should be using+-- If you do not need the offset parameter then you should be using -- 'Data.ByteString.Unsafe.unsafePackCStringLen' or -- 'Data.ByteString.Unsafe.unsafePackCStringFinalizer' instead. --@@ -501,6 +521,7 @@ fromForeignPtr fp o = BS (plusForeignPtr fp o) {-# INLINE fromForeignPtr #-} +-- | @since 0.11.0.0 fromForeignPtr0 :: ForeignPtr Word8                -> Int -- ^ Length                -> ByteString@@ -513,6 +534,8 @@ {-# INLINE toForeignPtr #-}  -- | /O(1)/ Deconstruct a ForeignPtr from a ByteString+--+-- @since 0.11.0.0 toForeignPtr0 :: ByteString -> (ForeignPtr Word8, Int) -- ^ (ptr, length) toForeignPtr0 (BS ps l) = (ps, l) {-# INLINE toForeignPtr0 #-}@@ -538,30 +561,33 @@  -- | Create ByteString of size @l@ and use action @f@ to fill its contents. create :: Int -> (Ptr Word8 -> IO ()) -> IO ByteString-create l f = do+create l action = do     fp <- mallocByteString l-    withForeignPtr fp $ \p -> f p+    -- Cannot use unsafeWithForeignPtr, because action can diverge+    withForeignPtr fp $ \p -> action p     return $! BS fp l {-# INLINE create #-}  -- | Given a maximum size @l@ and an action @f@ that fills the 'ByteString' -- starting at the given 'Ptr' and returns the actual utilized length,--- @`createUpToN'` l f@ returns the filled 'ByteString'.+-- @`createUptoN'` l f@ returns the filled 'ByteString'. createUptoN :: Int -> (Ptr Word8 -> IO Int) -> IO ByteString-createUptoN l f = do+createUptoN l action = do     fp <- mallocByteString l-    l' <- withForeignPtr fp $ \p -> f p+    -- Cannot use unsafeWithForeignPtr, because action can diverge+    l' <- withForeignPtr fp $ \p -> action p     assert (l' <= l) $ return $! BS fp l' {-# INLINE createUptoN #-} --- | Like 'createUpToN', but also returns an additional value created by the+-- | Like 'createUptoN', but also returns an additional value created by the -- action. -- -- @since 0.10.12.0 createUptoN' :: Int -> (Ptr Word8 -> IO (Int, a)) -> IO (ByteString, a)-createUptoN' l f = do+createUptoN' l action = do     fp <- mallocByteString l-    (l', res) <- withForeignPtr fp $ \p -> f p+    -- Cannot use unsafeWithForeignPtr, because action can diverge+    (l', res) <- withForeignPtr fp $ \p -> action p     assert (l' <= l) $ return (BS fp l', res) {-# INLINE createUptoN' #-} @@ -574,25 +600,28 @@ -- ByteString functions, using Haskell or C functions to fill the space. -- createAndTrim :: Int -> (Ptr Word8 -> IO Int) -> IO ByteString-createAndTrim l f = do+createAndTrim l action = do     fp <- mallocByteString l+    -- Cannot use unsafeWithForeignPtr, because action can diverge     withForeignPtr fp $ \p -> do-        l' <- f p+        l' <- action p         if assert (l' <= l) $ l' >= l             then return $! BS fp l             else create l' $ \p' -> memcpy p' p l' {-# INLINE createAndTrim #-}  createAndTrim' :: Int -> (Ptr Word8 -> IO (Int, Int, a)) -> IO (ByteString, a)-createAndTrim' l f = do+createAndTrim' l action = do     fp <- mallocByteString l+    -- Cannot use unsafeWithForeignPtr, because action can diverge     withForeignPtr fp $ \p -> do-        (off, l', res) <- f p+        (off, l', res) <- action p         if assert (l' <= l) $ l' >= l             then return (BS fp l, res)             else do ps <- create l' $ \p' ->                             memcpy p' (p `plusPtr` off) l'                     return (ps, res)+{-# INLINE createAndTrim' #-}  -- | Wrapper of 'Foreign.ForeignPtr.mallocForeignPtrBytes' with faster implementation for GHC --@@ -682,7 +711,6 @@    concat [x] = x  #-} -#if MIN_VERSION_base(4,9,0) -- | /O(log n)/ Repeats the given ByteString n times. times :: Integral a => a -> ByteString -> ByteString times n (BS fp len)@@ -707,7 +735,6 @@         memcpy (destptr `plusPtr` copied) destptr copied         fillFrom destptr (copied * 2)       | otherwise = memcpy (destptr `plusPtr` copied) destptr (size - copied)-#endif  -- | Add two non-negative numbers. Errors out on overflow. checkedAdd :: String -> Int -> Int -> Int
Data/ByteString/Lazy.hs view
@@ -1,9 +1,7 @@-{-# LANGUAGE CPP, BangPatterns #-}+{-# LANGUAGE BangPatterns #-} {-# OPTIONS_GHC -fno-warn-incomplete-patterns #-} {-# OPTIONS_HADDOCK prune #-}-#if __GLASGOW_HASKELL__ >= 701 {-# LANGUAGE Trustworthy #-}-#endif  -- | -- Module      : Data.ByteString.Lazy@@ -51,165 +49,174 @@  module Data.ByteString.Lazy ( -        -- * The @ByteString@ type-        ByteString,             -- instances: Eq, Ord, Show, Read, Data, Typeable+        -- * Lazy @ByteString@+        ByteString,+        LazyByteString,          -- * Introducing and eliminating 'ByteString's-        empty,                  -- :: ByteString-        singleton,              -- :: Word8   -> ByteString-        pack,                   -- :: [Word8] -> ByteString-        unpack,                 -- :: ByteString -> [Word8]-        fromStrict,             -- :: Strict.ByteString -> ByteString-        toStrict,               -- :: ByteString -> Strict.ByteString-        fromChunks,             -- :: [Strict.ByteString] -> ByteString-        toChunks,               -- :: ByteString -> [Strict.ByteString]-        foldrChunks,            -- :: (S.ByteString -> a -> a) -> a -> ByteString -> a-        foldlChunks,            -- :: (a -> S.ByteString -> a) -> a -> ByteString -> a+        empty,+        singleton,+        pack,+        unpack,+        fromStrict,+        toStrict,+        fromChunks,+        toChunks,+        foldrChunks,+        foldlChunks,          -- * Basic interface-        cons,                   -- :: Word8 -> ByteString -> ByteString-        cons',                  -- :: Word8 -> ByteString -> ByteString-        snoc,                   -- :: ByteString -> Word8 -> ByteString-        append,                 -- :: ByteString -> ByteString -> ByteString-        head,                   -- :: ByteString -> Word8-        uncons,                 -- :: ByteString -> Maybe (Word8, ByteString)-        unsnoc,                 -- :: ByteString -> Maybe (ByteString, Word8)-        last,                   -- :: ByteString -> Word8-        tail,                   -- :: ByteString -> ByteString-        init,                   -- :: ByteString -> ByteString-        null,                   -- :: ByteString -> Bool-        length,                 -- :: ByteString -> Int64+        cons,+        cons',+        snoc,+        append,+        head,+        uncons,+        unsnoc,+        last,+        tail,+        init,+        null,+        length,          -- * Transforming ByteStrings-        map,                    -- :: (Word8 -> Word8) -> ByteString -> ByteString-        reverse,                -- :: ByteString -> ByteString-        intersperse,            -- :: Word8 -> ByteString -> ByteString-        intercalate,            -- :: ByteString -> [ByteString] -> ByteString-        transpose,              -- :: [ByteString] -> [ByteString]+        map,+        reverse,+        intersperse,+        intercalate,+        transpose,          -- * 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-        foldr1,                 -- :: (Word8 -> Word8 -> Word8) -> ByteString -> Word8+        foldl,+        foldl',+        foldl1,+        foldl1',+        foldr,+        foldr',+        foldr1,+        foldr1',          -- ** 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-        compareLength,          -- :: ByteString -> Int64 -> Ordering+        concat,+        concatMap,+        any,+        all,+        maximum,+        minimum,+        compareLength,          -- * 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+        scanl,+        scanl1,+        scanr,+        scanr1,          -- ** Accumulating maps-        mapAccumL,              -- :: (acc -> Word8 -> (acc, Word8)) -> acc -> ByteString -> (acc, ByteString)-        mapAccumR,              -- :: (acc -> Word8 -> (acc, Word8)) -> acc -> ByteString -> (acc, ByteString)+        mapAccumL,+        mapAccumR,          -- ** Infinite ByteStrings-        repeat,                 -- :: Word8 -> ByteString-        replicate,              -- :: Int64 -> Word8 -> ByteString-        cycle,                  -- :: ByteString -> ByteString-        iterate,                -- :: (Word8 -> Word8) -> Word8 -> ByteString+        repeat,+        replicate,+        cycle,+        iterate,          -- ** Unfolding ByteStrings-        unfoldr,                -- :: (a -> Maybe (Word8, a)) -> a -> ByteString+        unfoldr,          -- * Substrings          -- ** Breaking strings-        take,                   -- :: Int64 -> ByteString -> ByteString-        drop,                   -- :: Int64 -> ByteString -> ByteString-        splitAt,                -- :: Int64 -> ByteString -> (ByteString, ByteString)-        takeWhile,              -- :: (Word8 -> Bool) -> ByteString -> ByteString-        dropWhile,              -- :: (Word8 -> Bool) -> ByteString -> ByteString-        span,                   -- :: (Word8 -> Bool) -> ByteString -> (ByteString, ByteString)-        break,                  -- :: (Word8 -> Bool) -> ByteString -> (ByteString, ByteString)-        group,                  -- :: ByteString -> [ByteString]-        groupBy,                -- :: (Word8 -> Word8 -> Bool) -> ByteString -> [ByteString]-        inits,                  -- :: ByteString -> [ByteString]-        tails,                  -- :: ByteString -> [ByteString]-        stripPrefix,            -- :: ByteString -> ByteString -> Maybe ByteString-        stripSuffix,            -- :: ByteString -> ByteString -> Maybe ByteString+        take,+        takeEnd,+        drop,+        dropEnd,+        splitAt,+        takeWhile,+        takeWhileEnd,+        dropWhile,+        dropWhileEnd,+        span,+        spanEnd,+        break,+        breakEnd,+        group,+        groupBy,+        inits,+        tails,+        stripPrefix,+        stripSuffix,          -- ** Breaking into many substrings-        split,                  -- :: Word8 -> ByteString -> [ByteString]-        splitWith,              -- :: (Word8 -> Bool) -> ByteString -> [ByteString]+        split,+        splitWith,          -- * Predicates-        isPrefixOf,             -- :: ByteString -> ByteString -> Bool-        isSuffixOf,             -- :: ByteString -> ByteString -> Bool---        isInfixOf,              -- :: ByteString -> ByteString -> Bool+        isPrefixOf,+        isSuffixOf,+--        isInfixOf,          -- ** Search for arbitrary substrings---        isSubstringOf,          -- :: ByteString -> ByteString -> Bool+--        isSubstringOf,          -- * Searching ByteStrings          -- ** Searching by equality-        elem,                   -- :: Word8 -> ByteString -> Bool-        notElem,                -- :: Word8 -> ByteString -> Bool+        elem,+        notElem,          -- ** Searching with a predicate-        find,                   -- :: (Word8 -> Bool) -> ByteString -> Maybe Word8-        filter,                 -- :: (Word8 -> Bool) -> ByteString -> ByteString-        partition,              -- :: (Word8 -> Bool) -> ByteString -> (ByteString, ByteString)+        find,+        filter,+        partition,          -- * Indexing ByteStrings-        index,                  -- :: ByteString -> Int64 -> Word8-        indexMaybe,             -- :: ByteString -> Int64 -> Maybe Word8-        (!?),                   -- :: ByteString -> Int64 -> Maybe Word8-        elemIndex,              -- :: Word8 -> ByteString -> Maybe Int64-        elemIndexEnd,           -- :: Word8 -> ByteString -> Maybe Int64-        elemIndices,            -- :: Word8 -> ByteString -> [Int64]-        findIndex,              -- :: (Word8 -> Bool) -> ByteString -> Maybe Int64-        findIndexEnd,           -- :: (Word8 -> Bool) -> ByteString -> Maybe Int64-        findIndices,            -- :: (Word8 -> Bool) -> ByteString -> [Int64]-        count,                  -- :: Word8 -> ByteString -> Int64+        index,+        indexMaybe,+        (!?),+        elemIndex,+        elemIndexEnd,+        elemIndices,+        findIndex,+        findIndexEnd,+        findIndices,+        count,          -- * Zipping and unzipping ByteStrings-        zip,                    -- :: ByteString -> ByteString -> [(Word8,Word8)]-        zipWith,                -- :: (Word8 -> Word8 -> c) -> ByteString -> ByteString -> [c]-        packZipWith,            -- :: (Word8 -> Word8 -> Word8) -> ByteString -> ByteString -> ByteString-        unzip,                  -- :: [(Word8,Word8)] -> (ByteString,ByteString)+        zip,+        zipWith,+        packZipWith,+        unzip,          -- * Ordered ByteStrings---        sort,                   -- :: ByteString -> ByteString+--        sort,          -- * Low level conversions         -- ** Copying ByteStrings-        copy,                   -- :: ByteString -> ByteString---        defrag,                -- :: ByteString -> ByteString+        copy,+--        defrag,          -- * I\/O with 'ByteString's         -- $IOChunk          -- ** Standard input and output-        getContents,            -- :: IO ByteString-        putStr,                 -- :: ByteString -> IO ()-        interact,               -- :: (ByteString -> ByteString) -> IO ()+        getContents,+        putStr,+        interact,          -- ** Files-        readFile,               -- :: FilePath -> IO ByteString-        writeFile,              -- :: FilePath -> ByteString -> IO ()-        appendFile,             -- :: FilePath -> ByteString -> IO ()+        readFile,+        writeFile,+        appendFile,          -- ** I\/O with Handles-        hGetContents,           -- :: Handle -> IO ByteString-        hGet,                   -- :: Handle -> Int -> IO ByteString-        hGetNonBlocking,        -- :: Handle -> Int -> IO ByteString-        hPut,                   -- :: Handle -> ByteString -> IO ()-        hPutNonBlocking,        -- :: Handle -> ByteString -> IO ByteString-        hPutStr,                -- :: Handle -> ByteString -> IO ()+        hGetContents,+        hGet,+        hGetNonBlocking,+        hPut,+        hPutNonBlocking,+        hPutStr,    ) where @@ -220,20 +227,19 @@     ,repeat, cycle, interact, iterate,readFile,writeFile,appendFile,replicate     ,getContents,getLine,putStr,putStrLn ,zip,zipWith,unzip,notElem) -import qualified Data.List              as L  -- L for list/lazy+import qualified Data.List              as List+import qualified Data.Bifunctor         as BF import qualified Data.ByteString        as P  (ByteString) -- type name only import qualified Data.ByteString        as S  -- S for strict (hmm...) import qualified Data.ByteString.Internal as S import qualified Data.ByteString.Unsafe as S+import qualified Data.ByteString.Lazy.Internal.Deque as D import Data.ByteString.Lazy.Internal -#if !(MIN_VERSION_base(4,8,0))-import Control.Applicative      ((<$>))-import Data.Monoid              (Monoid(..))-#endif import Control.Monad            (mplus) import Data.Word                (Word8) import Data.Int                 (Int64)+import GHC.Stack.Types          (HasCallStack) import System.IO                (Handle,openBinaryFile,stdin,stdout,withBinaryFile,IOMode(..)                                 ,hClose) import System.IO.Error          (mkIOError, illegalOperationErrorType)@@ -266,7 +272,7 @@  -- | /O(c)/ Convert a list of strict 'ByteString' into a lazy 'ByteString' fromChunks :: [P.ByteString] -> ByteString-fromChunks = L.foldr chunk Empty+fromChunks = List.foldr chunk Empty  -- | /O(c)/ Convert a lazy 'ByteString' into a list of strict 'ByteString' toChunks :: ByteString -> [P.ByteString]@@ -336,7 +342,7 @@ {-# INLINE snoc #-}  -- | /O(1)/ Extract the first element of a ByteString, which must be non-empty.-head :: ByteString -> Word8+head :: HasCallStack => ByteString -> Word8 head Empty       = errorEmptyList "head" head (Chunk c _) = S.unsafeHead c {-# INLINE head #-}@@ -352,7 +358,7 @@  -- | /O(1)/ Extract the elements after the head of a ByteString, which must be -- non-empty.-tail :: ByteString -> ByteString+tail :: HasCallStack => ByteString -> ByteString tail Empty          = errorEmptyList "tail" tail (Chunk c cs)   | S.length c == 1 = cs@@ -361,7 +367,7 @@  -- | /O(n\/c)/ Extract the last element of a ByteString, which must be finite -- and non-empty.-last :: ByteString -> Word8+last :: HasCallStack => ByteString -> Word8 last Empty          = errorEmptyList "last" last (Chunk c0 cs0) = go c0 cs0   where go c Empty        = S.unsafeLast c@@ -369,7 +375,7 @@ -- XXX Don't inline this. Something breaks with 6.8.2 (haven't investigated yet)  -- | /O(n\/c)/ Return all the elements of a 'ByteString' except the last one.-init :: ByteString -> ByteString+init :: HasCallStack => ByteString -> ByteString init Empty          = errorEmptyList "init" init (Chunk c0 cs0) = go c0 cs0   where go c Empty | S.length c == 1 = Empty@@ -427,8 +433,8 @@ -- | The 'transpose' function transposes the rows and columns of its -- 'ByteString' argument. transpose :: [ByteString] -> [ByteString]-transpose css = L.map (\ss -> Chunk (S.pack ss) Empty)-                      (L.transpose (L.map unpack css))+transpose css = List.map (\ss -> Chunk (S.pack ss) Empty)+                      (List.transpose (List.map unpack css)) --TODO: make this fast  -- ---------------------------------------------------------------------@@ -457,25 +463,44 @@ foldr k = foldrChunks (flip (S.foldr k)) {-# INLINE foldr #-} +-- | 'foldr'' is like 'foldr', but strict in the accumulator.+--+-- @since 0.11.2.0+foldr' :: (Word8 -> a -> a) -> a -> ByteString -> a+foldr' f a = go+  where+    go Empty = a+    go (Chunk c cs) = S.foldr' f (foldr' f a cs) c+{-# INLINE foldr' #-}+ -- | 'foldl1' is a variant of 'foldl' that has no starting value -- argument, and thus must be applied to non-empty 'ByteString's.-foldl1 :: (Word8 -> Word8 -> Word8) -> ByteString -> Word8+foldl1 :: HasCallStack => (Word8 -> Word8 -> Word8) -> ByteString -> Word8 foldl1 _ Empty        = errorEmptyList "foldl1" foldl1 f (Chunk c cs) = foldl f (S.unsafeHead c) (Chunk (S.unsafeTail c) cs)  -- | 'foldl1'' is like 'foldl1', but strict in the accumulator.-foldl1' :: (Word8 -> Word8 -> Word8) -> ByteString -> Word8+foldl1' :: HasCallStack => (Word8 -> Word8 -> Word8) -> ByteString -> Word8 foldl1' _ Empty        = errorEmptyList "foldl1'" foldl1' f (Chunk c cs) = foldl' f (S.unsafeHead c) (Chunk (S.unsafeTail c) cs)  -- | 'foldr1' is a variant of 'foldr' that has no starting value argument, -- and thus must be applied to non-empty 'ByteString's-foldr1 :: (Word8 -> Word8 -> Word8) -> ByteString -> Word8+foldr1 :: HasCallStack => (Word8 -> Word8 -> Word8) -> ByteString -> Word8 foldr1 _ Empty          = errorEmptyList "foldr1" foldr1 f (Chunk c0 cs0) = go c0 cs0   where go c Empty         = S.foldr1 f c         go c (Chunk c' cs) = S.foldr  f (go c' cs) c +-- | 'foldr1'' is like 'foldr1', but strict in the accumulator.+--+-- @since 0.11.2.0+foldr1' :: HasCallStack => (Word8 -> Word8 -> Word8) -> ByteString -> Word8+foldr1' _ Empty          = errorEmptyList "foldr1'"+foldr1' f (Chunk c0 cs0) = go c0 cs0+  where go c Empty         = S.foldr1' f c+        go c (Chunk c' cs) = S.foldr'  f (go c' cs) c+ -- --------------------------------------------------------------------- -- Special folds @@ -503,24 +528,22 @@ any :: (Word8 -> Bool) -> ByteString -> Bool any f = foldrChunks (\c rest -> S.any f c || rest) False {-# 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 f = foldrChunks (\c rest -> S.all f c && rest) True {-# INLINE all #-}--- todo fuse  -- | /O(n)/ 'maximum' returns the maximum value from a 'ByteString'-maximum :: ByteString -> Word8+maximum :: HasCallStack => ByteString -> Word8 maximum Empty        = errorEmptyList "maximum" maximum (Chunk c cs) = foldlChunks (\n c' -> n `max` S.maximum c')                                    (S.maximum c) cs {-# INLINE maximum #-}  -- | /O(n)/ 'minimum' returns the minimum value from a 'ByteString'-minimum :: ByteString -> Word8+minimum :: HasCallStack => ByteString -> Word8 minimum Empty        = errorEmptyList "minimum" minimum (Chunk c cs) = foldlChunks (\n c' -> n `min` S.minimum c')                                      (S.minimum c) cs@@ -596,7 +619,7 @@ -- Building ByteStrings  -- | 'scanl' is similar to 'foldl', but returns a list of successive--- reduced values from the left. This function will fuse.+-- reduced values from the left. -- -- > scanl f z [x1, x2, ...] == [z, z `f` x1, (z `f` x1) `f` x2, ...] --@@ -614,11 +637,49 @@     -- ^ input of length n     -> ByteString     -- ^ output of length n+1-scanl f z = snd . foldl k (z,singleton z)- where-    k (c,acc) a = let n = f c a in (n, acc `snoc` n)+scanl function = fmap (uncurry (flip snoc)) . mapAccumL (\x y -> (function x y, x)) {-# INLINE scanl #-} +-- | 'scanl1' is a variant of 'scanl' that has no starting value argument.+--+-- > scanl1 f [x1, x2, ...] == [x1, x1 `f` x2, ...]+--+-- @since 0.11.2.0+scanl1 :: (Word8 -> Word8 -> Word8) -> ByteString -> ByteString+scanl1 function byteStream = case uncons byteStream of+  Nothing -> Empty+  Just (firstByte, remainingBytes) -> scanl function firstByte remainingBytes++-- | 'scanr' is similar to 'foldr', but returns a list of successive+-- reduced values from the right.+--+-- > scanr f z [..., x{n-1}, xn] == [..., x{n-1} `f` (xn `f` z), xn `f` z, z]+--+-- Note that+--+-- > head (scanr f z xs) == foldr f z xs+-- > last (scanr f z xs) == z+--+-- @since 0.11.2.0+scanr+    :: (Word8 -> Word8 -> Word8)+    -- ^ element -> accumulator -> new accumulator+    -> Word8+    -- ^ starting value of accumulator+    -> ByteString+    -- ^ input of length n+    -> ByteString+    -- ^ output of length n+1+scanr function = fmap (uncurry cons) . mapAccumR (\x y -> (function y x, x))++-- | 'scanr1' is a variant of 'scanr' that has no starting value argument.+--+-- @since 0.11.2.0+scanr1 :: (Word8 -> Word8 -> Word8) -> ByteString -> ByteString+scanr1 function byteStream = case unsnoc byteStream of+  Nothing -> Empty+  Just (initialBytes, lastByte) -> scanr function lastByte initialBytes+ -- --------------------------------------------------------------------- -- Unfolds and replicates @@ -655,7 +716,7 @@ -- | 'cycle' ties a finite ByteString into a circular one, or equivalently, -- the infinite repetition of the original ByteString. ---cycle :: ByteString -> ByteString+cycle :: HasCallStack => ByteString -> ByteString cycle Empty = errorEmptyList "cycle" cycle cs    = cs' where cs' = foldrChunks Chunk cs' cs @@ -689,6 +750,28 @@             then Chunk (S.take (fromIntegral n) c) Empty             else Chunk c (take' (n - fromIntegral (S.length c)) cs) +-- | /O(c)/ @'takeEnd' n xs@ is equivalent to @'drop' ('length' xs - n) xs@.+-- Takes @n@ elements from end of bytestring.+--+-- >>> takeEnd 3 "abcdefg"+-- "efg"+-- >>> takeEnd 0 "abcdefg"+-- ""+-- >>> takeEnd 4 "abc"+-- "abc"+--+-- @since 0.11.2.0+takeEnd :: Int64 -> ByteString -> ByteString+takeEnd i _ | i <= 0 = Empty+takeEnd i cs0        = takeEnd' i cs0+  where takeEnd' 0 _         = Empty+        takeEnd' n cs        =+            snd $ foldrChunks takeTuple (n,Empty) cs+        takeTuple _ (0, cs)  = (0, cs)+        takeTuple c (n, cs)+            | n > fromIntegral (S.length c) = (n - fromIntegral (S.length c), Chunk c cs)+            | otherwise      = (0, Chunk (S.takeEnd (fromIntegral n) c) cs)+ -- | /O(n\/c)/ 'drop' @n xs@ returns the suffix of @xs@ after the first @n@ -- elements, or @[]@ if @n > 'length' xs@. drop  :: Int64 -> ByteString -> ByteString@@ -701,6 +784,57 @@             then Chunk (S.drop (fromIntegral n) c) cs             else drop' (n - fromIntegral (S.length c)) cs +-- | /O(n)/ @'dropEnd' n xs@ is equivalent to @'take' ('length' xs - n) xs@.+-- Drops @n@ elements from end of bytestring.+--+-- >>> dropEnd 3 "abcdefg"+-- "abcd"+-- >>> dropEnd 0 "abcdefg"+-- "abcdefg"+-- >>> dropEnd 4 "abc"+-- ""+--+-- @since 0.11.2.0+dropEnd :: Int64 -> ByteString -> ByteString+dropEnd i p | i <= 0 = p+dropEnd i p          = go D.empty p+  where go :: D.Deque -> ByteString -> ByteString+        go deque (Chunk c cs)+            | D.byteLength deque < i = go (D.snoc c deque) cs+            | otherwise              =+                  let (output, deque') = getOutput empty (D.snoc c deque)+                    in foldrChunks Chunk (go deque' cs) output+        go deque Empty               = fromDeque $ dropEndBytes deque i++        len c = fromIntegral (S.length c)++        -- get a `ByteString` from all the front chunks of the accumulating deque+        -- for which we know they won't be dropped+        getOutput :: ByteString -> D.Deque -> (ByteString, D.Deque)+        getOutput out deque = case D.popFront deque of+            Nothing                       -> (reverseChunks out, deque)+            Just (x, deque') | D.byteLength deque' >= i ->+                            getOutput (Chunk x out) deque'+            _ -> (reverseChunks out, deque)++        -- reverse a `ByteString`s chunks, keeping all internal `S.ByteString`s+        -- unchanged+        reverseChunks = foldlChunks (flip Chunk) empty++        -- drop n elements from the rear of the accumulating `deque`+        dropEndBytes :: D.Deque -> Int64 -> D.Deque+        dropEndBytes deque n = case D.popRear deque of+            Nothing                       -> deque+            Just (deque', x) | len x <= n -> dropEndBytes deque' (n - len x)+                             | otherwise  ->+                                D.snoc (S.dropEnd (fromIntegral n) x) deque'++        -- build a lazy ByteString from an accumulating `deque`+        fromDeque :: D.Deque -> ByteString+        fromDeque deque =+            List.foldr chunk Empty (D.front deque) `append`+            List.foldl' (flip chunk) Empty (D.rear deque)+ -- | /O(n\/c)/ 'splitAt' @n xs@ is equivalent to @('take' n xs, 'drop' n xs)@. splitAt :: Int64 -> ByteString -> (ByteString, ByteString) splitAt i cs0 | i <= 0 = (Empty, cs0)@@ -727,6 +861,27 @@             n | n < S.length c -> Chunk (S.take n c) Empty               | otherwise      -> Chunk c (takeWhile' cs) +-- | Returns the longest (possibly empty) suffix of elements+-- satisfying the predicate.+--+-- @'takeWhileEnd' p@ is equivalent to @'reverse' . 'takeWhile' p . 'reverse'@.+--+-- >>> {-# LANGUAGE OverloadedLists #-)+-- >>> takeWhileEnd even [1,2,3,4,6]+-- [4,6]+--+-- @since 0.11.2.0+takeWhileEnd :: (Word8 -> Bool) -> ByteString -> ByteString+takeWhileEnd f = takeWhileEnd'+  where takeWhileEnd' Empty = Empty+        takeWhileEnd' cs    =+            snd $ foldrChunks takeTuple (True,Empty) cs+        takeTuple _ (False, bs) = (False,bs)+        takeTuple c (True,bs)   =+           case S.takeWhileEnd f c of+                c' | S.length c' == S.length c -> (True, Chunk c bs)+                   | otherwise                 -> (False, fromStrict c' `append` bs)+ -- | Similar to 'P.dropWhile', -- drops the longest (possibly empty) prefix of elements -- satisfying the predicate and returns the remainder.@@ -738,6 +893,29 @@             n | n < S.length c -> Chunk (S.drop n c) cs               | otherwise      -> dropWhile' cs +-- | Similar to 'P.dropWhileEnd',+-- drops the longest (possibly empty) suffix of elements+-- satisfying the predicate and returns the remainder.+--+-- @'dropWhileEnd' p@ is equivalent to @'reverse' . 'dropWhile' p . 'reverse'@.+--+-- >>> {-# LANGUAGE OverloadedLists #-)+-- >>> dropWhileEnd even [1,2,3,4,6]+-- [1,2,3]+--+-- @since 0.11.2.0+dropWhileEnd :: (Word8 -> Bool) -> ByteString -> ByteString+dropWhileEnd f = go []+  where go acc (Chunk c cs)+            | f (S.last c) = go (c : acc) cs+            | otherwise    = List.foldl (flip Chunk) (go [] cs) (c : acc)+        go acc Empty       = dropEndBytes acc+        dropEndBytes []         = Empty+        dropEndBytes (x : xs)   =+            case S.dropWhileEnd f x of+                 x' | S.null x' -> dropEndBytes xs+                    | otherwise -> List.foldl' (flip Chunk) Empty (x' : xs)+ -- | Similar to 'P.break', -- returns the longest (possibly empty) prefix of elements which __do not__ -- satisfy the predicate and the remainder of the string.@@ -755,7 +933,29 @@               | otherwise      -> let (cs', cs'') = break' cs                                    in (Chunk c cs', cs'') ++-- | Returns the longest (possibly empty) suffix of elements which __do not__+-- satisfy the predicate and the remainder of the string. --+-- 'breakEnd' @p@ is equivalent to @'spanEnd' (not . p)@ and to @('takeWhileEnd' (not . p) &&& 'dropWhileEnd' (not . p))@.+--+-- @since 0.11.2.0+breakEnd :: (Word8 -> Bool) -> ByteString -> (ByteString, ByteString)+breakEnd  f = go []+  where go acc (Chunk c cs)+            | f (S.last c) = List.foldl (flip $ BF.first . Chunk) (go [] cs) (c : acc)+            | otherwise = go (c : acc) cs+        go acc Empty = dropEndBytes acc+        dropEndBytes [] = (Empty, Empty)+        dropEndBytes (x : xs) =+            case S.breakEnd f x of+                 (x', x'') | S.null x' -> let (y, y') = dropEndBytes xs+                                           in (y, y' `append` fromStrict x)+                           | otherwise ->+                                List.foldl' (flip $ BF.first . Chunk) (fromStrict x', fromStrict x'') xs+++-- -- TODO -- -- Add rules@@ -804,6 +1004,25 @@ span :: (Word8 -> Bool) -> ByteString -> (ByteString, ByteString) span p = break (not . p) +-- | Returns the longest (possibly empty) suffix of elements+-- satisfying the predicate and the remainder of the string.+--+-- 'spanEnd' @p@ is equivalent to @'breakEnd' (not . p)@ and to @('takeWhileEnd' p &&& 'dropWhileEnd' p)@.+--+-- We have+--+-- > spanEnd (not . isSpace) "x y z" == ("x y ", "z")+--+-- and+--+-- > spanEnd (not . isSpace) ps+-- >    ==+-- > let (x, y) = span (not . isSpace) (reverse ps) in (reverse y, reverse x)+--+-- @since 0.11.2.0+spanEnd :: (Word8 -> Bool) -> ByteString -> (ByteString, ByteString)+spanEnd p = breakEnd (not . p)+ -- | /O(n)/ Splits a 'ByteString' into components delimited by -- separators, where the predicate returns True for a separator element. -- The resulting components do not contain the separators.  Two adjacent@@ -898,13 +1117,13 @@ -- 'ByteString's and concatenates the list after interspersing the first -- argument between each element of the list. intercalate :: ByteString -> [ByteString] -> ByteString-intercalate s = concat . L.intersperse s+intercalate s = concat . List.intersperse s  -- --------------------------------------------------------------------- -- Indexing ByteStrings  -- | /O(c)/ 'ByteString' index (subscript) operator, starting from 0.-index :: ByteString -> Int64 -> Word8+index :: HasCallStack => ByteString -> Int64 -> Word8 index _  i | i < 0  = moduleError "index" ("negative index: " ++ show i) index cs0 i         = index' cs0 i   where index' Empty     n = moduleError "index" ("index too large: " ++ show n)@@ -968,7 +1187,7 @@ elemIndices :: Word8 -> ByteString -> [Int64] elemIndices w = elemIndices' 0   where elemIndices' _ Empty        = []-        elemIndices' n (Chunk c cs) = L.map ((+n).fromIntegral) (S.elemIndices w c)+        elemIndices' n (Chunk c cs) = List.map ((+n).fromIntegral) (S.elemIndices w c)                              ++ elemIndices' (n + fromIntegral (S.length c)) cs  -- | count returns the number of times its argument appears in the ByteString@@ -1025,7 +1244,7 @@ findIndices :: (Word8 -> Bool) -> ByteString -> [Int64] findIndices k = findIndices' 0   where findIndices' _ Empty        = []-        findIndices' n (Chunk c cs) = L.map ((+n).fromIntegral) (S.findIndices k c)+        findIndices' n (Chunk c cs) = List.map ((+n).fromIntegral) (S.findIndices k c)                              ++ findIndices' (n + fromIntegral (S.length c)) cs {-# INLINE findIndices #-} @@ -1192,7 +1411,7 @@ -- | /O(n)/ 'unzip' transforms a list of pairs of bytes into a pair of -- ByteStrings. Note that this performs two 'pack' operations. unzip :: [(Word8,Word8)] -> (ByteString,ByteString)-unzip ls = (pack (L.map fst ls), pack (L.map snd ls))+unzip ls = (pack (List.map fst ls), pack (List.map snd ls)) {-# INLINE unzip #-}  -- ---------------------------------------------------------------------@@ -1202,8 +1421,8 @@ inits :: ByteString -> [ByteString] inits = (Empty :) . inits'   where inits' Empty        = []-        inits' (Chunk c cs) = L.map (`Chunk` Empty) (L.tail (S.inits c))-                           ++ L.map (Chunk c) (inits' cs)+        inits' (Chunk c cs) = List.map (`Chunk` Empty) (List.tail (S.inits c))+                           ++ List.map (Chunk c) (inits' cs)  -- | /O(n)/ Return all final segments of the given 'ByteString', longest first. tails :: ByteString -> [ByteString]@@ -1395,22 +1614,22 @@  -- Common up near identical calls to `error' to reduce the number -- constant strings created when compiled:-errorEmptyList :: String -> a+errorEmptyList :: HasCallStack => String -> a errorEmptyList fun = moduleError fun "empty ByteString" {-# NOINLINE errorEmptyList #-} -moduleError :: String -> String -> a+moduleError :: HasCallStack => String -> String -> a moduleError fun msg = error ("Data.ByteString.Lazy." ++ fun ++ ':':' ':msg) {-# NOINLINE moduleError #-}   -- reverse a list of non-empty chunks into a lazy ByteString revNonEmptyChunks :: [P.ByteString] -> ByteString-revNonEmptyChunks = L.foldl' (flip Chunk) Empty+revNonEmptyChunks = List.foldl' (flip Chunk) Empty  -- reverse a list of possibly-empty chunks into a lazy ByteString revChunks :: [P.ByteString] -> ByteString-revChunks = L.foldl' (flip chunk) Empty+revChunks = List.foldl' (flip chunk) Empty  -- $IOChunk --
Data/ByteString/Lazy/Char8.hs view
@@ -1,8 +1,6 @@-{-# LANGUAGE CPP, BangPatterns #-}+{-# LANGUAGE BangPatterns #-} {-# OPTIONS_HADDOCK prune #-}-#if __GLASGOW_HASKELL__ >= 701 {-# LANGUAGE Trustworthy #-}-#endif  -- | -- Module      : Data.ByteString.Lazy.Char8@@ -33,142 +31,150 @@ module Data.ByteString.Lazy.Char8 (          -- * The @ByteString@ type-        ByteString,             -- instances: Eq, Ord, Show, Read, Data, Typeable+        ByteString,          -- * Introducing and eliminating 'ByteString's-        empty,                  -- :: ByteString-        singleton,              -- :: Char   -> ByteString-        pack,                   -- :: String -> ByteString-        unpack,                 -- :: ByteString -> String-        fromChunks,             -- :: [Strict.ByteString] -> ByteString-        toChunks,               -- :: ByteString -> [Strict.ByteString]-        fromStrict,             -- :: Strict.ByteString -> ByteString-        toStrict,               -- :: ByteString -> Strict.ByteString+        empty,+        singleton,+        pack,+        unpack,+        fromChunks,+        toChunks,+        fromStrict,+        toStrict,          -- * Basic interface-        cons,                   -- :: Char -> ByteString -> ByteString-        cons',                  -- :: Char -> ByteString -> ByteString-        snoc,                   -- :: ByteString -> Char -> ByteString-        append,                 -- :: ByteString -> ByteString -> ByteString-        head,                   -- :: ByteString -> Char-        uncons,                 -- :: ByteString -> Maybe (Char, ByteString)-        last,                   -- :: ByteString -> Char-        tail,                   -- :: ByteString -> ByteString-        unsnoc,                 -- :: ByteString -> Maybe (ByteString, Char)-        init,                   -- :: ByteString -> ByteString-        null,                   -- :: ByteString -> Bool-        length,                 -- :: ByteString -> Int64+        cons,+        cons',+        snoc,+        append,+        head,+        uncons,+        last,+        tail,+        unsnoc,+        init,+        null,+        length,          -- * Transforming ByteStrings-        map,                    -- :: (Char -> Char) -> ByteString -> ByteString-        reverse,                -- :: ByteString -> ByteString-        intersperse,            -- :: Char -> ByteString -> ByteString-        intercalate,            -- :: ByteString -> [ByteString] -> ByteString-        transpose,              -- :: [ByteString] -> [ByteString]+        map,+        reverse,+        intersperse,+        intercalate,+        transpose,          -- * Reducing 'ByteString's (folds)-        foldl,                  -- :: (a -> Char -> a) -> a -> ByteString -> a-        foldl',                 -- :: (a -> Char -> a) -> a -> ByteString -> a-        foldl1,                 -- :: (Char -> Char -> Char) -> ByteString -> Char-        foldl1',                -- :: (Char -> Char -> Char) -> ByteString -> Char-        foldr,                  -- :: (Char -> a -> a) -> a -> ByteString -> a-        foldr1,                 -- :: (Char -> Char -> Char) -> ByteString -> Char+        foldl,+        foldl',+        foldl1,+        foldl1',+        foldr,+        foldr',+        foldr1,+        foldr1',          -- ** Special folds-        concat,                 -- :: [ByteString] -> ByteString-        concatMap,              -- :: (Char -> ByteString) -> ByteString -> ByteString-        any,                    -- :: (Char -> Bool) -> ByteString -> Bool-        all,                    -- :: (Char -> Bool) -> ByteString -> Bool-        maximum,                -- :: ByteString -> Char-        minimum,                -- :: ByteString -> Char-        compareLength,          -- :: ByteString -> Int -> Ordering+        concat,+        concatMap,+        any,+        all,+        maximum,+        minimum,+        compareLength,          -- * Building ByteStrings         -- ** Scans-        scanl,                  -- :: (Char -> Char -> Char) -> Char -> ByteString -> ByteString---      scanl1,                 -- :: (Char -> Char -> Char) -> ByteString -> ByteString---      scanr,                  -- :: (Char -> Char -> Char) -> Char -> ByteString -> ByteString---      scanr1,                 -- :: (Char -> Char -> Char) -> ByteString -> ByteString+        scanl,+        scanl1,+        scanr,+        scanr1,          -- ** Accumulating maps-        mapAccumL,              -- :: (acc -> Char -> (acc, Char)) -> acc -> ByteString -> (acc, ByteString)-        mapAccumR,              -- :: (acc -> Char -> (acc, Char)) -> acc -> ByteString -> (acc, ByteString)+        mapAccumL,+        mapAccumR,          -- ** Infinite ByteStrings-        repeat,                 -- :: Char -> ByteString-        replicate,              -- :: Int64 -> Char -> ByteString-        cycle,                  -- :: ByteString -> ByteString-        iterate,                -- :: (Char -> Char) -> Char -> ByteString+        repeat,+        replicate,+        cycle,+        iterate,          -- ** Unfolding ByteStrings-        unfoldr,                -- :: (a -> Maybe (Char, a)) -> a -> ByteString+        unfoldr,          -- * Substrings          -- ** Breaking strings-        take,                   -- :: Int64 -> ByteString -> ByteString-        drop,                   -- :: Int64 -> ByteString -> ByteString-        splitAt,                -- :: Int64 -> ByteString -> (ByteString, ByteString)-        takeWhile,              -- :: (Char -> Bool) -> ByteString -> ByteString-        dropWhile,              -- :: (Char -> Bool) -> ByteString -> ByteString-        span,                   -- :: (Char -> Bool) -> ByteString -> (ByteString, ByteString)-        break,                  -- :: (Char -> Bool) -> ByteString -> (ByteString, ByteString)-        group,                  -- :: ByteString -> [ByteString]-        groupBy,                -- :: (Char -> Char -> Bool) -> ByteString -> [ByteString]-        inits,                  -- :: ByteString -> [ByteString]-        tails,                  -- :: ByteString -> [ByteString]-        stripPrefix,            -- :: ByteString -> ByteString -> Maybe ByteString-        stripSuffix,            -- :: ByteString -> ByteString -> Maybe ByteString+        take,+        takeEnd,+        drop,+        dropEnd,+        splitAt,+        takeWhile,+        takeWhileEnd,+        dropWhile,+        dropWhileEnd,+        span,+        spanEnd,+        break,+        breakEnd,+        group,+        groupBy,+        inits,+        tails,+        stripPrefix,+        stripSuffix,          -- ** Breaking into many substrings-        split,                  -- :: Char -> ByteString -> [ByteString]-        splitWith,              -- :: (Char -> Bool) -> ByteString -> [ByteString]+        split,+        splitWith,          -- ** Breaking into lines and words-        lines,                  -- :: ByteString -> [ByteString]-        words,                  -- :: ByteString -> [ByteString]-        unlines,                -- :: [ByteString] -> ByteString-        unwords,                -- :: ByteString -> [ByteString]+        lines,+        words,+        unlines,+        unwords,          -- * Predicates-        isPrefixOf,             -- :: ByteString -> ByteString -> Bool-        isSuffixOf,             -- :: ByteString -> ByteString -> Bool+        isPrefixOf,+        isSuffixOf,          -- * Searching ByteStrings          -- ** Searching by equality-        elem,                   -- :: Char -> ByteString -> Bool-        notElem,                -- :: Char -> ByteString -> Bool+        elem,+        notElem,          -- ** Searching with a predicate-        find,                   -- :: (Char -> Bool) -> ByteString -> Maybe Char-        filter,                 -- :: (Char -> Bool) -> ByteString -> ByteString-        partition,              -- :: (Char -> Bool) -> ByteString -> (ByteString, ByteString)+        find,+        filter,+        partition,          -- * Indexing ByteStrings-        index,                  -- :: ByteString -> Int64 -> Char-        indexMaybe,             -- :: ByteString -> Int64 -> Maybe Char-        (!?),                   -- :: ByteString -> Int64 -> Maybe Char-        elemIndex,              -- :: Char -> ByteString -> Maybe Int64-        elemIndexEnd,           -- :: Char -> ByteString -> Maybe Int64-        elemIndices,            -- :: Char -> ByteString -> [Int64]-        findIndex,              -- :: (Char -> Bool) -> ByteString -> Maybe Int64-        findIndexEnd,           -- :: (Char -> Bool) -> ByteString -> Maybe Int64-        findIndices,            -- :: (Char -> Bool) -> ByteString -> [Int64]-        count,                  -- :: Char -> ByteString -> Int64+        index,+        indexMaybe,+        (!?),+        elemIndex,+        elemIndexEnd,+        elemIndices,+        findIndex,+        findIndexEnd,+        findIndices,+        count,          -- * Zipping and unzipping ByteStrings-        zip,                    -- :: ByteString -> ByteString -> [(Char,Char)]-        zipWith,                -- :: (Char -> Char -> c) -> ByteString -> ByteString -> [c]-        packZipWith,            -- :: (Char -> Char -> Char) -> ByteString -> ByteString -> ByteString-        unzip,                  -- :: [(Char,Char)] -> (ByteString,ByteString)+        zip,+        zipWith,+        packZipWith,+        unzip,          -- * Ordered ByteStrings---        sort,                   -- :: ByteString -> ByteString+--        sort,          -- * Low level conversions         -- ** Copying ByteStrings-        copy,                   -- :: ByteString -> ByteString+        copy,          -- * Reading from ByteStrings         readInt,@@ -180,24 +186,24 @@         -- newline mode is considered a flaw and may be changed in a future version.          -- ** Standard input and output-        getContents,            -- :: IO ByteString-        putStr,                 -- :: ByteString -> IO ()-        putStrLn,               -- :: ByteString -> IO ()-        interact,               -- :: (ByteString -> ByteString) -> IO ()+        getContents,+        putStr,+        putStrLn,+        interact,          -- ** Files-        readFile,               -- :: FilePath -> IO ByteString-        writeFile,              -- :: FilePath -> ByteString -> IO ()-        appendFile,             -- :: FilePath -> ByteString -> IO ()+        readFile,+        writeFile,+        appendFile,          -- ** I\/O with Handles-        hGetContents,           -- :: Handle -> IO ByteString-        hGet,                   -- :: Handle -> Int64 -> IO ByteString-        hGetNonBlocking,        -- :: Handle -> Int64 -> IO ByteString-        hPut,                   -- :: Handle -> ByteString -> IO ()-        hPutNonBlocking,        -- :: Handle -> ByteString -> IO ByteString-        hPutStr,                -- :: Handle -> ByteString -> IO ()-        hPutStrLn,              -- :: Handle -> ByteString -> IO ()+        hGetContents,+        hGet,+        hGetNonBlocking,+        hPut,+        hPutNonBlocking,+        hPutStr,+        hPutStrLn,    ) where @@ -205,7 +211,7 @@ import Data.ByteString.Lazy         (fromChunks, toChunks         ,empty,null,length,tail,init,append,reverse,transpose,cycle-        ,concat,take,drop,splitAt,intercalate+        ,concat,take,takeEnd,drop,dropEnd,splitAt,intercalate         ,isPrefixOf,isSuffixOf,group,inits,tails,copy         ,stripPrefix,stripSuffix         ,hGetContents, hGet, hPut, getContents@@ -222,17 +228,13 @@  import Data.ByteString.Internal (w2c, c2w, isSpaceWord8) -#if !(MIN_VERSION_base(4,8,0))-import Control.Applicative ((<$>))-#endif- import Data.Int (Int64) import qualified Data.List as List  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-        ,unwords,words,maximum,minimum,all,concatMap,scanl,scanl1,foldl1,foldr1+        ,unwords,words,maximum,minimum,all,concatMap,scanl,scanl1,scanr,scanr1,foldl1,foldr1         ,readFile,writeFile,appendFile,replicate,getContents,getLine,putStr,putStrLn         ,zip,zipWith,unzip,notElem,repeat,iterate,interact,cycle) @@ -341,6 +343,12 @@ foldr f = L.foldr (f . w2c) {-# INLINE foldr #-} +-- | 'foldr'' is like 'foldr', but strict in the accumulator.+--+-- @since 0.11.2.0+foldr' :: (Char -> a -> a) -> a -> ByteString -> a+foldr' f = L.foldr' (f . w2c)+ -- | 'foldl1' is a variant of 'foldl' that has no starting value -- argument, and thus must be applied to non-empty 'ByteString's. foldl1 :: (Char -> Char -> Char) -> ByteString -> Char@@ -357,6 +365,12 @@ foldr1 f ps = w2c (L.foldr1 (\x y -> c2w (f (w2c x) (w2c y))) ps) {-# INLINE foldr1 #-} +-- | 'foldr1'' is like 'foldr1', but strict in the accumulator.+--+-- @since 0.11.2.0+foldr1' :: (Char -> Char -> Char) -> ByteString -> Char+foldr1' f ps = w2c (L.foldr1' (\x y -> c2w (f (w2c x) (w2c y))) ps)+ -- | Map a function over a 'ByteString' and concatenate the results concatMap :: (Char -> ByteString) -> ByteString -> ByteString concatMap f = L.concatMap (f . w2c)@@ -388,7 +402,7 @@ -- Building ByteStrings  -- | 'scanl' is similar to 'foldl', but returns a list of successive--- reduced values from the left. This function will fuse.+-- reduced values from the left. -- -- > scanl f z [x1, x2, ...] == [z, z `f` x1, (z `f` x1) `f` x2, ...] --@@ -398,6 +412,45 @@ scanl :: (Char -> Char -> Char) -> Char -> ByteString -> ByteString scanl f z = L.scanl (\a b -> c2w (f (w2c a) (w2c b))) (c2w z) +-- | 'scanl1' is a variant of 'scanl' that has no starting value argument.+--+-- > scanl1 f [x1, x2, ...] == [x1, x1 `f` x2, ...]+--+-- @since 0.11.2.0+scanl1 :: (Char -> Char -> Char) -> ByteString -> ByteString+scanl1 f = L.scanl1 f'+  where f' accumulator value = c2w (f (w2c accumulator) (w2c value))++-- | 'scanr' is similar to 'foldr', but returns a list of successive+-- reduced values from the right.+--+-- > scanr f z [..., x{n-1}, xn] == [..., x{n-1} `f` (xn `f` z), xn `f` z, z]+--+-- Note that+--+-- > head (scanr f z xs) == foldr f z xs+-- > last (scanr f z xs) == z+--+-- @since 0.11.2.0+scanr+    :: (Char -> Char -> Char)+    -- ^ element -> accumulator -> new accumulator+    -> Char+    -- ^ starting value of accumulator+    -> ByteString+    -- ^ input of length n+    -> ByteString+    -- ^ output of length n+1+scanr f = L.scanr f' . c2w+  where f' accumulator value = c2w (f (w2c accumulator) (w2c value))++-- | 'scanr1' is a variant of 'scanr' that has no starting value argument.+--+-- @since 0.11.2.0+scanr1 :: (Char -> Char -> Char) -> ByteString -> ByteString+scanr1 f = L.scanr1 f'+  where f' accumulator value = c2w (f (w2c accumulator) (w2c value))+ -- | The 'mapAccumL' function behaves like a combination of 'map' and -- 'foldl'; it applies a function to each element of a ByteString, -- passing an accumulating parameter from left to right, and returning a@@ -455,21 +508,67 @@ takeWhile f = L.takeWhile (f . w2c) {-# INLINE takeWhile #-} +-- | Returns the longest (possibly empty) suffix of elements+-- satisfying the predicate.+--+-- @'takeWhileEnd' p@ is equivalent to @'reverse' . 'takeWhile' p . 'reverse'@.+--+-- @since 0.11.2.0+takeWhileEnd :: (Char -> Bool) -> ByteString -> ByteString+takeWhileEnd f = L.takeWhileEnd (f . w2c)+{-# INLINE takeWhileEnd #-}+ -- | 'dropWhile' @p xs@ returns the suffix remaining after 'takeWhile' @p xs@. dropWhile :: (Char -> Bool) -> ByteString -> ByteString dropWhile f = L.dropWhile (f . w2c) {-# INLINE dropWhile #-} +-- | Similar to 'P.dropWhileEnd',+-- drops the longest (possibly empty) suffix of elements+-- satisfying the predicate and returns the remainder.+--+-- @'dropWhileEnd' p@ is equivalent to @'reverse' . 'dropWhile' p . 'reverse'@.+--+-- @since 0.11.2.0+dropWhileEnd :: (Char -> Bool) -> ByteString -> ByteString+dropWhileEnd f = L.dropWhileEnd (f . w2c)+{-# INLINE dropWhileEnd #-}+ -- | 'break' @p@ is equivalent to @'span' ('not' . p)@. break :: (Char -> Bool) -> ByteString -> (ByteString, ByteString) break f = L.break (f . w2c) {-# INLINE break #-} +-- | 'breakEnd' behaves like 'break' but from the end of the 'ByteString'+--+-- breakEnd p == spanEnd (not.p)+--+-- @since 0.11.2.0+breakEnd :: (Char -> Bool) -> ByteString -> (ByteString, ByteString)+breakEnd f = L.breakEnd (f . w2c)+{-# INLINE breakEnd #-}+ -- | 'span' @p xs@ breaks the ByteString into two segments. It is -- equivalent to @('takeWhile' p xs, 'dropWhile' p xs)@ span :: (Char -> Bool) -> ByteString -> (ByteString, ByteString) span f = L.span (f . w2c) {-# INLINE span #-}++-- | 'spanEnd' behaves like 'span' but from the end of the 'ByteString'.+-- We have+--+-- > spanEnd (not.isSpace) "x y z" == ("x y ","z")+--+-- and+--+-- > spanEnd (not . isSpace) ps+-- >    ==+-- > let (x,y) = span (not.isSpace) (reverse ps) in (reverse y, reverse x)+--+-- @since 0.11.2.0+spanEnd :: (Char -> Bool) -> ByteString -> (ByteString, ByteString)+spanEnd f = L.spanEnd (f . w2c)+{-# INLINE spanEnd #-}  {- -- | 'breakChar' breaks its ByteString argument at the first occurence
Data/ByteString/Lazy/Internal.hs view
@@ -1,10 +1,9 @@ {-# LANGUAGE CPP #-} {-# LANGUAGE BangPatterns #-} {-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE DeriveLift #-} {-# LANGUAGE TypeFamilies #-}-#if __GLASGOW_HASKELL__ >= 703 {-# LANGUAGE Unsafe #-}-#endif {-# OPTIONS_HADDOCK not-home #-}  -- |@@ -25,7 +24,8 @@ module Data.ByteString.Lazy.Internal (          -- * The lazy @ByteString@ type and representation-        ByteString(..),     -- instances: Eq, Ord, Show, Read, Data, Typeable+        ByteString(..),+        LazyByteString,         chunk,         foldrChunks,         foldlChunks,@@ -52,20 +52,15 @@ import qualified Data.ByteString.Internal as S  import Data.Word (Word8)-import Foreign.ForeignPtr (withForeignPtr) import Foreign.Ptr (plusPtr) import Foreign.Storable (Storable(sizeOf))  #if MIN_VERSION_base(4,13,0) import Data.Semigroup   (Semigroup (sconcat, stimes))-import Data.List.NonEmpty (NonEmpty ((:|)))-#elif MIN_VERSION_base(4,9,0)+#else import Data.Semigroup   (Semigroup ((<>), sconcat, stimes))-import Data.List.NonEmpty (NonEmpty ((:|))) #endif-#if !(MIN_VERSION_base(4,8,0))-import Data.Monoid      (Monoid(..))-#endif+import Data.List.NonEmpty (NonEmpty ((:|))) import Control.DeepSeq  (NFData, rnf)  import Data.String      (IsString(..))@@ -73,10 +68,10 @@ import Data.Typeable            (Typeable) import Data.Data                (Data(..), mkNoRepType) -#if MIN_VERSION_base(4,7,0) import GHC.Exts                 (IsList(..))-#endif +import qualified Language.Haskell.TH.Syntax as TH+ -- | A space-efficient representation of a 'Word8' vector, supporting many -- efficient operations. --@@ -85,29 +80,28 @@ -- 8-bit characters. -- data ByteString = Empty | Chunk {-# UNPACK #-} !S.ByteString ByteString-    deriving (Typeable)+    deriving (Typeable, TH.Lift) -- See 'invariant' function later in this module for internal invariants. +-- | Type synonym for the lazy flavour of 'ByteString'.+--+-- @since 0.11.2.0+type LazyByteString = ByteString+ instance Eq  ByteString where     (==)    = eq  instance Ord ByteString where     compare = cmp -#if MIN_VERSION_base(4,9,0) instance Semigroup ByteString where     (<>)    = append     sconcat (b:|bs) = concat (b:bs)-    stimes = times-#endif+    stimes  = times  instance Monoid ByteString where     mempty  = Empty-#if MIN_VERSION_base(4,9,0)     mappend = (<>)-#else-    mappend = append-#endif     mconcat = concat  instance NFData ByteString where@@ -120,13 +114,11 @@ instance Read ByteString where     readsPrec p str = [ (packChars x, y) | (x, y) <- readsPrec p str ] -#if MIN_VERSION_base(4,7,0) -- | @since 0.10.12.0 instance IsList ByteString where   type Item ByteString = Word8   fromList = packBytes   toList   = unpackBytes-#endif  -- | Beware: 'fromString' truncates multi-byte characters to octets. -- e.g. "枯朶に烏のとまりけり秋の暮" becomes �6k�nh~�Q��n�@@ -143,7 +135,6 @@ -- Packing and unpacking from lists  packBytes :: [Word8] -> ByteString-packBytes [] = Empty packBytes cs0 =     packChunks 32 cs0   where@@ -152,7 +143,6 @@       (bs, cs') -> Chunk bs (packChunks (min (n * 2) smallChunkSize) cs')  packChars :: [Char] -> ByteString-packChars [] = Empty packChars cs0 = packChunks 32 cs0   where     packChunks n cs = case S.packUptoLenChars n cs of@@ -275,7 +265,6 @@     to []               = Empty     to (cs:css)         = go cs css -#if MIN_VERSION_base(4,9,0) -- | Repeats the given ByteString n times. times :: Integral a => a -> ByteString -> ByteString times 0 _ = Empty@@ -287,7 +276,6 @@   where     go Empty = times (n-1) lbs0     go (Chunk c cs) = Chunk c (go cs)-#endif  ------------------------------------------------------------------------ -- Conversions@@ -331,7 +319,7 @@     goCopy Empty                    !_   = return ()     goCopy (Chunk (S.BS _  0  ) cs) !ptr = goCopy cs ptr     goCopy (Chunk (S.BS fp len) cs) !ptr =-      withForeignPtr fp $ \p -> do+      S.unsafeWithForeignPtr fp $ \p -> do         S.memcpy ptr p len         goCopy cs (ptr `plusPtr` len) -- See the comment on Data.ByteString.Internal.concat for some background on
+ Data/ByteString/Lazy/Internal/Deque.hs view
@@ -0,0 +1,65 @@+{- |+ A Deque used for accumulating `S.ByteString`s in `Data.ByteString.Lazy.dropEnd`.+-}+module Data.ByteString.Lazy.Internal.Deque (+    Deque (..),+    empty,+    null,+    cons,+    snoc,+    popFront,+    popRear,+) where++import qualified Data.ByteString as S+import Data.Int (Int64)+import Prelude hiding (head, length, null)++-- A `S.ByteString` Deque used as an accumulator for lazy+-- Bytestring operations+data Deque = Deque+    { front :: [S.ByteString]+    , rear :: [S.ByteString]+    , -- | Total length in bytes+      byteLength :: !Int64+    }++-- An empty Deque+empty :: Deque+empty = Deque [] [] 0++-- Is the `Deque` empty?+-- O(1)+null :: Deque -> Bool+null deque = byteLength deque == 0++-- Add a `S.ByteString` to the front of the `Deque`+-- O(1)+cons :: S.ByteString -> Deque -> Deque+cons x (Deque fs rs acc) = Deque (x : fs) rs (acc + len x)++-- Add a `S.ByteString` to the rear of the `Deque`+-- O(1)+snoc :: S.ByteString -> Deque -> Deque+snoc x (Deque fs rs acc) = Deque fs (x : rs) (acc + len x)++len :: S.ByteString -> Int64+len x = fromIntegral $ S.length x++-- Pop a `S.ByteString` from the front of the `Deque`+-- Returns the bytestring and the updated Deque, or Nothing if the Deque is empty+-- O(1) , occasionally O(n)+popFront :: Deque -> Maybe (S.ByteString, Deque)+popFront (Deque [] rs acc) = case reverse rs of+    [] -> Nothing+    x : xs -> Just (x, Deque xs [] (acc - len x))+popFront (Deque (x : xs) rs acc) = Just (x, Deque xs rs (acc - len x))++-- Pop a `S.ByteString` from the rear of the `Deque`+-- Returns the bytestring and the updated Deque, or Nothing if the Deque is empty+-- O(1) , occasionally O(n)+popRear :: Deque -> Maybe (Deque, S.ByteString)+popRear (Deque fs [] acc) = case reverse fs of+    [] -> Nothing+    x : xs -> Just (Deque [] xs (acc - len x), x)+popRear (Deque fs (x : xs) acc) = Just (Deque fs xs (acc - len x), x)
Data/ByteString/Short.hs view
@@ -1,7 +1,4 @@-{-# LANGUAGE CPP #-}-#if __GLASGOW_HASKELL__ >= 701 {-# LANGUAGE Trustworthy #-}-#endif  -- | -- Module      : Data.ByteString.Short
Data/ByteString/Short/Internal.hs view
@@ -3,9 +3,8 @@              UnliftedFFITypes #-} {-# LANGUAGE TypeFamilies #-} {-# OPTIONS_GHC -fno-warn-name-shadowing #-}-#if __GLASGOW_HASKELL__ >= 703 {-# LANGUAGE Unsafe #-}-#endif+{-# LANGUAGE TemplateHaskellQuotes #-} {-# OPTIONS_HADDOCK not-home #-}  -- |@@ -46,46 +45,31 @@     useAsCStringLen   ) where -import Data.ByteString.Internal (ByteString(..), accursedUnutterablePerformIO, c_strlen)+import Data.ByteString.Internal (ByteString(..), accursedUnutterablePerformIO)+import qualified Data.ByteString.Internal as BS  import Data.Typeable    (Typeable) import Data.Data        (Data(..), mkNoRepType)-#if MIN_VERSION_base(4,9,0) import Data.Semigroup   (Semigroup((<>)))-#endif import Data.Monoid      (Monoid(..)) import Data.String      (IsString(..)) import Control.DeepSeq  (NFData(..)) import qualified Data.List as List (length) import Foreign.C.String (CString, CStringLen)-#if MIN_VERSION_base(4,7,0) import Foreign.C.Types  (CSize(..), CInt(..))-#elif MIN_VERSION_base(4,4,0)-import Foreign.C.Types  (CSize(..), CInt(..), CLong(..))-#else-import Foreign.C.Types  (CSize, CInt, CLong)-#endif import Foreign.Marshal.Alloc (allocaBytes) import Foreign.ForeignPtr (touchForeignPtr)-#if MIN_VERSION_base(4,5,0) import Foreign.ForeignPtr.Unsafe (unsafeForeignPtrToPtr)-#else-import Foreign.ForeignPtr (unsafeForeignPtrToPtr)-#endif import Foreign.Storable (pokeByteOff) -#if MIN_VERSION_base(4,5,0) import qualified GHC.Exts-#endif import GHC.Exts ( Int(I#), Int#, Ptr(Ptr), Addr#, Char(C#)                 , State#, RealWorld                 , ByteArray#, MutableByteArray#                 , newByteArray#-#if MIN_VERSION_base(4,6,0)                 , newPinnedByteArray#                 , byteArrayContents#                 , unsafeCoerce#-#endif #if MIN_VERSION_base(4,10,0)                 , isByteArrayPinned#                 , isTrue#@@ -95,12 +79,9 @@                 , writeWord8Array#, writeCharArray#                 , unsafeFreezeByteArray# ) import GHC.IO-#if MIN_VERSION_base(4,6,0) import GHC.ForeignPtr (ForeignPtr(ForeignPtr), ForeignPtrContents(PlainPtr))-#else-import GHC.ForeignPtr (mallocPlainForeignPtrBytes)-#endif import GHC.ST         (ST(ST), runST)+import GHC.Stack.Types (HasCallStack) import GHC.Word  import Prelude ( Eq(..), Ord(..), Ordering(..), Read(..), Show(..)@@ -111,6 +92,9 @@                , return                , Maybe(..) ) +import qualified Language.Haskell.TH.Lib as TH+import qualified Language.Haskell.TH.Syntax as TH+ -- | A compact representation of a 'Word8' vector. -- -- It has a lower memory overhead than a 'ByteString' and does not@@ -127,6 +111,28 @@ data ShortByteString = SBS ByteArray#     deriving Typeable +-- | @since 0.11.2.0+instance TH.Lift ShortByteString where+#if MIN_VERSION_template_haskell(2,16,0)+  lift sbs = [| unsafePackLenLiteral |]+    `TH.appE` TH.litE (TH.integerL (fromIntegral len))+    `TH.appE` TH.litE (TH.BytesPrimL $ TH.Bytes ptr 0 (fromIntegral len))+    where+      BS ptr len = fromShort sbs+#else+  lift sbs = [| unsafePackLenLiteral |]+    `TH.appE` TH.litE (TH.integerL (fromIntegral len))+    `TH.appE` TH.litE (TH.StringPrimL $ BS.unpackBytes bs)+    where+      bs@(BS _ len) = fromShort sbs+#endif++#if MIN_VERSION_template_haskell(2,17,0)+  liftTyped = TH.unsafeCodeCoerce . TH.lift+#elif MIN_VERSION_template_haskell(2,16,0)+  liftTyped = TH.unsafeTExpCoerce . TH.lift+#endif+ -- The ByteArray# representation is always word sized and aligned but with a -- known byte length. Our representation choice for ShortByteString is to leave -- the 0--3 trailing bytes undefined. This means we can use word-sized writes,@@ -139,18 +145,12 @@ instance Ord ShortByteString where     compare = compareBytes -#if MIN_VERSION_base(4,9,0) instance Semigroup ShortByteString where     (<>)    = append-#endif  instance Monoid ShortByteString where     mempty  = empty-#if MIN_VERSION_base(4,9,0)     mappend = (<>)-#else-    mappend = append-#endif     mconcat = concat  instance NFData ShortByteString where@@ -162,13 +162,11 @@ instance Read ShortByteString where     readsPrec p str = [ (packChars x, y) | (x, y) <- readsPrec p str ] -#if MIN_VERSION_base(4,7,0) -- | @since 0.10.12.0 instance GHC.Exts.IsList ShortByteString where   type Item ShortByteString = Word8   fromList = packBytes   toList   = unpackBytes-#endif  -- | Beware: 'fromString' truncates multi-byte characters to octets. -- e.g. "枯朶に烏のとまりけり秋の暮" becomes �6k�nh~�Q��n�@@ -197,7 +195,7 @@ null sbs = length sbs == 0  -- | /O(1)/ 'ShortByteString' index (subscript) operator, starting from 0.-index :: ShortByteString -> Int -> Word8+index :: HasCallStack => ShortByteString -> Int -> Word8 index sbs i   | i >= 0 && i < length sbs = unsafeIndex sbs i   | otherwise                = indexError sbs i@@ -225,11 +223,15 @@ unsafeIndex :: ShortByteString -> Int -> Word8 unsafeIndex sbs = indexWord8Array (asBA sbs) -indexError :: ShortByteString -> Int -> a+indexError :: HasCallStack => ShortByteString -> Int -> a indexError sbs i =   error $ "Data.ByteString.Short.index: error in array index; " ++ show i        ++ " not in range [0.." ++ show (length sbs) ++ ")" +-- | @since 0.11.2.0+unsafePackLenLiteral :: Int -> Addr# -> ShortByteString+unsafePackLenLiteral len addr# =+    accursedUnutterablePerformIO $ createFromPtr (Ptr addr#) len  ------------------------------------------------------------------------ -- Internal utils@@ -281,23 +283,12 @@  fromShortIO :: ShortByteString -> IO ByteString fromShortIO sbs = do-#if MIN_VERSION_base(4,6,0)     let len = length sbs     mba@(MBA# mba#) <- stToIO (newPinnedByteArray len)     stToIO (copyByteArray (asBA sbs) 0 mba 0 len)     let fp = ForeignPtr (byteArrayContents# (unsafeCoerce# mba#))                         (PlainPtr mba#)     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#-    let len = length sbs-    fptr <- mallocPlainForeignPtrBytes len-    let ptr = unsafeForeignPtrToPtr fptr-    stToIO (copyByteArrayToAddr (asBA sbs) 0 ptr len)-    touchForeignPtr fptr-    return (BS fptr len)-#endif   ------------------------------------------------------------------------@@ -491,12 +482,10 @@     ST $ \s -> case newByteArray# len# s of                  (# s, mba# #) -> (# s, MBA# mba# #) -#if MIN_VERSION_base(4,6,0) newPinnedByteArray :: Int -> ST s (MBA s) newPinnedByteArray (I# len#) =     ST $ \s -> case newPinnedByteArray# len# s of                  (# s, mba# #) -> (# s, MBA# mba# #)-#endif  unsafeFreezeByteArray :: MBA s -> ST s BA unsafeFreezeByteArray (MBA# mba#) =@@ -558,78 +547,10 @@                      -> Int#                      -> State# s -> State# s -#if MIN_VERSION_base(4,7,0)---- These exist as real primops in ghc-7.8, and for before that we use--- FFI to C memcpy. copyAddrToByteArray# = GHC.Exts.copyAddrToByteArray# copyByteArrayToAddr# = GHC.Exts.copyByteArrayToAddr#--#else--copyAddrToByteArray# src dst dst_off len =-  unIO_ (memcpy_AddrToByteArray dst (csize dst_off) src 0 (csize len))--copyAddrToByteArray0 :: Addr# -> MutableByteArray# s -> Int#-                     -> State# RealWorld -> State# RealWorld-copyAddrToByteArray0 src dst len =-  unIO_ (memcpy_AddrToByteArray0 dst src (csize len))--{-# INLINE [0] copyAddrToByteArray# #-}-{-# RULES "copyAddrToByteArray# dst_off=0"-      forall src dst len s.-          copyAddrToByteArray# src dst 0# len s-        = copyAddrToByteArray0 src dst    len s  #-}--foreign import ccall unsafe "fpstring.h fps_memcpy_offsets"-  memcpy_AddrToByteArray :: MutableByteArray# s -> CSize -> Addr# -> CSize -> CSize -> IO ()--foreign import ccall unsafe "string.h memcpy"-  memcpy_AddrToByteArray0 :: MutableByteArray# s -> Addr# -> CSize -> IO ()---copyByteArrayToAddr# src src_off dst len =-  unIO_ (memcpy_ByteArrayToAddr dst 0 src (csize src_off) (csize len))--copyByteArrayToAddr0 :: ByteArray# -> Addr# -> Int#-                     -> State# RealWorld -> State# RealWorld-copyByteArrayToAddr0 src dst len =-  unIO_ (memcpy_ByteArrayToAddr0 dst src (csize len))--{-# INLINE [0] copyByteArrayToAddr# #-}-{-# RULES "copyByteArrayToAddr# src_off=0"-      forall src dst len s.-          copyByteArrayToAddr# src 0# dst len s-        = copyByteArrayToAddr0 src    dst len s  #-}--foreign import ccall unsafe "fpstring.h fps_memcpy_offsets"-  memcpy_ByteArrayToAddr :: Addr# -> CSize -> ByteArray# -> CSize -> CSize -> IO ()--foreign import ccall unsafe "string.h memcpy"-  memcpy_ByteArrayToAddr0 :: Addr# -> ByteArray# -> CSize -> IO ()---unIO_ :: IO () -> State# RealWorld -> State# RealWorld-unIO_ io s = case unIO io s of (# s, _ #) -> s--csize :: Int# -> CSize-csize i# = fromIntegral (I# i#)-#endif--#if MIN_VERSION_base(4,5,0) copyByteArray# = GHC.Exts.copyByteArray#-#else-copyByteArray# src src_off dst dst_off len s =-    unST_ (unsafeIOToST-      (memcpy_ByteArray dst (csize dst_off) src (csize src_off) (csize len))) s-  where-    unST (ST st) = st-    unST_ st s = case unST st s of (# s, _ #) -> s -foreign import ccall unsafe "fpstring.h fps_memcpy_offsets"-  memcpy_ByteArray :: MutableByteArray# s -> CSize -> ByteArray# -> CSize -> CSize -> IO ()-#endif- -- | /O(n)./ Construct a new @ShortByteString@ from a @CString@. The -- resulting @ShortByteString@ is an immutable copy of the original -- @CString@, and is managed on the Haskell heap. The original@@ -638,7 +559,7 @@ -- @since 0.10.10.0 packCString :: CString -> IO ShortByteString packCString cstr = do-  len <- c_strlen cstr+  len <- BS.c_strlen cstr   packCStringLen (cstr, fromIntegral len)  -- | /O(n)./ Construct a new @ShortByteString@ from a @CStringLen@. The@@ -681,7 +602,7 @@ -- --------------------------------------------------------------------- -- Internal utilities -moduleErrorIO :: String -> String -> IO a+moduleErrorIO :: HasCallStack => String -> String -> IO a moduleErrorIO fun msg = throwIO . userError $ moduleErrorMsg fun msg {-# NOINLINE moduleErrorIO #-} 
Data/ByteString/Unsafe.hs view
@@ -1,8 +1,5 @@-{-# LANGUAGE CPP #-} {-# LANGUAGE MagicHash #-}-#if __GLASGOW_HASKELL__ >= 703 {-# LANGUAGE Unsafe #-}-#endif  -- | -- Module      : Data.ByteString.Unsafe@@ -22,29 +19,29 @@ module Data.ByteString.Unsafe (          -- * Unchecked access-        unsafeHead,             -- :: ByteString -> Word8-        unsafeTail,             -- :: ByteString -> ByteString-        unsafeInit,             -- :: ByteString -> ByteString-        unsafeLast,             -- :: ByteString -> Word8-        unsafeIndex,            -- :: ByteString -> Int -> Word8-        unsafeTake,             -- :: Int -> ByteString -> ByteString-        unsafeDrop,             -- :: Int -> ByteString -> ByteString+        unsafeHead,+        unsafeTail,+        unsafeInit,+        unsafeLast,+        unsafeIndex,+        unsafeTake,+        unsafeDrop,          -- * Low level interaction with CStrings         -- ** Using ByteStrings with functions for CStrings-        unsafeUseAsCString,     -- :: ByteString -> (CString -> IO a) -> IO a-        unsafeUseAsCStringLen,  -- :: ByteString -> (CStringLen -> IO a) -> IO a+        unsafeUseAsCString,+        unsafeUseAsCStringLen,          -- ** Converting CStrings to ByteStrings-        unsafePackCString,      -- :: CString -> IO ByteString-        unsafePackCStringLen,   -- :: CStringLen -> IO ByteString-        unsafePackMallocCString,-- :: CString -> IO ByteString-        unsafePackMallocCStringLen, -- :: CStringLen -> IO ByteString+        unsafePackCString,+        unsafePackCStringLen,+        unsafePackMallocCString,+        unsafePackMallocCStringLen, -        unsafePackAddress,          -- :: Addr# -> IO ByteString-        unsafePackAddressLen,       -- :: Int -> Addr# -> IO ByteString-        unsafePackCStringFinalizer, -- :: Ptr Word8 -> Int -> IO () -> IO ByteString-        unsafeFinalize,             -- :: ByteString -> IO ()+        unsafePackAddress,+        unsafePackAddressLen,+        unsafePackCStringFinalizer,+        unsafeFinalize,    ) where @@ -76,7 +73,7 @@ -- to provide a proof that the ByteString is non-empty. unsafeHead :: ByteString -> Word8 unsafeHead (BS x l) = assert (l > 0) $-    accursedUnutterablePerformIO $ withForeignPtr x $ \p -> peek p+    accursedUnutterablePerformIO $ unsafeWithForeignPtr x $ \p -> peek p {-# INLINE unsafeHead #-}  -- | A variety of 'tail' for non-empty ByteStrings. 'unsafeTail' omits the@@ -98,7 +95,7 @@ -- provide a separate proof that the ByteString is non-empty. unsafeLast :: ByteString -> Word8 unsafeLast (BS x l) = assert (l > 0) $-    accursedUnutterablePerformIO $ withForeignPtr x $ \p -> peekByteOff p (l-1)+    accursedUnutterablePerformIO $ unsafeWithForeignPtr x $ \p -> peekByteOff p (l-1) {-# INLINE unsafeLast #-}  -- | Unsafe 'ByteString' index (subscript) operator, starting from 0, returning a 'Word8'@@ -107,7 +104,7 @@ -- other way. unsafeIndex :: ByteString -> Int -> Word8 unsafeIndex (BS x l) i = assert (i >= 0 && i < l) $-    accursedUnutterablePerformIO $ withForeignPtr x $ \p -> peekByteOff p i+    accursedUnutterablePerformIO $ unsafeWithForeignPtr x $ \p -> peekByteOff p i {-# INLINE unsafeIndex #-}  -- | A variety of 'take' which omits the checks on @n@ so there is an@@ -265,7 +262,8 @@ -- after this. -- unsafeUseAsCString :: ByteString -> (CString -> IO a) -> IO a-unsafeUseAsCString (BS ps _) ac = withForeignPtr ps $ \p -> ac (castPtr p)+unsafeUseAsCString (BS ps _) action = withForeignPtr ps $ \p -> action (castPtr p)+-- Cannot use unsafeWithForeignPtr, because action can diverge  -- | /O(1) construction/ Use a 'ByteString' with a function requiring a -- 'CStringLen'.@@ -284,4 +282,5 @@ -- -- If 'Data.ByteString.empty' is given, it will pass @('Foreign.Ptr.nullPtr', 0)@. unsafeUseAsCStringLen :: ByteString -> (CStringLen -> IO a) -> IO a-unsafeUseAsCStringLen (BS ps l) f = withForeignPtr ps $ \p -> f (castPtr p,l)+unsafeUseAsCStringLen (BS ps l) action = withForeignPtr ps $ \p -> action (castPtr p, l)+-- Cannot use unsafeWithForeignPtr, because action can diverge
LICENSE view
@@ -2,6 +2,7 @@           (c) Duncan Coutts 2006-2015           (c) David Roundy 2003-2005           (c) Simon Meier 2010-2011+          (c) Koz Ross 2021  All rights reserved. 
bench/BenchAll.hs view
@@ -39,6 +39,7 @@ import System.Random  import BenchBoundsCheckFusion+import BenchCount import BenchCSV import BenchIndices @@ -214,22 +215,15 @@ -- benchmarks ------------- -sanityCheckInfo :: [String]-sanityCheckInfo =-  [ "Sanity checks:"-  , " lengths of input data: " ++ show-      [ length intData, length floatData, length doubleData-      , length smallIntegerData, length largeIntegerData-      , S.length byteStringData, fromIntegral (L.length lazyByteStringData)-      ]-  ]- sortInputs :: [S.ByteString] sortInputs = map (`S.take` S.pack [122, 121 .. 32]) [10..25]  foldInputs :: [S.ByteString] foldInputs = map (\k -> S.pack $ if k <= 6 then take (2 ^ k) [32..95] else concat (replicate (2 ^ (k - 6)) [32..95])) [0..16] +foldInputsLazy :: [L.ByteString]+foldInputsLazy = map (\k -> L.pack $ if k <= 6 then take (2 ^ k) [32..95] else concat (replicate (2 ^ (k - 6)) [32..95])) [0..16]+ zeroes :: L.ByteString zeroes = L.replicate 10000 0 @@ -245,7 +239,6 @@  main :: IO () main = do-  mapM_ putStrLn sanityCheckInfo   defaultMain     [ bgroup "Data.ByteString.Builder"       [ bgroup "Small payload"@@ -411,20 +404,43 @@       , bench "one huge word" $ nf S8.words byteStringData       ]     , bgroup "folds"-      [ bgroup "foldl'" $ map (\s -> bench (show $ S.length s) $-          nf (S.foldl' (\acc x -> acc + fromIntegral x) (0 :: Int)) s) foldInputs-      , bgroup "foldr'" $ map (\s -> bench (show $ S.length s) $-          nf (S.foldr' (\x acc -> fromIntegral x + acc) (0 :: Int)) s) foldInputs-      , bgroup "mapAccumL" $ map (\s -> bench (show $ S.length s) $-          nf (S.mapAccumL (\acc x -> (acc + fromIntegral x, succ x)) (0 :: Int)) s) foldInputs-      , bgroup "mapAccumR" $ map (\s -> bench (show $ S.length s) $-          nf (S.mapAccumR (\acc x -> (fromIntegral x + acc, succ x)) (0 :: Int)) s) foldInputs-      , bgroup "scanl" $ map (\s -> bench (show $ S.length s) $-          nf (S.scanl (+) 0) s) foldInputs-      , bgroup "scanr" $ map (\s -> bench (show $ S.length s) $-          nf (S.scanr (+) 0) s) foldInputs-      , bgroup "filter" $ map (\s -> bench (show $ S.length s) $-          nf (S.filter odd) s) foldInputs+      [ bgroup "strict"+        [ bgroup "foldl'" $ map (\s -> bench (show $ S.length s) $+            nf (S.foldl' (\acc x -> acc + fromIntegral x) (0 :: Int)) s) foldInputs+        , bgroup "foldr'" $ map (\s -> bench (show $ S.length s) $+            nf (S.foldr' (\x acc -> fromIntegral x + acc) (0 :: Int)) s) foldInputs+        , bgroup "foldr1'" $ map (\s -> bench (show $ S.length s) $+            nf (S.foldr1' (\x  acc -> fromIntegral x + acc)) s) foldInputs+        , bgroup "unfoldrN" $ map (\s -> bench (show $ S.length s) $+            nf (S.unfoldrN (S.length s) (\a -> Just (a, a + 1))) 0) foldInputs+        , bgroup "mapAccumL" $ map (\s -> bench (show $ S.length s) $+            nf (S.mapAccumL (\acc x -> (acc + fromIntegral x, succ x)) (0 :: Int)) s) foldInputs+        , bgroup "mapAccumR" $ map (\s -> bench (show $ S.length s) $+            nf (S.mapAccumR (\acc x -> (fromIntegral x + acc, succ x)) (0 :: Int)) s) foldInputs+        , bgroup "scanl" $ map (\s -> bench (show $ S.length s) $+            nf (S.scanl (+) 0) s) foldInputs+        , bgroup "scanr" $ map (\s -> bench (show $ S.length s) $+            nf (S.scanr (+) 0) s) foldInputs+        , bgroup "filter" $ map (\s -> bench (show $ S.length s) $+            nf (S.filter odd) s) foldInputs+        ]+      , bgroup "lazy"+        [ bgroup "foldl'" $ map (\s -> bench (show $ L.length s) $+            nf (L.foldl' (\acc x -> acc + fromIntegral x) (0 :: Int)) s) foldInputsLazy+        , bgroup "foldr'" $ map (\s -> bench (show $ L.length s) $+            nf (L.foldr' (\x acc -> fromIntegral x + acc) (0 :: Int)) s) foldInputsLazy+        , bgroup "foldr1'" $ map (\s -> bench (show $ L.length s) $+            nf (L.foldr1' (\x  acc -> fromIntegral x + acc)) s) foldInputsLazy+        , bgroup "mapAccumL" $ map (\s -> bench (show $ L.length s) $+            nf (L.mapAccumL (\acc x -> (acc + fromIntegral x, succ x)) (0 :: Int)) s) foldInputsLazy+        , bgroup "mapAccumR" $ map (\s -> bench (show $ L.length s) $+            nf (L.mapAccumR (\acc x -> (fromIntegral x + acc, succ x)) (0 :: Int)) s) foldInputsLazy+        , bgroup "scanl" $ map (\s -> bench (show $ L.length s) $+            nf (L.scanl (+) 0) s) foldInputsLazy+        , bgroup "scanr" $ map (\s -> bench (show $ L.length s) $+            nf (L.scanr (+) 0) s) foldInputsLazy+        ]+       ]     , bgroup "findIndexOrLength"       [ bench "takeWhile"      $ nf (L.takeWhile even) zeroes@@ -444,10 +460,11 @@       , bench "elemIndexInd"   $ nf (S.elemIndexEnd 42) byteStringData       ]     , bgroup "traversals"-      [ bench "map (+1)"   $ nf (S.map (+ 1)) largeTraversalInput-      , bench "map (+1)"   $ nf (S.map (+ 1)) smallTraversalInput+      [ bench "map (+1) large" $ nf (S.map (+ 1)) largeTraversalInput+      , bench "map (+1) small" $ nf (S.map (+ 1)) smallTraversalInput       ]     , benchBoundsCheckFusion+    , benchCount     , benchCSV     , benchIndices     ]
bench/BenchCSV.hs view
@@ -122,9 +122,6 @@ import           Data.ByteString.Builder.Prim.Internal ( (>*<), (>$<) ) import qualified Data.ByteString.Builder.Prim         as E --- To be used in a later comparison-import qualified Data.DList                 as D- -- bytestring benchmarks cannot depend on text because of a circular dependency. -- Anyways these comparisons are of historical interest only, so disabled for now. -- A curious soul can re-enable them by moving benchmarks to a separate package@@ -136,6 +133,12 @@ import qualified Data.Text.Lazy.Builder.Int as TB #endif +-- Same as above: comparison against DList is of historical interest now,+-- so lets shave off another dependency.+#ifdef MIN_VERSION_dlist+import qualified Data.DList                 as D+#endif+ ------------------------------------------------------------------------------ -- Simplife CSV Tables ------------------------------------------------------------------------------@@ -334,6 +337,8 @@ -- Difference-list based rendering ------------------------------------------------------------------------------ +#ifdef MIN_VERSION_dlist+ type DString = D.DList Char  renderStringD :: String -> DString@@ -360,6 +365,8 @@ benchDListUtf8 = bench "utf8 + renderTableD maxiTable" $   nf (L.length . B.toLazyByteString . B.stringUtf8 . D.toList . renderTableD) maxiTable +#endif+ ------------------------------------------------------------------------------ -- Text Builder ------------------------------------------------------------------------------@@ -406,7 +413,9 @@       [ benchNF       , benchString       , benchStringUtf8+#ifdef MIN_VERSION_dlist       , benchDListUtf8+#endif #ifdef MIN_VERSION_text       , benchTextBuilder       , benchTextBuilderUtf8
+ bench/BenchCount.hs view
@@ -0,0 +1,29 @@+-- |+-- Copyright   : (c) 2021 Georg Rudoy+-- License     : BSD3-style (see LICENSE)+--+-- Maintainer  : Georg Rudoy <0xd34df00d+github@gmail.com>+--+-- Benchmark count++module BenchCount (benchCount) where++import           Test.Tasty.Bench+import qualified Data.ByteString.Char8 as B++benchCount :: Benchmark+benchCount = bgroup "Count"+  [ bgroup "no matches, same char"       $ mkBenches (1 : commonSizes) (\s -> B.replicate s 'b')+  , bgroup "no matches, different chars" $ mkBenches      commonSizes  (\s -> genCyclic 10 s 'b')+  , bgroup "some matches, alternating"   $ mkBenches      commonSizes  (\s -> genCyclic 2 s 'a')+  , bgroup "some matches, short cycle"   $ mkBenches      commonSizes  (\s -> genCyclic 5 s 'a')+  , bgroup "some matches, long cycle"    $ mkBenches      commonSizes  (\s -> genCyclic 10 s 'a')+  , bgroup "all matches"                 $ mkBenches (1 : commonSizes) (\s -> B.replicate s 'a')+  ]+  where+    aboveSimdSwitchThreshold = 1030 -- something above the threshold of 1024 that's divisible by cycle lengths+    commonSizes = [ 10, 100, 1000, aboveSimdSwitchThreshold, 10000, 100000, 1000000 ]+    mkBenches sizes gen = [ bench (show size ++ " chars long") $ nf (B.count 'a') (gen size)+                          | size <- sizes+                          ]+    genCyclic cycleLen size from = B.concat $ replicate (size `div` cycleLen) $ B.pack (take cycleLen [from..])
bytestring.cabal view
@@ -1,5 +1,5 @@ Name:                bytestring-Version:             0.11.1.0+Version:             0.11.2.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)@@ -54,9 +54,13 @@ Maintainer:          Haskell Bytestring Team <andrew.lelechenko@gmail.com>, Core Libraries Committee Homepage:            https://github.com/haskell/bytestring Bug-reports:         https://github.com/haskell/bytestring/issues-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+Tested-With:         GHC==9.0.1,+                     GHC==8.10.4,+                     GHC==8.8.4,+                     GHC==8.6.5,+                     GHC==8.4.4,+                     GHC==8.2.2,+                     GHC==8.0.2 Build-Type:          Simple Cabal-Version:       >= 1.10 extra-source-files:  README.md Changelog.md@@ -65,12 +69,8 @@   type:     git   location: https://github.com/haskell/bytestring -flag integer-simple-  description: Use the simple integer library instead of GMP-  default: False- library-  build-depends:     base >= 4.3 && < 5, ghc-prim, deepseq+  build-depends:     base >= 4.9 && < 5, ghc-prim, deepseq, template-haskell    exposed-modules:   Data.ByteString                      Data.ByteString.Char8@@ -85,16 +85,21 @@                      Data.ByteString.Builder                      Data.ByteString.Builder.Extra                      Data.ByteString.Builder.Prim+                     Data.ByteString.Builder.RealFloat                       -- perhaps only exposed temporarily                      Data.ByteString.Builder.Internal                      Data.ByteString.Builder.Prim.Internal-  other-modules:-                     Data.ByteString.Builder.ASCII-                     Data.ByteString.Builder.Prim.Binary+  other-modules:     Data.ByteString.Builder.ASCII                      Data.ByteString.Builder.Prim.ASCII-                     Data.ByteString.Builder.Prim.Internal.Floating+                     Data.ByteString.Builder.Prim.Binary                      Data.ByteString.Builder.Prim.Internal.Base16+                     Data.ByteString.Builder.Prim.Internal.Floating+                     Data.ByteString.Builder.RealFloat.F2S+                     Data.ByteString.Builder.RealFloat.D2S+                     Data.ByteString.Builder.RealFloat.Internal+                     Data.ByteString.Builder.RealFloat.TableGenerator+                     Data.ByteString.Lazy.Internal.Deque    default-language:  Haskell2010   other-extensions:  CPP,@@ -107,92 +112,76 @@                      ScopedTypeVariables                      RankNTypes                      NamedFieldPuns---  if impl(ghc >= 7.2)---    other-extensions: Trustworthy, Unsafe-  -- older ghc had issues with language pragmas guarded by cpp-  if impl(ghc < 7)-    default-extensions: CPP, MagicHash, UnboxedTuples,-                        DeriveDataTypeable, BangPatterns,-                        NamedFieldPuns    ghc-options:      -Wall -fwarn-tabs                     -O2                     -fmax-simplifier-iterations=10                     -fdicts-cheap                     -fspec-constr-count=6+  +  c-sources:        cbits/fpstring.c+                    cbits/itoa.c+  +  if (arch(aarch64))+    c-sources:        cbits/aarch64/is-valid-utf8.c+  else+    c-sources:        cbits/is-valid-utf8.c+  +  cc-options:        -std=c11+ +  -- Required, due to the following issues:+  -- * https://gitlab.haskell.org/ghc/ghc/-/issues/20525#note_385580+  -- * https://gitlab.haskell.org/ghc/ghc/-/issues/19417+  if os(windows)+    extra-libraries:  gcc_s gcc -  c-sources:         cbits/fpstring.c-                     cbits/itoa.c   include-dirs:      include   includes:          fpstring.h   install-includes:  fpstring.h -   -- flags for the decimal integer serialization code-  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--  if impl(ghc >= 6.9) && impl(ghc < 6.11)-    cpp-options: -DINTEGER_GMP-    build-depends: integer >= 0.1 && < 0.2--test-suite prop-compiled-  type:             exitcode-stdio-1.0-  main-is:          Properties.hs-  other-modules:    Rules-                    QuickCheckUtils-  hs-source-dirs:   tests-  build-depends:    base, bytestring, ghc-prim, deepseq,-                    tasty, tasty-quickcheck-  ghc-options:      -fwarn-unused-binds-                    -threaded -rtsopts-  default-language: Haskell2010--test-suite lazy-hclose-  type:             exitcode-stdio-1.0-  main-is:          LazyHClose.hs-  hs-source-dirs:   tests-  build-depends:    base, bytestring, ghc-prim, deepseq,-                    tasty, tasty-quickcheck-  ghc-options:      -fwarn-unused-binds-                    -threaded -rtsopts-  default-language: Haskell2010--test-suite test-builder+test-suite bytestring-tests   type:             exitcode-stdio-1.0-  hs-source-dirs:   tests/builder-  main-is:          TestSuite.hs-  other-modules:    Data.ByteString.Builder.Tests-                    Data.ByteString.Builder.Prim.Tests+  main-is:          Main.hs+  other-modules:    Builder                     Data.ByteString.Builder.Prim.TestUtils-  build-depends:    base, bytestring, ghc-prim,+                    Data.ByteString.Builder.Prim.Tests+                    Data.ByteString.Builder.Tests+                    IsValidUtf8+                    LazyHClose+                    Lift+                    Properties+                    Properties.ByteString+                    Properties.ByteStringChar8+                    Properties.ByteStringLazy+                    Properties.ByteStringLazyChar8+                    QuickCheckUtils+  hs-source-dirs:   tests,+                    tests/builder+  build-depends:    base,+                    bytestring,                     deepseq,-                    dlist                      >= 0.5 && < 0.9,-                    transformers               >= 0.3,+                    ghc-prim,+                    QuickCheck,                     tasty,-                    tasty-hunit,-                    tasty-quickcheck-  if impl(ghc < 8.4)-    build-depends:  ghc-byteorder-  ghc-options:      -Wall -fwarn-tabs -threaded -rtsopts+                    tasty-quickcheck,+                    template-haskell,+                    transformers >= 0.3+  ghc-options:      -fwarn-unused-binds+                    -threaded -rtsopts   default-language: Haskell2010  benchmark bytestring-bench   main-is:          BenchAll.hs   other-modules:    BenchBoundsCheckFusion+                    BenchCount                     BenchCSV                     BenchIndices   type:             exitcode-stdio-1.0   hs-source-dirs:   bench   default-language: Haskell2010-  ghc-options:      -O2+  ghc-options:      -O2 "-with-rtsopts=-A32m"   build-depends:    base,                     bytestring,                     deepseq,-                    dlist,                     tasty-bench,                     random
+ cbits/aarch64/is-valid-utf8.c view
@@ -0,0 +1,280 @@+/*+Copyright (c) Koz Ross 2021++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions+are met:+1. Redistributions of source code must retain the above copyright+   notice, this list of conditions and the following disclaimer.+2. Redistributions in binary form must reproduce the above copyright+   notice, this list of conditions and the following disclaimer in the+   documentation and/or other materials provided with the distribution.+3. Neither the name of the author nor the names of his contributors+   may be used to endorse or promote products derived from this software+   without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE+ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF+SUCH DAMAGE.+*/+#pragma GCC push_options+#pragma GCC optimize("-O2")+#include <stdbool.h>+#include <stdint.h>+#include <stddef.h>+#include <arm_neon.h>++// Fallback (for tails).+static inline int is_valid_utf8_fallback(uint8_t const *const src,+                                         size_t const len) {+  uint8_t const *ptr = (uint8_t const *)src;+  // This is 'one past the end' to make loop termination and bounds checks+  // easier.+  uint8_t const *const end = ptr + len;+  while (ptr < end) {+    uint8_t const byte = *ptr;+    // Check if the byte is ASCII.+    if (byte <= 0x7F) {+      ptr++;+    }+    // Check for a valid 2-byte sequence.+    //+    // We use a signed comparison to avoid an extra comparison with 0x80, since+    // _signed_ 0x80 is -128.+    else if (ptr + 1 < end && byte >= 0xC2 && byte <= 0xDF &&+             ((int8_t) * (ptr + 1)) <= (int8_t)0xBF) {+      ptr += 2;+    }+    // Check for a valid 3-byte sequence.+    else if (ptr + 2 < end && byte >= 0xE0 && byte <= 0xEF) {+      uint8_t const byte2 = *(ptr + 1);+      bool byte2_valid = (int8_t)byte2 <= (int8_t)0xBF;+      bool byte3_valid = ((int8_t) * (ptr + 2)) <= (int8_t)0xBF;+      if (byte2_valid && byte3_valid &&+          // E0, A0..BF, 80..BF+          ((byte == 0xE0 && byte2 >= 0xA0) ||+           // E1..EC, 80..BF, 80..BF+           (byte >= 0xE1 && byte <= 0xEC) ||+           // ED, 80..9F, 80..BF+           (byte == 0xED && byte2 <= 0x9F) ||+           // EE..EF, 80..BF, 80..BF+           (byte >= 0xEE && byte <= 0xEF))) {+        ptr += 3;+      } else {+        return 0;+      }+    }+    // Check for a valid 4-byte sequence.+    else if (ptr + 3 < end) {+      uint8_t const byte2 = *(ptr + 1);+      bool byte2_valid = (int8_t)byte2 <= (int8_t)0xBF;+      bool byte3_valid = ((int8_t) * (ptr + 2)) <= (int8_t)0xBF;+      bool byte4_valid = ((int8_t) * (ptr + 3)) <= (int8_t)0xBF;+      if (byte2_valid && byte3_valid && byte4_valid &&+          // F0, 90..BF, 80..BF, 80..BF+          ((byte == 0xF0 && byte2 >= 0x90) ||+           // F1..F3, 80..BF, 80..BF, 80..BF+           (byte >= 0xF1 && byte <= 0xF3) ||+           // F4, 80..8F, 80..BF, 80..BF+           (byte == 0xF4 && byte2 <= 0x8F))) {+        ptr += 4;+      } else {+        return 0;+      }+    }+    // Otherwise, invalid.+    else {+      return 0;+    }+  }+  // If we got this far, we're valid.+  return 1;+}++static uint8_t const first_len_lookup[16] = {+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3,+};++static uint8_t const first_range_lookup[16] = {+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8,+};++static uint8_t const range_min_lookup[16] = {+  0x00, 0x80, 0x80, 0x80, 0xA0, 0x80, 0x90, 0x80,+  0xC2, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,+};++static uint8_t const range_max_lookup[16] = {+  0x7F, 0xBF, 0xBF, 0xBF, 0xBF, 0x9F, 0xBF, 0x8F,+  0xF4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,+};++static uint8_t const range_adjust_lookup[32] = {+  2, 3, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0,+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0,+};++static bool is_ascii (uint8x16_t const * const inputs) {+  uint8x16_t const all_80 = vdupq_n_u8(0x80);+  // A non-ASCII byte will have its highest-order bit set. Since this is+  // preserved by OR, we can OR everything together.+  uint8x16_t ored = vorrq_u8(vorrq_u8(inputs[0], inputs[1]),+                             vorrq_u8(inputs[2], inputs[3]));+  // ANDing with 0x80 retains any set high-order bits. We then check for zeroes.+  uint64x2_t result = vreinterpretq_u64_u8(vandq_u8(ored, all_80));+  return !(vgetq_lane_u64(result, 0) || vgetq_lane_u64(result, 1));+}++static void check_block_neon(uint8x16_t const prev_input,+                             uint8x16_t const prev_first_len,+                             uint8x16_t* errors,+                             uint8x16_t const first_range_tbl,+                             uint8x16_t const range_min_tbl,+                             uint8x16_t const range_max_tbl,+                             uint8x16x2_t const range_adjust_tbl,+                             uint8x16_t const all_ones,+                             uint8x16_t const all_twos,+                             uint8x16_t const all_e0s,+                             uint8x16_t const input,+                             uint8x16_t const first_len) {+  // Get the high 4-bits of the input.+  uint8x16_t const high_nibbles = vshrq_n_u8(input, 4);+  // Set range index to 8 for bytes in [C0, FF] by lookup (first byte).+  uint8x16_t range = vqtbl1q_u8(first_range_tbl, high_nibbles);+  // Reduce the range index based on first_len (second byte).+  // This is 0 for [00, 7F], 1 for [C0, DF], 2 for [E0, EF], 3 for [F0, FF].+  range = vorrq_u8(range, vextq_u8(prev_first_len, first_len, 15));+  uint8x16_t tmp[2];+  // Set range index to the saturation of (first_len - 1) (third byte).+  // This is 0 for [00, 7F], 0 for [C0, DF], 1 for [E0, EF], 2 for [F0, FF].+  tmp[0] = vextq_u8(prev_first_len, first_len, 14);+  tmp[0] = vqsubq_u8(tmp[0], all_ones);+  range = vorrq_u8(range, tmp[0]);+  // Set range index to the saturation of (first_len - 2) (fourth byte).+  // This is 0 for [00, 7F], 0 for [C0, DF], 0 for [E0, EF] and 1 for [F0, FF].+  // This is 'split apart' for speed, as we're not as register-starved as on+  // x86.+  tmp[1] = vextq_u8(prev_first_len, first_len, 13);+  tmp[1] = vqsubq_u8(tmp[1], all_twos);+  range = vorrq_u8(range, tmp[1]);+  // At this stage, we have calculated range indices correctly, except for+  // special cases for first bytes (E0, ED, F0, F4). We repair this to avoid+  // missing in the range table.+  uint8x16_t const shift1 = vextq_u8(prev_input, input, 15);+  uint8x16_t const pos = vsubq_u8(shift1, all_e0s);+  range = vaddq_u8(range, vqtbl2q_u8(range_adjust_tbl, pos));+  // We can now load minimum and maximum values from our tables based on the+  // calculated indices.+  uint8x16_t const minv = vqtbl1q_u8(range_min_tbl, range);+  uint8x16_t const maxv = vqtbl1q_u8(range_max_tbl, range);+  // Accumulate errors, if any.+  errors[0] = vorrq_u8(errors[0], vcltq_u8(input, minv));+  errors[1] = vorrq_u8(errors[1], vcgtq_u8(input, maxv));+}++int bytestring_is_valid_utf8(uint8_t const * const src, size_t const len) {+  if (len == 0) {+    return 1;+  }+  // We step 64 bytes at a time.+  size_t const big_strides = len / 64;+  size_t const remaining = len % 64;+  uint8_t const * ptr = (uint8_t const *)src;+  // Tracking state+  uint8x16_t prev_input = vdupq_n_u8(0);+  uint8x16_t prev_first_len = vdupq_n_u8(0);+  uint8x16_t errors[2] = {+    vdupq_n_u8(0),+    vdupq_n_u8(0),+  };+  // Load our lookup tables.+  uint8x16_t const first_len_tbl = vld1q_u8(first_len_lookup);+  uint8x16_t const first_range_tbl = vld1q_u8(first_range_lookup);+  uint8x16_t const range_min_tbl = vld1q_u8(range_min_lookup);+  uint8x16_t const range_max_tbl = vld1q_u8(range_max_lookup);+  uint8x16x2_t const range_adjust_tbl = vld2q_u8(range_adjust_lookup);+  // Useful constants.+  uint8x16_t const all_ones = vdupq_n_u8(1);+  uint8x16_t const all_twos = vdupq_n_u8(2);+  uint8x16_t const all_e0s = vdupq_n_u8(0xE0);+  for (size_t i = 0; i < big_strides; i++) {+    // Load 64 bytes+    uint8x16_t const inputs[4] = {+      vld1q_u8(ptr),+      vld1q_u8(ptr + 16),+      vld1q_u8(ptr + 32),+      vld1q_u8(ptr + 48)+    };+    // Check if we have ASCII+    if (is_ascii(inputs)) {+      // Prev_first_len cheaply.+      prev_first_len = vqtbl1q_u8(first_len_tbl, vshrq_n_u8(inputs[3], 4));+    } else {+      uint8x16_t first_len = vqtbl1q_u8(first_len_tbl, vshrq_n_u8(inputs[0], 4));+      check_block_neon(prev_input, prev_first_len, errors,+                       first_range_tbl, range_min_tbl, range_max_tbl,+                       range_adjust_tbl, all_ones, all_twos, all_e0s,+                       inputs[0], first_len);+      prev_first_len = first_len;+      first_len = vqtbl1q_u8(first_len_tbl, vshrq_n_u8(inputs[1], 4));+      check_block_neon(inputs[0], prev_first_len, errors,+                       first_range_tbl, range_min_tbl, range_max_tbl,+                       range_adjust_tbl, all_ones, all_twos, all_e0s,+                       inputs[1], first_len);+      prev_first_len = first_len;+      first_len = vqtbl1q_u8(first_len_tbl, vshrq_n_u8(inputs[2], 4));+      check_block_neon(inputs[1], prev_first_len, errors,+                       first_range_tbl, range_min_tbl, range_max_tbl,+                       range_adjust_tbl, all_ones, all_twos, all_e0s,+                       inputs[2], first_len);+      prev_first_len = first_len;+      first_len = vqtbl1q_u8(first_len_tbl, vshrq_n_u8(inputs[3], 4));+      check_block_neon(inputs[2], prev_first_len, errors,+                       first_range_tbl, range_min_tbl, range_max_tbl,+                       range_adjust_tbl, all_ones, all_twos, all_e0s,+                       inputs[3], first_len);+      prev_first_len = first_len;+    }+    // Set prev_input based on last block.+    prev_input = inputs[3];+    // Advance.+    ptr += 64;+  }+  // Combine error carriers with a manually-unrolled loop, then check if+  // anything went awry.+  if (vmaxvq_u8(vorrq_u8(errors[0], errors[1])) != 0) {+    return 0;+  }+  //'Roll back' our pointer a little to prepare for a slow search of the rest.+  uint32_t token;+  vst1q_lane_u32(&token, vreinterpretq_u32_u8(prev_input), 3);+  // We cast this pointer to avoid a redundant check against < 127, as any such+  // value would be negative in signed form.+  int8_t const * token_ptr = (int8_t const *)&token;+  ptrdiff_t lookahead = 0;+  if (token_ptr[3] > (int8_t)0xBF) {+    lookahead = 1;+  }+  else if (token_ptr[2] > (int8_t)0xBF) {+    lookahead = 2;+  }+  else if (token_ptr[1] > (int8_t)0xBF) {+    lookahead = 3;+  }+  // Finish the job.+  uint8_t const * const small_ptr = ptr - lookahead;+  size_t const small_len = remaining + lookahead;+  return is_valid_utf8_fallback(small_ptr, small_len);+}++#pragma GCC pop_options
cbits/fpstring.c view
@@ -31,10 +31,17 @@  #include "fpstring.h" #if defined(__x86_64__)-#include <emmintrin.h>-#include <xmmintrin.h>+#include <x86intrin.h>+#include <cpuid.h> #endif +#include <stdint.h>+#include <stdbool.h>++#ifndef __STDC_NO_ATOMICS__+#include <stdatomic.h>+#endif+ /* copy a string in reverse */ void fps_reverse(unsigned char *q, unsigned char *p, size_t n) {     p += n-1;@@ -90,26 +97,190 @@     return c; } +int fps_compare(const void *a, const void *b) {+    return (int)*(unsigned char*)a - (int)*(unsigned char*)b;+}++void fps_sort(unsigned char *p, size_t len) {+    return qsort(p, len, 1, fps_compare);+}+ /* count the number of occurences of a char in a string */-size_t fps_count(unsigned char *p, size_t len, unsigned char w) {+size_t fps_count_naive(unsigned char *str, size_t len, unsigned char w) {     size_t c;-    for (c = 0; len-- != 0; ++p)-        if (*p == w)+    for (c = 0; len-- != 0; ++str)+        if (*str == w)             ++c;     return c; } -/* This wrapper is here so that we can copy a sub-range of a ByteArray#.-   We cannot construct a pointer to the interior of an unpinned ByteArray#,-   except by doing an unsafe ffi call, and adjusting the pointer C-side. */-void * fps_memcpy_offsets(void *dst, size_t dst_off, const void *src, size_t src_off, size_t n) {-    return memcpy(dst + dst_off, src + src_off, n);+#if defined(__x86_64__) && (__GNUC__ >= 6 || defined(__clang_major__)) && !defined(__STDC_NO_ATOMICS__)+#define USE_SIMD_COUNT+#endif++#ifdef USE_SIMD_COUNT+__attribute__((target("sse4.2")))+size_t fps_count_cmpestrm(unsigned char *str, size_t len, unsigned char w) {+    const __m128i pat = _mm_set1_epi8(w);++    size_t res = 0;++    size_t i = 0;++    for (; i < len && (intptr_t)(str + i) % 64; ++i) {+        res += str[i] == w;+    }++    for (size_t end = len - 128; i < end; i += 128) {+        __m128i p0 = _mm_load_si128((const __m128i*)(str + i + 16 * 0));+        __m128i p1 = _mm_load_si128((const __m128i*)(str + i + 16 * 1));+        __m128i p2 = _mm_load_si128((const __m128i*)(str + i + 16 * 2));+        __m128i p3 = _mm_load_si128((const __m128i*)(str + i + 16 * 3));+        __m128i p4 = _mm_load_si128((const __m128i*)(str + i + 16 * 4));+        __m128i p5 = _mm_load_si128((const __m128i*)(str + i + 16 * 5));+        __m128i p6 = _mm_load_si128((const __m128i*)(str + i + 16 * 6));+        __m128i p7 = _mm_load_si128((const __m128i*)(str + i + 16 * 7));+        // Here, cmpestrm compares two strings in the following mode:+        // * _SIDD_SBYTE_OPS: interprets the strings as consisting of 8-bit chars,+        // * _SIDD_CMP_EQUAL_EACH: computes the number of `i`s+        //    for which `p[i]`, a part of `str`, is equal to `pat[i]`+        //    (the latter being always equal to `w`).+        //+        // q.v. https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmpestrm&expand=835+#define MODE _SIDD_SBYTE_OPS | _SIDD_CMP_EQUAL_EACH+        __m128i r0 = _mm_cmpestrm(p0, 16, pat, 16, MODE);+        __m128i r1 = _mm_cmpestrm(p1, 16, pat, 16, MODE);+        __m128i r2 = _mm_cmpestrm(p2, 16, pat, 16, MODE);+        __m128i r3 = _mm_cmpestrm(p3, 16, pat, 16, MODE);+        __m128i r4 = _mm_cmpestrm(p4, 16, pat, 16, MODE);+        __m128i r5 = _mm_cmpestrm(p5, 16, pat, 16, MODE);+        __m128i r6 = _mm_cmpestrm(p6, 16, pat, 16, MODE);+        __m128i r7 = _mm_cmpestrm(p7, 16, pat, 16, MODE);+#undef MODE+        res += _popcnt64(_mm_extract_epi64(r0, 0));+        res += _popcnt64(_mm_extract_epi64(r1, 0));+        res += _popcnt64(_mm_extract_epi64(r2, 0));+        res += _popcnt64(_mm_extract_epi64(r3, 0));+        res += _popcnt64(_mm_extract_epi64(r4, 0));+        res += _popcnt64(_mm_extract_epi64(r5, 0));+        res += _popcnt64(_mm_extract_epi64(r6, 0));+        res += _popcnt64(_mm_extract_epi64(r7, 0));+    }++    for (; i < len; ++i) {+        res += str[i] == w;+    }++    return res; } -int fps_compare(const void *a, const void *b) {-  return (int)*(unsigned char*)a - (int)*(unsigned char*)b;+__attribute__((target("avx2")))+size_t fps_count_avx2(unsigned char *str, size_t len, unsigned char w) {+    __m256i pat = _mm256_set1_epi8(w);++    size_t prefix = 0, res = 0;++    size_t i = 0;++    for (; i < len && (intptr_t)(str + i) % 64; ++i) {+        prefix += str[i] == w;+    }++    for (size_t end = len - 128; i < end; i += 128) {+        __m256i p0 = _mm256_load_si256((const __m256i*)(str + i + 32 * 0));+        __m256i p1 = _mm256_load_si256((const __m256i*)(str + i + 32 * 1));+        __m256i p2 = _mm256_load_si256((const __m256i*)(str + i + 32 * 2));+        __m256i p3 = _mm256_load_si256((const __m256i*)(str + i + 32 * 3));+        __m256i r0 = _mm256_cmpeq_epi8(p0, pat);+        __m256i r1 = _mm256_cmpeq_epi8(p1, pat);+        __m256i r2 = _mm256_cmpeq_epi8(p2, pat);+        __m256i r3 = _mm256_cmpeq_epi8(p3, pat);+        res += _popcnt64(_mm256_extract_epi64(r0, 0));+        res += _popcnt64(_mm256_extract_epi64(r0, 1));+        res += _popcnt64(_mm256_extract_epi64(r0, 2));+        res += _popcnt64(_mm256_extract_epi64(r0, 3));+        res += _popcnt64(_mm256_extract_epi64(r1, 0));+        res += _popcnt64(_mm256_extract_epi64(r1, 1));+        res += _popcnt64(_mm256_extract_epi64(r1, 2));+        res += _popcnt64(_mm256_extract_epi64(r1, 3));+        res += _popcnt64(_mm256_extract_epi64(r2, 0));+        res += _popcnt64(_mm256_extract_epi64(r2, 1));+        res += _popcnt64(_mm256_extract_epi64(r2, 2));+        res += _popcnt64(_mm256_extract_epi64(r2, 3));+        res += _popcnt64(_mm256_extract_epi64(r3, 0));+        res += _popcnt64(_mm256_extract_epi64(r3, 1));+        res += _popcnt64(_mm256_extract_epi64(r3, 2));+        res += _popcnt64(_mm256_extract_epi64(r3, 3));+    }++    // _mm256_cmpeq_epi8(p, pat) returns a SIMD vector+    // with `i`th byte consisting of eight `1`s if `p[i] == pat[i]`,+    // and of eight `0`s otherwise,+    // hence each matching byte is counted 8 times by popcnt.+    // Dividing by 8 corrects for that.+    res /= 8;++    res += prefix;++    for (; i < len; ++i) {+        res += str[i] == w;+    }++    return res; } -void fps_sort(unsigned char *p, size_t len) {-  return qsort(p, len, 1, fps_compare);+typedef size_t (*fps_impl_t) (unsigned char*, size_t, unsigned char);++fps_impl_t select_fps_simd_impl() {+    uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0;++    uint32_t ecx1 = 0;+    if (__get_cpuid(1, &eax, &ebx, &ecx, &edx)) {+        ecx1 = ecx;+    }++    const bool has_xsave = ecx1 & (1 << 26);+    const bool has_popcnt = ecx1 & (1 << 23);++    if (__get_cpuid_count(7, 0, &eax, &ebx, &ecx, &edx)) {+        const bool has_avx2 = has_xsave && (ebx & (1 << 5));+        if (has_avx2 && has_popcnt) {+            return &fps_count_avx2;+        }+    }++    const bool has_sse42 = ecx1 & (1 << 19);+    if (has_sse42 && has_popcnt) {+        return &fps_count_cmpestrm;+    }++    return &fps_count_naive;+}+#endif++++size_t fps_count(unsigned char *str, size_t len, unsigned char w) {+#ifndef USE_SIMD_COUNT+    return fps_count_naive(str, len, w);+#else+    // 1024 is a rough guesstimate of the string length+    // for which the extra performance of the main SIMD loop+    // starts to compensate the extra work and extra branching outside the SIMD loop.+    // The real optimal number depends on the specific μarch+    // and isn't worth optimizing for in this context,+    // since counting characters in shorter strings is unlikely to be a hot spot.+    if (len <= 1024) {+        return fps_count_naive(str, len, w);+    }++    static _Atomic fps_impl_t s_impl = (fps_impl_t)NULL;+    fps_impl_t impl = atomic_load_explicit(&s_impl, memory_order_relaxed);+    if (!impl) {+      impl = select_fps_simd_impl();+      atomic_store_explicit(&s_impl, impl, memory_order_relaxed);+    }++    return (*impl)(str, len, w);+#endif }
+ cbits/is-valid-utf8.c view
@@ -0,0 +1,696 @@+/*+Copyright (c) Koz Ross 2021++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions+are met:+1. Redistributions of source code must retain the above copyright+   notice, this list of conditions and the following disclaimer.+2. Redistributions in binary form must reproduce the above copyright+   notice, this list of conditions and the following disclaimer in the+   documentation and/or other materials provided with the distribution.+3. Neither the name of the author nor the names of his contributors+   may be used to endorse or promote products derived from this software+   without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE+ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF+SUCH DAMAGE.+*/+#pragma GCC push_options+#pragma GCC optimize("-O2")+#include <stdbool.h>+#include <stddef.h>+#include <stdint.h>++#ifdef __x86_64__+#include <emmintrin.h>+#include <immintrin.h>+#include <tmmintrin.h>+#include <cpuid.h>+#endif++#ifndef __STDC_NO_ATOMICS__+#include <stdatomic.h>+#endif++#include <MachDeps.h>++#ifdef WORDS_BIGENDIAN+#define to_little_endian(x) __builtin_bswap64(x)+#else+#define to_little_endian(x) (x)+#endif++// 0x80 in every 'lane'.+static uint64_t const high_bits_mask = 0x8080808080808080ULL;++static inline int is_valid_utf8_fallback(uint8_t const *const src, size_t const len) {+  uint8_t const *ptr = (uint8_t const *)src;+  // This is 'one past the end' to make loop termination and bounds checks+  // easier.+  uint8_t const *const end = ptr + len;+  while (ptr < end) {+    uint8_t const byte = *ptr;+    // Check if the byte is ASCII.+    if (byte <= 0x7F) {+      ptr++;+      // If we saw one ASCII byte, as long as it's not whitespace, it's quite+      // likely we'll see more.+      bool is_not_whitespace = byte > 32;+      // If possible, do a block-check ahead.+      if ((ptr + 32 < end) && is_not_whitespace) {+        uint64_t const *big_ptr = (uint64_t const *)ptr;+        // Non-ASCII bytes have a set MSB. Thus, if we AND with 0x80 in every+        // 'lane', we will get 0 if everything is ASCII, and something else+        // otherwise.+        uint64_t results[4] = {to_little_endian(*big_ptr) & high_bits_mask,+                               to_little_endian(*(big_ptr + 1)) & high_bits_mask,+                               to_little_endian(*(big_ptr + 2)) & high_bits_mask,+                               to_little_endian(*(big_ptr + 3)) & high_bits_mask};+        if (results[0] == 0) {+          ptr += 8;+          if (results[1] == 0) {+            ptr += 8;+            if (results[2] == 0) {+              ptr += 8;+              if (results[3] == 0) {+                ptr += 8;+              } else {+                ptr += (__builtin_ctzl(results[3]) / 8);+              }+            } else {+              ptr += (__builtin_ctzl(results[2]) / 8);+            }+          } else {+            ptr += (__builtin_ctzl(results[1]) / 8);+          }+        } else {+          ptr += (__builtin_ctzl(results[0]) / 8);+        }+      }+    }+    // Check for a valid 2-byte sequence.+    //+    // We use a signed comparison to avoid an extra comparison with 0x80, since+    // _signed_ 0x80 is -128.+    else if (ptr + 1 < end && byte >= 0xC2 && byte <= 0xDF &&+             ((int8_t) * (ptr + 1)) <= (int8_t)0xBF) {+      ptr += 2;+    }+    // Check for a valid 3-byte sequence.+    else if (ptr + 2 < end && byte >= 0xE0 && byte <= 0xEF) {+      uint8_t const byte2 = *(ptr + 1);+      bool byte2_valid = (int8_t)byte2 <= (int8_t)0xBF;+      bool byte3_valid = ((int8_t) * (ptr + 2)) <= (int8_t)0xBF;+      if (byte2_valid && byte3_valid &&+          // E0, A0..BF, 80..BF+          ((byte == 0xE0 && byte2 >= 0xA0) ||+           // E1..EC, 80..BF, 80..BF+           (byte >= 0xE1 && byte <= 0xEC) ||+           // ED, 80..9F, 80..BF+           (byte == 0xED && byte2 <= 0x9F) ||+           // EE..EF, 80..BF, 80..BF+           (byte >= 0xEE && byte <= 0xEF))) {+        ptr += 3;+      } else {+        return 0;+      }+    }+    // Check for a valid 4-byte sequence.+    else if (ptr + 3 < end) {+      uint8_t const byte2 = *(ptr + 1);+      bool byte2_valid = (int8_t)byte2 <= (int8_t)0xBF;+      bool byte3_valid = ((int8_t) * (ptr + 2)) <= (int8_t)0xBF;+      bool byte4_valid = ((int8_t) * (ptr + 3)) <= (int8_t)0xBF;+      if (byte2_valid && byte3_valid && byte4_valid &&+          // F0, 90..BF, 80..BF, 80..BF+          ((byte == 0xF0 && byte2 >= 0x90) ||+           // F1..F3, 80..BF, 80..BF, 80..BF+           (byte >= 0xF1 && byte <= 0xF3) ||+           // F4, 80..8F, 80..BF, 80..BF+           (byte == 0xF4 && byte2 <= 0x8F))) {+        ptr += 4;+      } else {+        return 0;+      }+    }+    // Otherwise, invalid.+    else {+      return 0;+    }+  }+  // If we got this far, we're valid.+  return 1;+}++#ifdef __x86_64__++// SSE2++static inline int is_valid_utf8_sse2(uint8_t const *const src,+                                     size_t const len) {+  uint8_t const *ptr = (uint8_t const *)src;+  // This is 'one past the end' to make loop termination and bounds checks+  // easier.+  uint8_t const *const end = ptr + len;+  while (ptr < end) {+    uint8_t const byte = *ptr;+    // Check if the byte is ASCII.+    if (byte <= 0x7F) {+      ptr++;+      // If we saw one ASCII byte, as long as it's not whitespace, it's quite+      // likely we'll see more.+      bool is_not_whitespace = byte > 32;+      // If possible, do a block-check ahead.+      if ((ptr + 64 < end) && is_not_whitespace) {+        __m128i const *big_ptr = (__m128i const *)ptr;+        // Non-ASCII bytes have a set MSB. Thus, if we evacuate the MSBs, we+        // will get a set bit somewhere if there's a non-ASCII byte in that+        // block.+        uint16_t result = _mm_movemask_epi8(_mm_loadu_si128(big_ptr));+        if (result == 0) {+          ptr += 16;+          // Try one more.+          result = _mm_movemask_epi8(_mm_loadu_si128(big_ptr + 1));+          if (result == 0) {+            ptr += 16;+            // And one more.+            result = _mm_movemask_epi8(_mm_loadu_si128(big_ptr + 2));+            if (result == 0) {+              ptr += 16;+              // Last one.+              result = _mm_movemask_epi8(_mm_loadu_si128(big_ptr + 3));+              if (result == 0) {+                ptr += 16;+              } else {+                ptr += __builtin_ctz(result);+              }+            } else {+              ptr += __builtin_ctz(result);+            }+          } else {+            ptr += __builtin_ctz(result);+          }+        } else {+          ptr += __builtin_ctz(result);+        }+      }+    }+    // Check for a valid 2-byte sequence.+    //+    // We use a signed comparison to avoid an extra comparison with 0x80, since+    // _signed_ 0x80 is -128.+    else if (ptr + 1 < end && byte >= 0xC2 && byte <= 0xDF &&+             ((int8_t) * (ptr + 1)) <= (int8_t)0xBF) {+      ptr += 2;+    }+    // Check for a valid 3-byte sequence.+    else if (ptr + 2 < end) {+      uint8_t const byte2 = *(ptr + 1);+      bool byte2_valid = (int8_t)byte2 <= (int8_t)0xBF;+      bool byte3_valid = ((int8_t) * (ptr + 2)) <= (int8_t)0xBF;+      if (byte2_valid && byte3_valid &&+          // E0, A0..BF, 80..BF+          ((byte == 0xE0 && byte2 >= 0xA0) ||+           // E1..EC, 80..BF, 80..BF+           (byte >= 0xE1 && byte <= 0xEC) ||+           // ED, 80..9F, 80..BF+           (byte == 0xED && byte2 <= 0x9F) ||+           // EE..EF, 80..BF, 80..BF+           (byte >= 0xEE && byte <= 0xEF))) {+        ptr += 3;+      } else {+        return 0;+      }+    }+    // Check for a valid 4-byte sequence.+    else if (ptr + 3 < end) {+      uint8_t const byte2 = *(ptr + 1);+      bool byte2_valid = (int8_t)byte2 <= (int8_t)0xBF;+      bool byte3_valid = ((int8_t) * (ptr + 2)) <= (int8_t)0xBF;+      bool byte4_valid = ((int8_t) * (ptr + 3)) <= (int8_t)0xBF;+      if (byte2_valid && byte3_valid && byte4_valid &&+          // F0, 90..BF, 80..BF, 80..BF+          ((byte == 0xF0 && byte2 >= 0x90) ||+           // F1..F3, 80..BF, 80..BF, 80..BF+           (byte >= 0xF1 && byte <= 0xF3) ||+           // F4, 80..8F, 80..BF, 80..BF+           (byte == 0xF4 && byte2 <= 0x8F))) {+        ptr += 4;+      } else {+        return 0;+      }+    }+    // Otherwise, invalid.+    else {+      return 0;+    }+  }+  // If we got this far, we're valid.+  return 1;+}++// SSSE3++// Lookup tables++// Map high nibble the first byte to legal character length minus 1+// [0x00, 0xBF] --> 0+// [0xC0, 0xDF] --> 1+// [0xE0, 0xEF] --> 2+// [0xF0, 0xFF] --> 3+static int8_t const first_len_lookup[16] = {+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3,+};++// Map first byte to 8th item of range table if it's in [0xC2, 0xF4]+static int8_t const first_range_lookup[16] = {+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8,+};++// Range tables, mapping range index to min and max values+// Index 0    : 00 ~ 7F (First Byte, ascii)+// Index 1,2,3: 80 ~ BF (Second, Third, Fourth Byte)+// Index 4    : A0 ~ BF (Second Byte after E0)+// Index 5    : 80 ~ 9F (Second Byte after ED)+// Index 6    : 90 ~ BF (Second Byte after F0)+// Index 7    : 80 ~ 8F (Second Byte after F4)+// Index 8    : C2 ~ F4 (First Byte, non ascii)+// Index 9~15 : illegal: i >= 127 && i <= -128+static int8_t const range_min_lookup[16] = {+    0x00, 0x80, 0x80, 0x80, 0xA0, 0x80, 0x90, 0x80,+    0xC2, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F,+};++static int8_t const range_max_lookup[16] = {+    0x7F, 0xBF, 0xBF, 0xBF, 0xBF, 0x9F, 0xBF, 0x8F,+    0xF4, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,+};++// Tables for fast handling of four special First Bytes(E0,ED,F0,F4), after+// which the Second Byte are not 80~BF. It contains "range index adjustment".+// +------------+---------------+------------------+----------------++// | First Byte | original range| range adjustment | adjusted range |+// +------------+---------------+------------------+----------------++// | E0         | 2             | 2                | 4              |+// +------------+---------------+------------------+----------------++// | ED         | 2             | 3                | 5              |+// +------------+---------------+------------------+----------------++// | F0         | 3             | 3                | 6              |+// +------------+---------------+------------------+----------------++// | F4         | 4             | 4                | 8              |+// +------------+---------------+------------------+----------------++// index1 -> E0, index14 -> ED+static int8_t const df_ee_lookup[16] = {+    0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0,+};++// index1 -> F0, index5 -> F4+static int8_t const ef_fe_lookup[16] = {+    0, 3, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,+};++__attribute__((target("ssse3"))) static inline bool+is_ascii_sse2(__m128i const *src) {+  // OR together everything, then check for a high bit anywhere.+  __m128i const ored =+      _mm_or_si128(_mm_or_si128(src[0], src[1]), _mm_or_si128(src[2], src[3]));+  return (_mm_movemask_epi8(ored) == 0);+}++__attribute__((target("ssse3"))) static inline __m128i+high_nibbles_of(__m128i const src) {+  return _mm_and_si128(_mm_srli_epi16(src, 4), _mm_set1_epi8(0x0F));+}++__attribute__((target("ssse3"))) static inline __m128i+check_block_sse3(__m128i prev_input, __m128i prev_first_len,+                 __m128i const errors, __m128i const first_range_tbl,+                 __m128i const range_min_tbl, __m128i const range_max_tbl,+                 __m128i const df_ee_tbl, __m128i const ef_fe_tbl,+                 __m128i const input, __m128i const first_len) {+  // Get the high 4-bits of the input.+  __m128i const high_nibbles =+      _mm_and_si128(_mm_srli_epi16(input, 4), _mm_set1_epi8(0x0F));+  // Set range index to 8 for bytes in [C0, FF] by lookup (first byte).+  __m128i range = _mm_shuffle_epi8(first_range_tbl, high_nibbles);+  // Reduce the range index based on first_len (second byte)+  // This is 0 for [00, 7F], 1 for [C0, DF], 2 for [E0, EF], 3 for [F0, FF].+  range = _mm_or_si128(range, _mm_alignr_epi8(first_len, prev_first_len, 15));+  // Set range index to the saturation of (first_len - 1) (third byte).+  // This is 0 for [00, 7F], 0 for [C0, DF], 1 for [E0, EF], 2 for [F0, FF].+  __m128i tmp = _mm_alignr_epi8(first_len, prev_first_len, 14);+  tmp = _mm_subs_epu8(tmp, _mm_set1_epi8(1));+  range = _mm_or_si128(range, tmp);+  // Set range index to the saturation of (first_len - 2) (fourth byte).+  // This is 0 for [00, 7F], 0 for [C0, DF], 0 for [E0, EF] and 1 for [F0, FF].+  tmp = _mm_alignr_epi8(first_len, prev_first_len, 13);+  tmp = _mm_subs_epu8(tmp, _mm_set1_epi8(2));+  range = _mm_or_si128(range, tmp);+  // At this stage, we have calculated range indices correctly, except for+  // special cases for first bytes (E0, ED, F0, F4). We repair this to avoid+  // missing in the range table.+  __m128i const shift1 = _mm_alignr_epi8(input, prev_input, 15);+  __m128i const pos = _mm_sub_epi8(shift1, _mm_set1_epi8(0xEF));+  tmp = _mm_subs_epu8(pos, _mm_set1_epi8(0xF0));+  __m128i range2 = _mm_shuffle_epi8(df_ee_tbl, tmp);+  tmp = _mm_adds_epu8(pos, _mm_set1_epi8(0x70));+  range2 = _mm_add_epi8(range2, _mm_shuffle_epi8(ef_fe_tbl, tmp));+  range = _mm_add_epi8(range, range2);+  // We can now load minimum and maximum values from our tables based on the+  // calculated indices.+  __m128i const minv = _mm_shuffle_epi8(range_min_tbl, range);+  __m128i const maxv = _mm_shuffle_epi8(range_max_tbl, range);+  // Calculate the error (if any).+  tmp = _mm_or_si128(_mm_cmplt_epi8(input, minv), _mm_cmpgt_epi8(input, maxv));+  // Accumulate error.+  return _mm_or_si128(errors, tmp);+}++__attribute__((target("ssse3"))) static inline int+is_valid_utf8_ssse3(uint8_t const *const src, size_t const len) {+  // We stride 64 bytes at a time.+  size_t const big_strides = len / 64;+  size_t const remaining = len % 64;+  uint8_t const *ptr = (uint8_t const *)src;+  // Tracking state.+  __m128i prev_input = _mm_setzero_si128();+  __m128i prev_first_len = _mm_setzero_si128();+  __m128i errors = _mm_setzero_si128();+  for (size_t i = 0; i < big_strides; i++) {+    // Pre-load tables.+    __m128i const first_len_tbl =+        _mm_loadu_si128((__m128i const *)first_len_lookup);+    __m128i const first_range_tbl =+        _mm_loadu_si128((__m128i const *)first_range_lookup);+    __m128i const range_min_tbl =+        _mm_loadu_si128((__m128i const *)range_min_lookup);+    __m128i const range_max_tbl =+        _mm_loadu_si128((__m128i const *)range_max_lookup);+    __m128i const df_ee_tbl = _mm_loadu_si128((__m128i const *)df_ee_lookup);+    __m128i const ef_fe_tbl = _mm_loadu_si128((__m128i const *)ef_fe_lookup);+    // Load 64 bytes.+    __m128i const *big_ptr = (__m128i const *)ptr;+    __m128i const inputs[4] = {+        _mm_loadu_si128(big_ptr), _mm_loadu_si128(big_ptr + 1),+        _mm_loadu_si128(big_ptr + 2), _mm_loadu_si128(big_ptr + 3)};+    // Check if we have ASCII.+    if (is_ascii_sse2(inputs)) {+      // Prev_first_len cheaply.+      prev_first_len =+          _mm_shuffle_epi8(first_len_tbl, high_nibbles_of(inputs[3]));+    } else {+      __m128i first_len =+          _mm_shuffle_epi8(first_len_tbl, high_nibbles_of(inputs[0]));+      errors = check_block_sse3(prev_input, prev_first_len, errors,+                                first_range_tbl, range_min_tbl, range_max_tbl,+                                df_ee_tbl, ef_fe_tbl, inputs[0], first_len);+      prev_first_len = first_len;+      first_len = _mm_shuffle_epi8(first_len_tbl, high_nibbles_of(inputs[1]));+      errors = check_block_sse3(inputs[0], prev_first_len, errors,+                                first_range_tbl, range_min_tbl, range_max_tbl,+                                df_ee_tbl, ef_fe_tbl, inputs[1], first_len);+      prev_first_len = first_len;+      first_len = _mm_shuffle_epi8(first_len_tbl, high_nibbles_of(inputs[2]));+      errors = check_block_sse3(inputs[1], prev_first_len, errors,+                                first_range_tbl, range_min_tbl, range_max_tbl,+                                df_ee_tbl, ef_fe_tbl, inputs[2], first_len);+      prev_first_len = first_len;+      first_len = _mm_shuffle_epi8(first_len_tbl, high_nibbles_of(inputs[3]));+      errors = check_block_sse3(inputs[2], prev_first_len, errors,+                                first_range_tbl, range_min_tbl, range_max_tbl,+                                df_ee_tbl, ef_fe_tbl, inputs[3], first_len);+      prev_first_len = first_len;+    }+    // Set prev_input based on last block.+    prev_input = inputs[3];+    // Advance.+    ptr += 64;+  }+  // Write out the error, check if it's OK.+  uint64_t results[2];+  _mm_storeu_si128((__m128i *)results, errors);+  if (results[0] != 0 || results[1] != 0) {+    return 0;+  }+  // 'Roll back' our pointer a little to prepare for a slow search of the rest.+  int16_t tokens[2];+  tokens[0] = _mm_extract_epi16(prev_input, 6);+  tokens[1] = _mm_extract_epi16(prev_input, 7);+  int8_t const *token_ptr = (int8_t const *)tokens;+  ptrdiff_t lookahead = 0;+  if (token_ptr[3] > (int8_t)0xBF) {+    lookahead = 1;+  } else if (token_ptr[2] > (int8_t)0xBF) {+    lookahead = 2;+  } else if (token_ptr[1] > (int8_t)0xBF) {+    lookahead = 3;+  }+  uint8_t const *const small_ptr = ptr - lookahead;+  size_t const small_len = remaining + lookahead;+  return is_valid_utf8_fallback(small_ptr, small_len);+}++// AVX2+//+// These work similarly to the SSSE3 version, but with registers twice the+// width.++static int8_t const first_len_lookup2[32] = {+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3,+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3,+};++static int8_t const first_range_lookup2[32] = {+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8,+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8,+};++static int8_t const range_min_lookup2[32] = {+    0x00, 0x80, 0x80, 0x80, 0xA0, 0x80, 0x90, 0x80, 0xC2, 0x7F, 0x7F,+    0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x00, 0x80, 0x80, 0x80, 0xA0, 0x80,+    0x90, 0x80, 0xC2, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F,+};++static int8_t const range_max_lookup2[32] = {+    0x7F, 0xBF, 0xBF, 0xBF, 0xBF, 0x9F, 0xBF, 0x8F, 0xF4, 0x80, 0x80,+    0x80, 0x80, 0x80, 0x80, 0x80, 0x7F, 0xBF, 0xBF, 0xBF, 0xBF, 0x9F,+    0xBF, 0x8F, 0xF4, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,+};++static int8_t const df_ee_lookup2[32] = {+    0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0,+    0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0,+};++static int8_t const ef_fe_lookup2[32] = {+    0, 3, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,+    0, 3, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,+};++__attribute__((target("avx,avx2"))) static inline __m256i+high_nibbles_of_avx2(__m256i const src) {+  return _mm256_and_si256(_mm256_srli_epi16(src, 4), _mm256_set1_epi8(0x0F));+}++__attribute__((target("avx,avx2"))) static inline __m256i+push_last_byte_of_a_to_b(__m256i const a, __m256i const b) {+  return _mm256_alignr_epi8(b, _mm256_permute2x128_si256(a, b, 0x21), 15);+}++__attribute__((target("avx,avx2"))) static inline __m256i+push_last_2bytes_of_a_to_b(__m256i const a, __m256i const b) {+  return _mm256_alignr_epi8(b, _mm256_permute2x128_si256(a, b, 0x21), 14);+}++__attribute__((target("avx,avx2"))) static inline __m256i+push_last_3bytes_of_a_to_b(__m256i const a, __m256i const b) {+  return _mm256_alignr_epi8(b, _mm256_permute2x128_si256(a, b, 0x21), 13);+}++__attribute__((target("avx,avx2"))) static inline void+check_block_avx2(__m256i const prev_input, __m256i const prev_first_len,+                 __m256i *errors, __m256i const first_range_tbl,+                 __m256i const range_min_tbl, __m256i const range_max_tbl,+                 __m256i const df_ee_tbl, __m256i const ef_fe_tbl,+                 __m256i const input, __m256i const first_len) {+  // Set range index to 8 for bytes in [C0, FF] by lookup (first byte).+  __m256i range =+      _mm256_shuffle_epi8(first_range_tbl, high_nibbles_of_avx2(input));+  // Reduce the range index based on first_len (second byte)+  // This is 0 for [00, 7F], 1 for [C0, DF], 2 for [E0, EF], 3 for [F0, FF].+  range = _mm256_or_si256(range,+                          push_last_byte_of_a_to_b(prev_first_len, first_len));+  // Set range index to the saturation of (first_len - 1) (third byte).+  // This is 0 for [00, 7F], 0 for [C0, DF], 1 for [E0, EF], 2 for [F0, FF].+  __m256i tmp1 = push_last_2bytes_of_a_to_b(prev_first_len, first_len);+  __m256i tmp2 = _mm256_subs_epu8(tmp1, _mm256_set1_epi8(0x01));+  range = _mm256_or_si256(range, tmp2);+  // Set range index to the saturation of (first_len - 2) (fourth byte).+  tmp1 = push_last_3bytes_of_a_to_b(prev_first_len, first_len);+  tmp2 = _mm256_subs_epu8(tmp1, _mm256_set1_epi8(0x02));+  range = _mm256_or_si256(range, tmp2);+  // At this stage, we have calculated range indices correctly, except for+  // special cases for first bytes (E0, ED, F0, F4). We repair this to avoid+  // missing in the range table.+  __m256i const shift1 = push_last_byte_of_a_to_b(prev_input, input);+  __m256i pos = _mm256_sub_epi8(shift1, _mm256_set1_epi8(0xEF));+  tmp1 = _mm256_subs_epu8(pos, _mm256_set1_epi8(0xF0));+  __m256i range2 = _mm256_shuffle_epi8(df_ee_tbl, tmp1);+  tmp2 = _mm256_adds_epu8(pos, _mm256_set1_epi8(0x70));+  range2 = _mm256_add_epi8(range2, _mm256_shuffle_epi8(ef_fe_tbl, tmp2));+  range = _mm256_add_epi8(range, range2);+  // We can now load minimum and maximum values from our tables based on the+  // calculated indices.+  __m256i const minv = _mm256_shuffle_epi8(range_min_tbl, range);+  __m256i const maxv = _mm256_shuffle_epi8(range_max_tbl, range);+  // Calculate the error, if any.+  errors[0] = _mm256_or_si256(errors[0], _mm256_cmpgt_epi8(minv, input));+  errors[1] = _mm256_or_si256(errors[1], _mm256_cmpgt_epi8(input, maxv));+}++__attribute__((target("avx,avx2"))) static inline int+is_valid_utf8_avx2(uint8_t const *const src, size_t const len) {+  // We stride 128 bytes at a time.+  size_t const big_strides = len / 128;+  size_t const remaining = len % 128;+  uint8_t const *ptr = (uint8_t const *)src;+  // Tracking state.+  __m256i prev_input = _mm256_setzero_si256();+  __m256i prev_first_len = _mm256_setzero_si256();+  __m256i errors[2] = {_mm256_setzero_si256(), _mm256_setzero_si256()};+  for (size_t i = 0; i < big_strides; i++) {+    // Pre-load tables.+    __m256i const first_len_tbl =+        _mm256_loadu_si256((__m256i const *)first_len_lookup2);+    __m256i const first_range_tbl =+        _mm256_loadu_si256((__m256i const *)first_range_lookup2);+    __m256i const range_min_tbl =+        _mm256_loadu_si256((__m256i const *)range_min_lookup2);+    __m256i const range_max_tbl =+        _mm256_loadu_si256((__m256i const *)range_max_lookup2);+    __m256i const df_ee_tbl =+        _mm256_loadu_si256((__m256i const *)df_ee_lookup2);+    __m256i const ef_fe_tbl =+        _mm256_loadu_si256((__m256i const *)ef_fe_lookup2);+    // Load 128 bytes.+    __m256i const *big_ptr = (__m256i const *)ptr;+    __m256i const inputs[4] = {+        _mm256_loadu_si256(big_ptr), _mm256_loadu_si256(big_ptr + 1),+        _mm256_loadu_si256(big_ptr + 2), _mm256_loadu_si256(big_ptr + 3)};+    // Check if we have ASCII.+    bool is_ascii = _mm256_movemask_epi8(_mm256_or_si256(+                        _mm256_or_si256(inputs[0], inputs[1]),+                        _mm256_or_si256(inputs[2], inputs[3]))) == 0;+    if (is_ascii) {+      // Prev_first_len cheaply+      prev_first_len =+          _mm256_shuffle_epi8(first_len_tbl, high_nibbles_of_avx2(inputs[3]));+    } else {+      __m256i first_len =+          _mm256_shuffle_epi8(first_len_tbl, high_nibbles_of_avx2(inputs[0]));+      check_block_avx2(prev_input, prev_first_len, errors, first_range_tbl,+                       range_min_tbl, range_max_tbl, df_ee_tbl, ef_fe_tbl,+                       inputs[0], first_len);+      prev_first_len = first_len;+      first_len =+          _mm256_shuffle_epi8(first_len_tbl, high_nibbles_of_avx2(inputs[1]));+      check_block_avx2(inputs[0], prev_first_len, errors, first_range_tbl,+                       range_min_tbl, range_max_tbl, df_ee_tbl, ef_fe_tbl,+                       inputs[1], first_len);+      prev_first_len = first_len;+      first_len =+          _mm256_shuffle_epi8(first_len_tbl, high_nibbles_of_avx2(inputs[2]));+      check_block_avx2(inputs[1], prev_first_len, errors, first_range_tbl,+                       range_min_tbl, range_max_tbl, df_ee_tbl, ef_fe_tbl,+                       inputs[2], first_len);+      prev_first_len = first_len;+      first_len =+          _mm256_shuffle_epi8(first_len_tbl, high_nibbles_of_avx2(inputs[3]));+      check_block_avx2(inputs[2], prev_first_len, errors, first_range_tbl,+                       range_min_tbl, range_max_tbl, df_ee_tbl, ef_fe_tbl,+                       inputs[3], first_len);+      prev_first_len = first_len;+    }+    // Set prev_input based on last block.+    prev_input = inputs[3];+    // Advance.+    ptr += 128;+  }+  // Write out the error, check if it's OK.+  __m256i const combined_errors = _mm256_or_si256(errors[0], errors[1]);+  if (_mm256_testz_si256(combined_errors, combined_errors) != 1) {+    return 0;+  }+  // 'Roll back' our pointer a little to prepare for a slow search of the rest.+  uint32_t tokens_blob = _mm256_extract_epi32(prev_input, 7);+  int8_t const *tokens = (int8_t const *)&tokens_blob;+  ptrdiff_t lookahead = 0;+  if (tokens[3] > (int8_t)0xBF) {+    lookahead = 1;+  } else if (tokens[2] > (int8_t)0xBF) {+    lookahead = 2;+  } else if (tokens[1] > (int8_t)0xBF) {+    lookahead = 3;+  }+  uint8_t const *const small_ptr = ptr - lookahead;+  size_t const small_len = remaining + lookahead;+  return is_valid_utf8_fallback(small_ptr, small_len);+}++#endif++#ifdef __x86_64__+static inline bool has_sse2() {+  uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0;+  __get_cpuid_count(1, 0, &eax, &ebx, &ecx, &edx);+  // https://en.wikipedia.org/wiki/CPUID#EAX=1:_Processor_Info_and_Feature_Bits+  return edx & (1 << 26);+}++static inline bool has_ssse3() {+  uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0;+  __get_cpuid_count(1, 0, &eax, &ebx, &ecx, &edx);+  // https://en.wikipedia.org/wiki/CPUID#EAX=1:_Processor_Info_and_Feature_Bits+  return ecx & (1 << 9);+}++static inline bool has_avx2() {+  uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0;+  __get_cpuid_count(7, 0, &eax, &ebx, &ecx, &edx);+  // https://en.wikipedia.org/wiki/CPUID#EAX=7,_ECX=0:_Extended_Features+  return ebx & (1 << 5);+}+#endif++typedef int (*is_valid_utf8_t) (uint8_t const *const, size_t const);++int bytestring_is_valid_utf8(uint8_t const *const src, size_t const len) {+  if (len == 0) {+    return 1;+  }+#ifdef __x86_64__+  static _Atomic is_valid_utf8_t s_impl = (is_valid_utf8_t)NULL;+  is_valid_utf8_t impl = atomic_load_explicit(&s_impl, memory_order_relaxed);+  if (!impl) {+    impl = has_avx2() ? is_valid_utf8_avx2 : (has_ssse3() ? is_valid_utf8_ssse3 : (has_sse2() ? is_valid_utf8_sse2 : is_valid_utf8_fallback));+    atomic_store_explicit(&s_impl, impl, memory_order_relaxed);+  }+  return (*impl)(src, len);+#else+  return is_valid_utf8_fallback(src, len);+#endif+}++#pragma GCC pop_options
+ tests/Builder.hs view
@@ -0,0 +1,14 @@+module Builder (testSuite) where++import qualified Data.ByteString.Builder.Tests+import qualified Data.ByteString.Builder.Prim.Tests+import           Test.Tasty (TestTree, testGroup)++testSuite :: TestTree+testSuite = testGroup "Builder"+  [ testGroup "Data.ByteString.Builder"+       Data.ByteString.Builder.Tests.tests++  , testGroup "Data.ByteString.Builder.BasicEncoding"+       Data.ByteString.Builder.Prim.Tests.tests+  ]
+ tests/IsValidUtf8.hs view
@@ -0,0 +1,301 @@+{-# LANGUAGE LambdaCase #-}++module IsValidUtf8 (testSuite) where++import Data.Bits (shiftR, (.&.), shiftL)+import Data.ByteString (ByteString)+import qualified Data.ByteString as B+import Data.Char (chr, ord)+import Data.Word (Word8)+import GHC.Exts (fromList)+import Test.QuickCheck (Property, forAll, (===))+import Test.QuickCheck.Arbitrary (Arbitrary (arbitrary, shrink))+import Test.QuickCheck.Gen (oneof, Gen, choose, vectorOf, listOf1, sized, resize,+                            elements)+import Test.Tasty (testGroup, adjustOption, TestTree)+import Test.Tasty.QuickCheck (testProperty, QuickCheckTests)++testSuite :: TestTree+testSuite = testGroup "UTF-8 validation" $ [+  adjustOption (max testCount) . testProperty "Valid UTF-8" $ goValid,+  adjustOption (max testCount) . testProperty "Invalid UTF-8" $ goInvalid,+  testGroup "Regressions" checkRegressions+  ]+  where+    goValid :: Property+    goValid = forAll arbitrary $+      \(ValidUtf8 ss) -> (B.isValidUtf8 . foldMap sequenceToBS $ ss) === True+    goInvalid :: Property+    goInvalid = forAll arbitrary $ +      \inv -> (B.isValidUtf8 . toByteString $ inv) === False+    testCount :: QuickCheckTests+    testCount = 1000++checkRegressions :: [TestTree]+checkRegressions = [+  testProperty "Too high code point" $ not $ B.isValidUtf8 tooHigh+  ]+  where+    tooHigh :: ByteString+    tooHigh = fromList $ replicate 56 48 ++ -- 56 ASCII zeroes+                         [244, 176, 181, 139] ++ -- our invalid sequence too high to be valid+                         (take 68 . cycle $ [194, 162]) -- 68 cent symbols++-- Helpers++data Utf8Sequence = +  One Word8 |+  Two Word8 Word8 |+  Three Word8 Word8 Word8 |+  Four Word8 Word8 Word8 Word8+  deriving (Eq)++instance Arbitrary Utf8Sequence where+  arbitrary = oneof [+    One <$> elements [0x00 .. 0x7F],+    Two <$> elements [0xC2 .. 0xDF] <*> elements [0x80 .. 0xBF],+    genThree,+    genFour+    ]+    where+      genThree :: Gen Utf8Sequence+      genThree = do+        w1 <- elements [0xE0 .. 0xED]+        w2 <- elements $ case w1 of +          0xE0 -> [0xA0 .. 0xBF]+          0xED -> [0x80 .. 0x9F]+          _ -> [0x80 .. 0xBF]+        w3 <- elements [0x80 .. 0xBF]+        pure . Three w1 w2 $ w3+      genFour :: Gen Utf8Sequence+      genFour = do+        w1 <- elements [0xF0 .. 0xF4]+        w2 <- elements $ case w1 of +          0xF0 -> [0x90 .. 0xBF]+          0xF4 -> [0x80 .. 0x8F]+          _ -> [0x80 .. 0xBF]+        w3 <- elements [0x80 .. 0xBF]+        w4 <- elements [0x80 .. 0xBF]+        pure . Four w1 w2 w3 $ w4+  shrink = \case+    One w1 -> One <$> case w1 of +      0x00 -> []+      _ -> [0x00 .. (w1 - 1)]+    Two w1 w2 -> case (w1, w2) of +      (0xC2, 0x80) -> allOnes+      _ -> (Two <$> [0xC2 .. (w1 - 1)] <*> [0x80 .. (w2 - 1)]) ++ allOnes+    Three w1 w2 w3 -> case (w1, w2, w3) of +      (0xE0, 0xA0, 0x80) -> allTwos ++ allOnes+      (0xE0, 0xA0, _) -> (Three 0xE0 0xA0 <$> [0x80 .. (w3 - 1)]) ++ allTwos ++ allOnes+      (0xE0, _, _) -> +        (Three 0xE0 <$> [0xA0 .. (w2 - 1)] <*> [0x80 .. (w3 - 1)]) ++ allTwos ++ allOnes+      _ -> do+        w1' <- [0xE0 .. (w1 - 1)]+        case w1' of +          0xE0 -> (Three 0xE0 <$> [0xA0 .. 0xBF] <*> [0x80 .. 0xBF]) ++ +                  allTwos ++ +                  allOnes+          _ -> (Three w1' <$> [0x80 .. 0xBF] <*> [0x80 .. 0xBF]) ++ +               allTwos ++ +               allOnes+    Four w1 w2 w3 w4 -> case (w1, w2, w3, w4) of +      (0xF0, 0x90, 0x80, 0x80) -> allThrees ++ allTwos ++ allOnes+      (0xF0, 0x90, 0x80, _) -> +        (Four 0xF0 0x90 0x80 <$> [0x80 .. (w4 - 1)]) ++ +        allThrees +++        allTwos +++        allOnes+      (0xF0, 0x90, _, _) -> +        (Four 0xF0 0x90 <$> [0x80 .. (w3 - 1)] <*> [0x80 .. (w4 - 1)]) +++        allThrees +++        allTwos +++        allOnes+      (0xF0, _, _, _) -> +        (Four 0xF0 <$> [0x90 .. (w2 - 1)] <*> [0x80 .. (w3 - 1)] <*> [0x80 .. (w4 - 1)]) +++        allThrees +++        allTwos +++        allOnes+      _ -> do+        w1' <- [0xF0 .. (w1 - 1)]+        case w1' of +          0xF0 -> (Four 0xF0 <$> [0x90 .. 0xBF] <*> [0x80 .. 0xBF] <*> [0x80 .. 0xBF]) +++                  allThrees +++                  allTwos +++                  allOnes+          _ -> (Four w1' <$> [0x80 .. 0xBF] <*> [0x80 .. 0xBF] <*> [0x80 .. 0xBF]) +++               allThrees +++               allTwos +++               allOnes++allOnes :: [Utf8Sequence]+allOnes = One <$> [0x00 .. 0x7F]++allTwos :: [Utf8Sequence]+allTwos = Two <$> [0xC2 .. 0xDF] <*> [0x80 .. 0xBF]++allThrees :: [Utf8Sequence]+allThrees = (Three 0xE0 <$> [0xA0 .. 0xBF] <*> [0x80 .. 0xBF]) ++ +            (Three 0xED <$> [0x80 .. 0x9F] <*> [0x80 .. 0xBF]) +++            (Three <$> [0xE1 .. 0xEC] <*> [0x80 .. 0xBF] <*> [0x80 .. 0xBF]) +++            (Three <$> [0xEE .. 0xEF] <*> [0x80 .. 0xBF] <*> [0x80 .. 0xBF])++sequenceToBS :: Utf8Sequence -> ByteString+sequenceToBS = B.pack . \case+  One w1 -> [w1]+  Two w1 w2 -> [w1, w2]+  Three w1 w2 w3 -> [w1, w2, w3]+  Four w1 w2 w3 w4 -> [w1, w2, w3, w4]++newtype ValidUtf8 = ValidUtf8 [Utf8Sequence]+  deriving (Eq)++instance Show ValidUtf8 where+  show (ValidUtf8 ss) = show . foldMap sequenceToBS $ ss++instance Arbitrary ValidUtf8 where+  arbitrary = ValidUtf8 <$> arbitrary+  shrink (ValidUtf8 ss) = ValidUtf8 <$> shrink ss++data InvalidUtf8 = InvalidUtf8 {+  prefix :: ByteString,+  invalid :: ByteString,+  suffix :: ByteString+  }+  deriving (Eq)++instance Show InvalidUtf8 where+  show i = "InvalidUtf8 {prefix = " ++ show (prefix i)+                  ++ ", invalid = " ++ show (invalid i)+                  ++ ", suffix = " ++ show (suffix i)+                  ++ ", asBS = "   ++ show (toByteString i)+                  ++ ", length = " ++ show (B.length . toByteString $ i)+                  ++ "}"++instance Arbitrary InvalidUtf8 where+  arbitrary = oneof+    [ InvalidUtf8 mempty <$> genInvalidUtf8 <*> pure mempty+    , InvalidUtf8 mempty <$> genInvalidUtf8 <*> genValidUtf8+    , InvalidUtf8 <$> genValidUtf8 <*> genInvalidUtf8 <*> pure mempty+    , InvalidUtf8 <$> genValidUtf8 <*> genInvalidUtf8 <*> genValidUtf8+    ]+  shrink (InvalidUtf8 p i s) = +    (InvalidUtf8 p i <$> shrinkBS s) +++    ((\p' -> InvalidUtf8 p' i s) <$> shrinkBS p)++toByteString :: InvalidUtf8 -> ByteString+toByteString (InvalidUtf8 p i s) = p `B.append` i `B.append` s++genInvalidUtf8 :: Gen ByteString+genInvalidUtf8 = B.pack <$> oneof [+    -- invalid leading byte of a 2-byte sequence+    (:) <$> choose (0xC0, 0xC1) <*> upTo 1 contByte+    -- invalid leading byte of a 4-byte sequence+  , (:) <$> choose (0xF5, 0xFF) <*> upTo 3 contByte+    -- 4-byte sequence greater than U+10FFF+  , do k <- choose (0x11, 0x13)+       let w0 = 0xF0 + (k `shiftR` 2)+       let w1 = 0x80 + ((k .&. 3) `shiftL` 4)+       ([w0, w1] ++) <$> vectorOf 2 contByte+    -- continuation bytes without a start byte+  , listOf1 contByte+    -- short 2-byte sequence+  , (:[]) <$> choose (0xC2, 0xDF)+    -- short 3-byte sequence+  , (:) <$> choose (0xE0, 0xEF) <*> upTo 1 contByte+    -- short 4-byte sequence+  , (:) <$> choose (0xF0, 0xF4) <*> upTo 2 contByte+    -- overlong encoding+  , do k <- choose (0, 0xFFFF)+       let c = chr k+       case k of +        _ | k < 0x80    -> oneof [ let (w, x)       = ord2 c in pure [w, x]+                                 , let (w, x, y)    = ord3 c in pure [w, x, y]+                                 , let (w, x, y, z) = ord4 c in pure [w, x, y, z] ]+          | k < 0x7FF   -> oneof [ let (w, x, y)    = ord3 c in pure [w, x, y]+                                 , let (w, x, y, z) = ord4 c in pure [w, x, y, z] ]+          | otherwise   -> oneof [ let (w, x, y, z) = ord4 c in pure [w, x, y, z] ]+  ]+  where+    contByte :: Gen Word8+    contByte = (0x80 +) <$> choose (0, 0x3F)+    upTo :: Int -> Gen a -> Gen [a]+    upTo n gen = do+      k <- choose (0, n)+      vectorOf k gen++genValidUtf8 :: Gen ByteString+genValidUtf8 = sized $ \size -> +  if size <= 0+  then pure mempty+  else oneof [+    B.append <$> genAscii <*> resize (size `div` 2) genValidUtf8,+    B.append <$> gen2Byte <*> resize (size `div` 2) genValidUtf8,+    B.append <$> gen3Byte <*> resize (size `div` 2) genValidUtf8,+    B.append <$> gen4Byte <*> resize (size `div` 2) genValidUtf8+    ]+  where+    genAscii :: Gen ByteString+    genAscii = B.pack . (:[]) <$> elements [0x00 .. 0x7F]+    gen2Byte :: Gen ByteString+    gen2Byte = do+      b1 <- elements [0xC2 .. 0xDF]+      b2 <- elements [0x80 .. 0xBF]+      pure . B.pack $ [b1, b2]+    gen3Byte :: Gen ByteString+    gen3Byte = do+      b1 <- elements [0xE0 .. 0xED]+      b2 <- elements $ case b1 of +        0xE0 -> [0xA0 .. 0xBF]+        0xED -> [0x80 .. 0x9F]+        _ -> [0x80 .. 0xBF]+      b3 <- elements [0x80 .. 0xBF]+      pure . B.pack $ [b1, b2, b3]+    gen4Byte :: Gen ByteString+    gen4Byte = do+      b1 <- elements [0xF0 .. 0xF4]+      b2 <- elements $ case b1 of +        0xF0 -> [0x90 .. 0xBF]+        0xF4 -> [0x80 .. 0x8F]+        _ -> [0x80 .. 0xBF]+      b3 <- elements [0x80 .. 0xBF]+      b4 <- elements [0x80 .. 0xBF]+      pure . B.pack $ [b1, b2, b3, b4]++shrinkBS :: ByteString -> [ByteString]+shrinkBS bs = B.pack <$> (shrink . B.unpack $ bs)++ord2 :: Char -> (Word8, Word8)+ord2 c = (x, y)+  where+    n :: Int+    n = ord c+    x :: Word8+    x = fromIntegral $ (n `shiftR` 6) + 0xC0+    y :: Word8+    y = fromIntegral $ (n .&. 0x3F) + 0x80++ord3 :: Char -> (Word8, Word8, Word8)+ord3 c = (x, y, z)+  where+    n :: Int+    n = ord c+    x :: Word8+    x = fromIntegral $ (n `shiftR` 12) + 0xE0+    y :: Word8+    y = fromIntegral $ ((n `shiftR` 6) .&. 0x3F) + 0x80+    z :: Word8+    z = fromIntegral $ (n .&. 0x3F) + 0x80++ord4 :: Char -> (Word8, Word8, Word8, Word8)+ord4 c = (x, y, z, a)+  where+    n :: Int+    n = ord c+    x :: Word8+    x = fromIntegral $ (n `shiftR` 18) + 0xF0+    y :: Word8+    y = fromIntegral $ ((n `shiftR` 12) .&. 0x3F) + 0x80+    z :: Word8+    z = fromIntegral $ ((n `shiftR` 6) .&. 0x3F) + 0x80+    a :: Word8+    a = fromIntegral $ (n .&. 0x3F) + 0x80
tests/LazyHClose.hs view
@@ -1,4 +1,4 @@-module Main (main) where+module LazyHClose (testSuite) where  import Control.Monad (void, forM_) import Data.ByteString.Internal (toForeignPtr)@@ -6,59 +6,59 @@ import Foreign.ForeignPtr (finalizeForeignPtr) import System.IO (openFile, openTempFile, hClose, hPutStrLn, IOMode(..)) import System.Posix.Internals (c_unlink)+import Test.Tasty (TestTree, testGroup, withResource)+import Test.Tasty.QuickCheck (testProperty, ioProperty)  import qualified Data.ByteString            as S import qualified Data.ByteString.Char8      as S8 import qualified Data.ByteString.Lazy       as L import qualified Data.ByteString.Lazy.Char8 as L8 -main :: IO ()-main = do-    let n = 1000-    (fn, h) <- openTempFile "." "lazy-hclose-test.tmp"-    hPutStrLn h "x"-    hClose h--    -------------------------------------------------------------------------    -- readFile tests--    putStrLn "Testing resource leaks for Strict.readFile"-    forM_ [1..n] $ const $ do-         r <- S.readFile fn-         appendFile fn "" -- will fail, if fn has not been closed yet--    putStrLn "Testing resource leaks for Lazy.readFile"-    forM_ [1..n] $ const $ do-         r <- L.readFile fn-         L.length r `seq` return ()-         appendFile fn "" -- will fail, if fn has not been closed yet+n :: Int+n = 1000 -    -- manage the resources explicitly.-    putStrLn "Testing resource leaks when converting lazy to strict"-    forM_ [1..n] $ const $ do-         let release c = finalizeForeignPtr fp where (fp,_,_) = toForeignPtr c-         r <- L.readFile fn-         mapM_ release (L.toChunks r)-         appendFile fn "" -- will fail, if fn has not been closed yet+testSuite :: TestTree+testSuite = withResource+  (do (fn, h) <- openTempFile "." "lazy-hclose-test.tmp"; hPutStrLn h "x"; hClose h; pure fn)+  removeFile $ \fn' ->+    testGroup "LazyHClose"+    [ testProperty "Testing resource leaks for Strict.readFile" $ ioProperty $+      forM_ [1..n] $ const $ do+        fn <- fn'+        r <- S.readFile fn+        appendFile fn "" -- will fail, if fn has not been closed yet -    -------------------------------------------------------------------------    -- hGetContents tests+    , testProperty "Testing resource leaks for Lazy.readFile" $ ioProperty $+      forM_ [1..n] $ const $ do+        fn <- fn'+        r <- L.readFile fn+        L.length r `seq` return ()+        appendFile fn "" -- will fail, if fn has not been closed yet -    putStrLn "Testing strict hGetContents"-    forM_ [1..n] $ const $ do-         h <- openFile fn ReadMode-         r <- S.hGetContents h-         S.last r `seq` return ()-         appendFile fn "" -- will fail, if fn has not been closed yet+    , testProperty "Testing resource leaks when converting lazy to strict" $ ioProperty $+      forM_ [1..n] $ const $ do+        fn <- fn'+        let release c = finalizeForeignPtr fp where (fp,_,_) = toForeignPtr c+        r <- L.readFile fn+        mapM_ release (L.toChunks r)+        appendFile fn "" -- will fail, if fn has not been closed yet -    putStrLn "Testing lazy hGetContents"-    forM_ [1..n] $ const $ do-         h <- openFile fn ReadMode-         r <- L.hGetContents h-         L.last r `seq` return ()-         appendFile fn "" -- will fail, if fn has not been closed yet+    , testProperty "Testing strict hGetContents" $ ioProperty $+      forM_ [1..n] $ const $ do+        fn <- fn'+        h <- openFile fn ReadMode+        r <- S.hGetContents h+        S.last r `seq` return ()+        appendFile fn "" -- will fail, if fn has not been closed yet -    removeFile fn+    , testProperty "Testing lazy hGetContents" $ ioProperty $+      forM_ [1..n] $ const $ do+        fn <- fn'+        h <- openFile fn ReadMode+        r <- L.hGetContents h+        L.last r `seq` return ()+        appendFile fn "" -- will fail, if fn has not been closed yet+    ]  removeFile :: String -> IO () removeFile fn = void $ withCString fn c_unlink
+ tests/Lift.hs view
@@ -0,0 +1,62 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE OverloadedStrings #-}+module Lift (testSuite) where++import           Test.Tasty (TestTree, testGroup)+import           Test.Tasty.QuickCheck (testProperty, (===))+import qualified Data.ByteString as BS+import qualified Data.ByteString.Lazy as LBS+import qualified Data.ByteString.Short as SBS+import qualified Language.Haskell.TH.Syntax as TH++testSuite :: TestTree+testSuite = testGroup "Lift"+  [ testGroup "strict"+    [ testProperty "normal" $+        let bs = "foobar" :: BS.ByteString in+        bs === $(TH.lift $ BS.pack [102,111,111,98,97,114])++    , testProperty "binary" $+        let bs = "\0\1\2\3\0\1\2\3" :: BS.ByteString in+        bs === $(TH.lift $ BS.pack [0,1,2,3,0,1,2,3])++#if MIN_VERSION_template_haskell(2,16,0)+    , testProperty "typed" $+        let bs = "\0\1\2\3\0\1\2\3" :: BS.ByteString in+        bs === $$(TH.liftTyped $ BS.pack [0,1,2,3,0,1,2,3])+#endif+    ]++  , testGroup "lazy"+    [ testProperty "normal" $+        let bs = "foobar" :: LBS.ByteString in+        bs === $(TH.lift $ LBS.pack [102,111,111,98,97,114])++    , testProperty "binary" $+        let bs = "\0\1\2\3\0\1\2\3" :: LBS.ByteString in+        bs === $(TH.lift $ LBS.pack [0,1,2,3,0,1,2,3])++#if MIN_VERSION_template_haskell(2,16,0)+    , testProperty "typed" $+        let bs = "\0\1\2\3\0\1\2\3" :: LBS.ByteString in+        bs === $$(TH.liftTyped $ LBS.pack [0,1,2,3,0,1,2,3])+#endif+    ]++  , testGroup "short"+    [ testProperty "normal" $+        let bs = "foobar" :: SBS.ShortByteString in+        bs === $(TH.lift $ SBS.pack [102,111,111,98,97,114])++    , testProperty "binary" $+        let bs = "\0\1\2\3\0\1\2\3" :: SBS.ShortByteString in+        bs === $(TH.lift $ SBS.pack [0,1,2,3,0,1,2,3])++#if MIN_VERSION_template_haskell(2,16,0)+    , testProperty "typed" $+        let bs = "\0\1\2\3\0\1\2\3" :: SBS.ShortByteString in+        bs === $$(TH.liftTyped $ SBS.pack [0,1,2,3,0,1,2,3])+#endif+    ]+  ]
+ tests/Main.hs view
@@ -0,0 +1,18 @@+module Main (main) where++import Test.Tasty++import qualified Builder+import qualified IsValidUtf8+import qualified LazyHClose+import qualified Lift+import qualified Properties++main :: IO ()+main = defaultMain $ testGroup "All"+  [ Builder.testSuite+  , IsValidUtf8.testSuite+  , LazyHClose.testSuite+  , Lift.testSuite+  , Properties.testSuite+  ]
tests/Properties.hs view
@@ -1,2556 +1,498 @@-{-# LANGUAGE CPP #-}-{-# LANGUAGE BangPatterns #-}-{-# LANGUAGE MagicHash #-}-{-# LANGUAGE UnboxedTuples #-}------ Must have rules off, otherwise the rewrite rules will replace the rhs--- with the lhs, and we only end up testing lhs == lhs---------- -fhpc interferes with rewrite rules firing.-----import Foreign.C.String (withCString)-import Foreign.Storable-import Foreign.ForeignPtr-import Foreign.Marshal.Alloc-import Foreign.Marshal.Array-import GHC.Ptr-import Test.Tasty.QuickCheck-import Control.Applicative-import Control.Monad-import Control.Concurrent-import Control.Exception-import System.Posix.Internals (c_unlink)--import Data.List-import Data.Char-import Data.Word-import Data.Maybe-import Data.Int (Int64)-import Data.Monoid-#if MIN_VERSION_base(4,9,0)-import Data.Semigroup-#endif-import GHC.Exts (Int(..), newPinnedByteArray#, unsafeFreezeByteArray#)-import GHC.ST (ST(..), runST)--import Text.Printf-import Data.String--import System.Environment-import System.IO--import Data.ByteString.Lazy (ByteString(..), pack , unpack)-import qualified Data.ByteString.Lazy as L-import Data.ByteString.Lazy.Internal (ByteString(..))--import qualified Data.ByteString            as P-import qualified Data.ByteString.Internal   as P-import qualified Data.ByteString.Unsafe     as P-import qualified Data.ByteString.Char8      as C-import qualified Data.ByteString.Short      as Short--import qualified Data.ByteString.Lazy.Char8 as LC-import qualified Data.ByteString.Lazy.Char8 as D--import qualified Data.ByteString.Lazy.Internal as L-import Prelude hiding (abs)--import Rules-import QuickCheckUtils-import Test.Tasty-import Test.Tasty.QuickCheck--toInt64 :: Int -> Int64-toInt64 = fromIntegral------- ByteString.Lazy.Char8 <=> ByteString.Char8-----prop_concatCC       = D.concat                `eq1`  C.concat-prop_nullCC         = D.null                  `eq1`  C.null-prop_reverseCC      = D.reverse               `eq1`  C.reverse-prop_transposeCC    = D.transpose             `eq1`  C.transpose-prop_groupCC        = D.group                 `eq1`  C.group-prop_groupByCC      = D.groupBy               `eq2`  C.groupBy-prop_initsCC        = D.inits                 `eq1`  C.inits-prop_tailsCC        = D.tails                 `eq1`  C.tails-prop_allCC          = D.all                   `eq2`  C.all-prop_anyCC          = D.any                   `eq2`  C.any-prop_appendCC       = D.append                `eq2`  C.append-prop_breakCC        = D.break                 `eq2`  C.break-prop_concatMapCC    = forAll (sized $ \n -> resize (min 50 n) arbitrary) $-                      D.concatMap             `eq2`  C.concatMap-prop_consCC         = D.cons                  `eq2`  C.cons-prop_consCC'        = D.cons'                 `eq2`  C.cons-prop_unconsCC       = D.uncons                `eq1`  C.uncons-prop_unsnocCC       = D.unsnoc                `eq1`  C.unsnoc-prop_countCC        = D.count                 `eq2`  ((toInt64 .) . C.count)-prop_dropCC         = (D.drop . toInt64)      `eq2`  C.drop-prop_dropWhileCC    = D.dropWhile             `eq2`  C.dropWhile-prop_filterCC       = D.filter                `eq2`  C.filter-prop_findCC         = D.find                  `eq2`  C.find-prop_findIndexCC    = D.findIndex             `eq2`  ((fmap toInt64 .) . C.findIndex)-prop_findIndexEndCC = D.findIndexEnd          `eq2`  ((fmap toInt64 .) . C.findIndexEnd)-prop_findIndicesCC  = D.findIndices           `eq2`  ((fmap toInt64 .) . C.findIndices)-prop_isPrefixOfCC   = D.isPrefixOf            `eq2`  C.isPrefixOf-prop_stripPrefixCC  = D.stripPrefix           `eq2`  C.stripPrefix-prop_isSuffixOfCC   = D.isSuffixOf            `eq2`  C.isSuffixOf-prop_stripSuffixCC  = D.stripSuffix           `eq2`  C.stripSuffix-prop_mapCC          = D.map                   `eq2`  C.map-prop_replicateCC    = forAll arbitrarySizedIntegral $-                      (D.replicate . toInt64) `eq2`  C.replicate-prop_snocCC         = D.snoc                  `eq2`  C.snoc-prop_spanCC         = D.span                  `eq2`  C.span-prop_splitCC        = D.split                 `eq2`  C.split-prop_splitAtCC      = (D.splitAt . toInt64)   `eq2`  C.splitAt-prop_takeCC         = (D.take    . toInt64)   `eq2`  C.take-prop_takeWhileCC    = D.takeWhile             `eq2`  C.takeWhile-prop_elemCC         = D.elem                  `eq2`  C.elem-prop_notElemCC      = D.notElem               `eq2`  C.notElem-prop_elemIndexCC    = D.elemIndex             `eq2`  ((fmap toInt64 .) . C.elemIndex)-prop_elemIndicesCC  = D.elemIndices           `eq2`  ((fmap toInt64 .) . C.elemIndices)-prop_lengthCC       = D.length                `eq1`  (toInt64 . C.length)--prop_headCC         = D.head        `eqnotnull1` C.head-prop_initCC         = D.init        `eqnotnull1` C.init-prop_lastCC         = D.last        `eqnotnull1` C.last-prop_maximumCC      = D.maximum     `eqnotnull1` C.maximum-prop_minimumCC      = D.minimum     `eqnotnull1` C.minimum-prop_tailCC         = D.tail        `eqnotnull1` C.tail-prop_foldl1CC       = D.foldl1      `eqnotnull2` C.foldl1-prop_foldl1CC'      = D.foldl1'     `eqnotnull2` C.foldl1'-prop_foldr1CC       = D.foldr1      `eqnotnull2` C.foldr1-prop_foldr1CC'      = D.foldr1      `eqnotnull2` C.foldr1'-prop_scanlCC        = D.scanl       `eqnotnull3` C.scanl--prop_intersperseCC = D.intersperse  `eq2` C.intersperse--prop_foldlCC     = eq3-    (D.foldl     :: (X -> Char -> X) -> X -> B -> X)-    (C.foldl     :: (X -> Char -> X) -> X -> P -> X)-prop_foldlCC'    = eq3-    (D.foldl'    :: (X -> Char -> X) -> X -> B -> X)-    (C.foldl'    :: (X -> Char -> X) -> X -> P -> X)-prop_foldrCC     = eq3-    (D.foldr     :: (Char -> X -> X) -> X -> B -> X)-    (C.foldr     :: (Char -> X -> X) -> X -> P -> X)-prop_foldrCC'    = eq3-    (D.foldr     :: (Char -> X -> X) -> X -> B -> X)-    (C.foldr'    :: (Char -> X -> X) -> X -> P -> X)-prop_mapAccumLCC = eq3-    (D.mapAccumL :: (X -> Char -> (X,Char)) -> X -> B -> (X, B))-    (C.mapAccumL :: (X -> Char -> (X,Char)) -> X -> P -> (X, P))----prop_mapIndexedCC = D.mapIndexed `eq2` C.mapIndexed---prop_mapIndexedPL = L.mapIndexed `eq2` P.mapIndexed----prop_mapAccumL_mapIndexedBP =---        P.mapIndexed `eq2`---        (\k p -> snd $ P.mapAccumL (\i w -> (i+1, k i w)) (0::Int) p)------- ByteString.Lazy <=> ByteString-----prop_concatBP       = forAll (sized $ \n -> resize (n `div` 2) arbitrary) $-                      L.concat               `eq1`  P.concat-prop_nullBP         = L.null                 `eq1`  P.null-prop_reverseBP      = L.reverse              `eq1`  P.reverse--prop_transposeBP    = L.transpose            `eq1`  P.transpose-prop_groupBP        = L.group                `eq1`  P.group-prop_groupByBP      = L.groupBy              `eq2`  P.groupBy-prop_initsBP        = L.inits                `eq1`  P.inits-prop_tailsBP        = L.tails                `eq1`  P.tails-prop_allBP          = L.all                  `eq2`  P.all-prop_anyBP          = L.any                  `eq2`  P.any-prop_appendBP       = L.append               `eq2`  P.append-prop_breakBP        = L.break                `eq2`  P.break-prop_concatMapBP    = forAll (sized $ \n -> resize (n `div` 4) arbitrary) $-                      L.concatMap            `eq2`  P.concatMap-prop_consBP         = L.cons                 `eq2`  P.cons-prop_consBP'        = L.cons'                `eq2`  P.cons-prop_unconsBP       = L.uncons               `eq1`  P.uncons-prop_unsnocBP       = L.unsnoc               `eq1`  P.unsnoc-prop_countBP        = L.count                `eq2`  ((toInt64 .) . P.count)-prop_dropBP         = (L.drop. toInt64)      `eq2`  P.drop-prop_dropWhileBP    = L.dropWhile            `eq2`  P.dropWhile-prop_filterBP       = L.filter               `eq2`  P.filter-prop_findBP         = L.find                 `eq2`  P.find-prop_findIndexBP    = L.findIndex            `eq2`  ((fmap toInt64 .) . P.findIndex)-prop_findIndexEndBP = L.findIndexEnd         `eq2`  ((fmap toInt64 .) . P.findIndexEnd)-prop_findIndicesBP  = L.findIndices          `eq2`  ((fmap toInt64 .) . P.findIndices)-prop_isPrefixOfBP   = L.isPrefixOf           `eq2`  P.isPrefixOf-prop_stripPrefixBP  = L.stripPrefix          `eq2`  P.stripPrefix-prop_isSuffixOfBP   = L.isSuffixOf           `eq2`  P.isSuffixOf-prop_stripSuffixBP  = L.stripSuffix          `eq2`  P.stripSuffix-prop_mapBP          = L.map                  `eq2`  P.map-prop_replicateBP    = forAll arbitrarySizedIntegral $-                      (L.replicate. toInt64) `eq2`  P.replicate-prop_snocBP         = L.snoc                 `eq2`  P.snoc-prop_spanBP         = L.span                 `eq2`  P.span-prop_splitBP        = L.split                `eq2`  P.split-prop_splitAtBP      = (L.splitAt. toInt64)   `eq2`  P.splitAt-prop_takeBP         = (L.take   . toInt64)   `eq2`  P.take-prop_takeWhileBP    = L.takeWhile            `eq2`  P.takeWhile-prop_elemBP         = L.elem                 `eq2`  P.elem-prop_notElemBP      = L.notElem              `eq2`  P.notElem-prop_elemIndexBP    = L.elemIndex            `eq2`  ((fmap toInt64 .) . P.elemIndex)-prop_elemIndexEndBP = L.elemIndexEnd         `eq2`  ((fmap toInt64 .) . P.elemIndexEnd)-prop_elemIndicesBP  = L.elemIndices          `eq2`  ((fmap toInt64 .) . P.elemIndices)-prop_intersperseBP  = L.intersperse          `eq2`  P.intersperse-prop_lengthBP       = L.length               `eq1`  (toInt64 . P.length)-prop_readIntBP      = D.readInt              `eq1`  C.readInt-prop_linesBP        = D.lines                `eq1`  C.lines---- double check:--- Currently there's a bug in the lazy bytestring version of lines, this--- catches it:-prop_linesNLBP      = eq1 D.lines C.lines x-    where x = D.pack "one\ntwo\n\n\nfive\n\nseven\n"--prop_headBP         = L.head        `eqnotnull1` P.head-prop_initBP         = L.init        `eqnotnull1` P.init-prop_lastBP         = L.last        `eqnotnull1` P.last-prop_maximumBP      = L.maximum     `eqnotnull1` P.maximum-prop_minimumBP      = L.minimum     `eqnotnull1` P.minimum-prop_tailBP         = L.tail        `eqnotnull1` P.tail-prop_foldl1BP       = L.foldl1      `eqnotnull2` P.foldl1-prop_foldl1BP'      = L.foldl1'     `eqnotnull2` P.foldl1'-prop_foldr1BP       = L.foldr1      `eqnotnull2` P.foldr1-prop_foldr1BP'      = L.foldr1      `eqnotnull2` P.foldr1'-prop_scanlBP        = L.scanl       `eqnotnull3` P.scanl---prop_eqBP        = eq2-    ((==) :: B -> B -> Bool)-    ((==) :: P -> P -> Bool)-prop_compareBP   = eq2-    ((compare) :: B -> B -> Ordering)-    ((compare) :: P -> P -> Ordering)-prop_foldlBP     = eq3-    (L.foldl     :: (X -> W -> X) -> X -> B -> X)-    (P.foldl     :: (X -> W -> X) -> X -> P -> X)-prop_foldlBP'    = eq3-    (L.foldl'    :: (X -> W -> X) -> X -> B -> X)-    (P.foldl'    :: (X -> W -> X) -> X -> P -> X)-prop_foldrBP     = eq3-    (L.foldr     :: (W -> X -> X) -> X -> B -> X)-    (P.foldr     :: (W -> X -> X) -> X -> P -> X)-prop_foldrBP'    = eq3-    (L.foldr     :: (W -> X -> X) -> X -> B -> X)-    (P.foldr'    :: (W -> X -> X) -> X -> P -> X)-prop_mapAccumLBP = eq3-    (L.mapAccumL :: (X -> W -> (X,W)) -> X -> B -> (X, B))-    (P.mapAccumL :: (X -> W -> (X,W)) -> X -> P -> (X, P))--prop_unfoldrBP   =-  forAll arbitrarySizedIntegral $-  eq3-    ((\n f a -> L.take (fromIntegral n) $-        L.unfoldr    f a) :: Int -> (X -> Maybe (W,X)) -> X -> B)-    ((\n f a ->                     fst $-        P.unfoldrN n f a) :: Int -> (X -> Maybe (W,X)) -> X -> P)--prop_unfoldr2BP   =-  forAll arbitrarySizedIntegral $ \n ->-  forAll arbitrarySizedIntegral $ \a ->-  eq2-    ((\n a -> P.take (n*100) $-        P.unfoldr    (\x -> if x <= (n*100) then Just (fromIntegral x, x + 1) else Nothing) a)-                :: Int -> Int -> P)-    ((\n a ->                     fst $-        P.unfoldrN (n*100) (\x -> if x <= (n*100) then Just (fromIntegral x, x + 1) else Nothing) a)-                :: Int -> Int -> P)-    n a--prop_unfoldr2CP   =-  forAll arbitrarySizedIntegral $ \n ->-  forAll arbitrarySizedIntegral $ \a ->-  eq2-    ((\n a -> C.take (n*100) $-        C.unfoldr    (\x -> if x <= (n*100) then Just (chr (x `mod` 256), x + 1) else Nothing) a)-                :: Int -> Int -> P)-    ((\n a ->                     fst $-        C.unfoldrN (n*100) (\x -> if x <= (n*100) then Just (chr (x `mod` 256), x + 1) else Nothing) a)-                :: Int -> Int -> P)-    n a---prop_unfoldrLC   =-  forAll arbitrarySizedIntegral $-  eq3-    ((\n f a -> LC.take (fromIntegral n) $-        LC.unfoldr    f a) :: Int -> (X -> Maybe (Char,X)) -> X -> B)-    ((\n f a ->                     fst $-        C.unfoldrN n f a) :: Int -> (X -> Maybe (Char,X)) -> X -> P)--prop_cycleLC  a   =-  not (LC.null a) ==>-  forAll arbitrarySizedIntegral $-  eq1-    ((\n   -> LC.take (fromIntegral n) $-              LC.cycle a-     ) :: Int -> B)--    ((\n   -> LC.take (fromIntegral (n::Int)) . LC.concat $-              unfoldr (\x ->  Just (x,x) ) a-     ) :: Int -> B)---prop_iterateLC :: Int -> (Char8 -> Char8) -> Char8 -> Bool-prop_iterateLC n f (Char8 c) =-  eq3-    (\n f a -> LC.take (fromIntegral n) $ LC.iterate  f a)-    (\n f a -> fst $ C.unfoldrN n (\a -> Just (f a, f a)) a)-    n-    (castFn f :: Char -> Char)-    c--prop_iterateLC_2 :: Int -> (Char8 -> Char8) -> Char8 -> Bool-prop_iterateLC_2 n f (Char8 c) =-  eq3-    (\n f a -> LC.take (fromIntegral (n :: Int)) $ LC.iterate f a)-    (\n f a -> LC.take (fromIntegral (n :: Int)) $ LC.unfoldr (\a -> Just (f a, f a)) a)-    n-    (castFn f :: Char -> Char)-    c--prop_iterateL   =-  forAll arbitrarySizedIntegral $-  eq3-    ((\n f a -> L.take (fromIntegral n) $-        L.iterate  f a) :: Int -> (W -> W) -> W -> B)-    ((\n f a -> fst $-        P.unfoldrN n (\a -> Just (f a, f a)) a) :: Int -> (W -> W) -> W -> P)--prop_repeatLC   =-  forAll arbitrarySizedIntegral $-  eq2-    ((\n a -> LC.take (fromIntegral n) $-        LC.repeat a) :: Int -> Char -> B)-    ((\n a -> fst $-        C.unfoldrN n (\a -> Just (a, a)) a) :: Int -> Char -> P)--prop_repeatL   =-  forAll arbitrarySizedIntegral $-  eq2-    ((\n a -> L.take (fromIntegral n) $-        L.repeat a) :: Int -> W -> B)-    ((\n a -> fst $-        P.unfoldrN n (\a -> Just (a, a)) a) :: Int -> W -> P)------- properties comparing ByteString.Lazy `eq1` List-----prop_concatBL       = forAll (sized $ \n -> resize (n `div` 2) arbitrary) $-                      L.concat                `eq1` (concat    :: [[W]] -> [W])-prop_lengthBL       = L.length                `eq1` (toInt64 . length    :: [W] -> Int64)-prop_nullBL         = L.null                  `eq1` (null      :: [W] -> Bool)-prop_reverseBL      = L.reverse               `eq1` (reverse   :: [W] -> [W])-prop_transposeBL    = L.transpose             `eq1` (transpose :: [[W]] -> [[W]])-prop_groupBL        = L.group                 `eq1` (group     :: [W] -> [[W]])-prop_groupByBL      = L.groupBy               `eq2` (groupBy   :: (W -> W -> Bool) -> [W] -> [[W]])-prop_initsBL        = L.inits                 `eq1` (inits     :: [W] -> [[W]])-prop_tailsBL        = L.tails                 `eq1` (tails     :: [W] -> [[W]])-prop_allBL          = L.all                   `eq2` (all       :: (W -> Bool) -> [W] -> Bool)-prop_anyBL          = L.any                   `eq2` (any       :: (W -> Bool) -> [W] -> Bool)-prop_appendBL       = L.append                `eq2` ((++)      :: [W] -> [W] -> [W])-prop_breakBL        = L.break                 `eq2` (break     :: (W -> Bool) -> [W] -> ([W],[W]))-prop_concatMapBL    = forAll (sized $ \n -> resize (n `div` 2) arbitrary) $-                      L.concatMap             `eq2` (concatMap :: (W -> [W]) -> [W] -> [W])-prop_consBL         = L.cons                  `eq2` ((:)       :: W -> [W] -> [W])-prop_dropBL         = (L.drop . toInt64)      `eq2` (drop      :: Int -> [W] -> [W])-prop_dropWhileBL    = L.dropWhile             `eq2` (dropWhile :: (W -> Bool) -> [W] -> [W])-prop_filterBL       = L.filter                `eq2` (filter    :: (W -> Bool ) -> [W] -> [W])-prop_findBL         = L.find                  `eq2` (find      :: (W -> Bool) -> [W] -> Maybe W)-prop_findIndicesBL  = L.findIndices           `eq2` ((fmap toInt64 .) . findIndices:: (W -> Bool) -> [W] -> [Int64])-prop_findIndexBL    = L.findIndex             `eq2` ((fmap toInt64 .) . findIndex :: (W -> Bool) -> [W] -> Maybe Int64)-prop_findIndexEndBL = L.findIndexEnd          `eq2` ((fmap toInt64 .) . findIndexEnd :: (W -> Bool) -> [W] -> Maybe Int64)-prop_isPrefixOfBL   = L.isPrefixOf            `eq2` (isPrefixOf:: [W] -> [W] -> Bool)-prop_stripPrefixBL  = L.stripPrefix           `eq2` (stripPrefix:: [W] -> [W] -> Maybe [W])-prop_isSuffixOfBL   = L.isSuffixOf            `eq2` (isSuffixOf:: [W] -> [W] -> Bool)-prop_stripSuffixBL  = L.stripSuffix           `eq2` (stripSuffix :: [W] -> [W] -> Maybe [W])-prop_mapBL          = L.map                   `eq2` (map       :: (W -> W) -> [W] -> [W])-prop_replicateBL    = forAll arbitrarySizedIntegral $-                      (L.replicate . toInt64) `eq2` (replicate :: Int -> W -> [W])-prop_snocBL         = L.snoc                  `eq2` ((\xs x -> xs ++ [x]) :: [W] -> W -> [W])-prop_spanBL         = L.span                  `eq2` (span      :: (W -> Bool) -> [W] -> ([W],[W]))-prop_splitAtBL      = (L.splitAt . toInt64)   `eq2` (splitAt :: Int -> [W] -> ([W],[W]))-prop_takeBL         = (L.take    . toInt64)   `eq2` (take    :: Int -> [W] -> [W])-prop_takeWhileBL    = L.takeWhile             `eq2` (takeWhile :: (W -> Bool) -> [W] -> [W])-prop_elemBL         = L.elem                  `eq2` (elem      :: W -> [W] -> Bool)-prop_notElemBL      = L.notElem               `eq2` (notElem   :: W -> [W] -> Bool)-prop_elemIndexBL    = L.elemIndex             `eq2` ((fmap toInt64 .) . elemIndex   :: W -> [W] -> Maybe Int64)-prop_elemIndexEndBL = L.elemIndexEnd          `eq2` ((fmap toInt64 .) . elemIndexEnd:: W -> [W] -> Maybe Int64)-prop_elemIndicesBL  = L.elemIndices           `eq2` ((fmap toInt64 .) . elemIndices :: W -> [W] -> [Int64])-prop_linesBL        = D.lines                 `eq1` (lines     :: String -> [String])--prop_foldl1BL       = L.foldl1  `eqnotnull2` (foldl1    :: (W -> W -> W) -> [W] -> W)-prop_foldl1BL'      = L.foldl1' `eqnotnull2` (foldl1'   :: (W -> W -> W) -> [W] -> W)-prop_foldr1BL       = L.foldr1  `eqnotnull2` (foldr1    :: (W -> W -> W) -> [W] -> W)-prop_headBL         = L.head    `eqnotnull1` (head      :: [W] -> W)-prop_initBL         = L.init    `eqnotnull1` (init      :: [W] -> [W])-prop_lastBL         = L.last    `eqnotnull1` (last      :: [W] -> W)-prop_maximumBL      = L.maximum `eqnotnull1` (maximum   :: [W] -> W)-prop_minimumBL      = L.minimum `eqnotnull1` (minimum   :: [W] -> W)-prop_tailBL         = L.tail    `eqnotnull1` (tail      :: [W] -> [W])--prop_eqBL         = eq2-    ((==) :: B   -> B   -> Bool)-    ((==) :: [W] -> [W] -> Bool)-prop_compareBL    = eq2-    ((compare) :: B   -> B   -> Ordering)-    ((compare) :: [W] -> [W] -> Ordering)-prop_foldlBL      = eq3-    (L.foldl  :: (X -> W -> X) -> X -> B   -> X)-    (  foldl  :: (X -> W -> X) -> X -> [W] -> X)-prop_foldlBL'     = eq3-    (L.foldl' :: (X -> W -> X) -> X -> B   -> X)-    (  foldl' :: (X -> W -> X) -> X -> [W] -> X)-prop_foldrBL      = eq3-    (L.foldr  :: (W -> X -> X) -> X -> B   -> X)-    (  foldr  :: (W -> X -> X) -> X -> [W] -> X)-prop_mapAccumLBL  = eq3-    (L.mapAccumL :: (X -> W -> (X,W)) -> X -> B   -> (X, B))-    (  mapAccumL :: (X -> W -> (X,W)) -> X -> [W] -> (X, [W]))--prop_mapAccumRBL  = eq3-    (L.mapAccumR :: (X -> W -> (X,W)) -> X -> B   -> (X, B))-    (  mapAccumR :: (X -> W -> (X,W)) -> X -> [W] -> (X, [W]))--prop_mapAccumRDL :: (X -> Char8 -> (X, Char8)) -> X -> B -> Bool-prop_mapAccumRDL f = eq3-    (D.mapAccumR :: (X -> Char -> (X,Char)) -> X -> B   -> (X, B))-    (  mapAccumR :: (X -> Char -> (X,Char)) -> X -> [Char] -> (X, [Char]))-    (castFn f)--prop_mapAccumRCC :: (X -> Char8 -> (X, Char8)) -> X -> P -> Bool-prop_mapAccumRCC f = eq3-    (C.mapAccumR :: (X -> Char -> (X,Char)) -> X -> P   -> (X, P))-    (  mapAccumR :: (X -> Char -> (X,Char)) -> X -> [Char] -> (X, [Char]))-    (castFn f)--prop_unfoldrBL =-  forAll arbitrarySizedIntegral $-  eq3-    ((\n f a -> L.take (fromIntegral n) $-        L.unfoldr f a) :: Int -> (X -> Maybe (W,X)) -> X -> B)-    ((\n f a ->                  take n $-          unfoldr f a) :: Int -> (X -> Maybe (W,X)) -> X -> [W])--prop_packZipWithBL   = L.packZipWith `eq3` (zipWith :: (W -> W -> W) -> [W] -> [W] -> [W])------- And finally, check correspondance between Data.ByteString and List-----prop_lengthPL     = (fromIntegral.P.length :: P -> Int) `eq1` (length :: [W] -> Int)-prop_nullPL       = P.null      `eq1` (null      :: [W] -> Bool)-prop_reversePL    = P.reverse   `eq1` (reverse   :: [W] -> [W])-prop_transposePL  = P.transpose `eq1` (transpose :: [[W]] -> [[W]])-prop_groupPL      = P.group     `eq1` (group     :: [W] -> [[W]])-prop_groupByPL    = P.groupBy   `eq2` (groupBy   :: (W -> W -> Bool) -> [W] -> [[W]])-prop_initsPL      = P.inits     `eq1` (inits     :: [W] -> [[W]])-prop_tailsPL      = P.tails     `eq1` (tails     :: [W] -> [[W]])-prop_concatPL     = forAll (sized $ \n -> resize (n `div` 2) arbitrary) $-                    P.concat    `eq1` (concat    :: [[W]] -> [W])-prop_allPL        = P.all       `eq2` (all       :: (W -> Bool) -> [W] -> Bool)-prop_anyPL        = P.any       `eq2`    (any       :: (W -> Bool) -> [W] -> Bool)-prop_appendPL     = P.append    `eq2`    ((++)      :: [W] -> [W] -> [W])-prop_breakPL      = P.break     `eq2`    (break     :: (W -> Bool) -> [W] -> ([W],[W]))-prop_concatMapPL  = forAll (sized $ \n -> resize (n `div` 2) arbitrary) $-                    P.concatMap `eq2`    (concatMap :: (W -> [W]) -> [W] -> [W])-prop_consPL       = P.cons      `eq2`    ((:)       :: W -> [W] -> [W])-prop_dropPL       = P.drop      `eq2`    (drop      :: Int -> [W] -> [W])-prop_dropWhilePL  = P.dropWhile `eq2`    (dropWhile :: (W -> Bool) -> [W] -> [W])-prop_filterPL     = P.filter    `eq2`    (filter    :: (W -> Bool ) -> [W] -> [W])-prop_filterPL_rule= (\x -> P.filter ((==) x))  `eq2` -- test rules-                    ((\x -> filter ((==) x)) :: W -> [W] -> [W])---- under lambda doesn't fire?-prop_filterLC_rule= (f)  `eq2` -- test rules-                    ((\x -> filter ((==) x)) :: Char -> [Char] -> [Char])-    where-         f x s = LC.filter ((==) x) s--prop_partitionPL  = P.partition `eq2`    (partition :: (W -> Bool ) -> [W] -> ([W],[W]))-prop_partitionLL  = L.partition `eq2`    (partition :: (W -> Bool ) -> [W] -> ([W],[W]))-prop_findPL       = P.find      `eq2`    (find      :: (W -> Bool) -> [W] -> Maybe W)-prop_findIndexPL  = P.findIndex `eq2`    (findIndex :: (W -> Bool) -> [W] -> Maybe Int)-prop_findIndexEndPL = P.findIndexEnd `eq2` (findIndexEnd :: (W -> Bool) -> [W] -> Maybe Int)-prop_isPrefixOfPL = P.isPrefixOf`eq2`    (isPrefixOf:: [W] -> [W] -> Bool)-prop_isSuffixOfPL = P.isSuffixOf`eq2`    (isSuffixOf:: [W] -> [W] -> Bool)-prop_isInfixOfPL  = P.isInfixOf `eq2`    (isInfixOf:: [W] -> [W] -> Bool)-prop_stripPrefixPL = P.stripPrefix`eq2`  (stripPrefix:: [W] -> [W] -> Maybe [W])-prop_stripSuffixPL = P.stripSuffix`eq2`  (stripSuffix:: [W] -> [W] -> Maybe [W])-prop_mapPL        = P.map       `eq2`    (map       :: (W -> W) -> [W] -> [W])-prop_replicatePL  = forAll arbitrarySizedIntegral $-                    P.replicate `eq2`    (replicate :: Int -> W -> [W])-prop_snocPL       = P.snoc      `eq2`    ((\xs x -> xs ++ [x]) :: [W] -> W -> [W])-prop_spanPL       = P.span      `eq2`    (span      :: (W -> Bool) -> [W] -> ([W],[W]))-prop_splitAtPL    = P.splitAt   `eq2`    (splitAt   :: Int -> [W] -> ([W],[W]))-prop_takePL       = P.take      `eq2`    (take      :: Int -> [W] -> [W])-prop_takeWhilePL  = P.takeWhile `eq2`    (takeWhile :: (W -> Bool) -> [W] -> [W])-prop_elemPL       = P.elem      `eq2`    (elem      :: W -> [W] -> Bool)-prop_notElemPL    = P.notElem   `eq2`    (notElem   :: W -> [W] -> Bool)-prop_elemIndexPL  = P.elemIndex `eq2`    (elemIndex :: W -> [W] -> Maybe Int)-prop_linesPL      = C.lines     `eq1`    (lines     :: String -> [String])-prop_findIndicesPL= P.findIndices`eq2`   (findIndices:: (W -> Bool) -> [W] -> [Int])-prop_elemIndicesPL= P.elemIndices`eq2`   (elemIndices:: W -> [W] -> [Int])-prop_zipPL        = P.zip        `eq2`   (zip :: [W] -> [W] -> [(W,W)])-prop_zipCL        = C.zip        `eq2`   (zip :: [Char] -> [Char] -> [(Char,Char)])-prop_zipLL        = L.zip        `eq2`   (zip :: [W] -> [W] -> [(W,W)])-prop_unzipPL      = P.unzip      `eq1`   (unzip :: [(W,W)] -> ([W],[W]))-prop_unzipLL      = L.unzip      `eq1`   (unzip :: [(W,W)] -> ([W],[W]))--prop_unzipCL :: [(Char8, Char8)] -> Bool-prop_unzipCL xs   = (C.unzip     `eq1`   (unzip :: [(Char,Char)] -> ([Char],[Char])))-                    [ (a,b) | (Char8 a, Char8 b) <- xs ]--prop_unzipDL :: [(Char8, Char8)] -> Bool-prop_unzipDL xs   = (D.unzip     `eq1`   (unzip :: [(Char,Char)] -> ([Char],[Char])))-                    [ (a,b) | (Char8 a, Char8 b) <- xs ]--prop_foldl1PL     = P.foldl1    `eqnotnull2` (foldl1   :: (W -> W -> W) -> [W] -> W)-prop_foldl1PL'    = P.foldl1'   `eqnotnull2` (foldl1' :: (W -> W -> W) -> [W] -> W)-prop_foldr1PL     = P.foldr1    `eqnotnull2` (foldr1 :: (W -> W -> W) -> [W] -> W)-prop_scanlPL      = P.scanl     `eqnotnull3` (scanl  :: (W -> W -> W) -> W -> [W] -> [W])-prop_scanl1PL     = P.scanl1    `eqnotnull2` (scanl1 :: (W -> W -> W) -> [W] -> [W])-prop_scanrPL      = P.scanr     `eqnotnull3` (scanr  :: (W -> W -> W) -> W -> [W] -> [W])-prop_scanr1PL     = P.scanr1    `eqnotnull2` (scanr1 :: (W -> W -> W) -> [W] -> [W])-prop_headPL       = P.head      `eqnotnull1` (head      :: [W] -> W)-prop_initPL       = P.init      `eqnotnull1` (init      :: [W] -> [W])-prop_lastPL       = P.last      `eqnotnull1` (last      :: [W] -> W)-prop_maximumPL    = P.maximum   `eqnotnull1` (maximum   :: [W] -> W)-prop_minimumPL    = P.minimum   `eqnotnull1` (minimum   :: [W] -> W)-prop_tailPL       = P.tail      `eqnotnull1` (tail      :: [W] -> [W])--prop_scanl1CL :: (Char8 -> Char8 -> Char8) -> P -> Property-prop_scanrCL  :: (Char8 -> Char8 -> Char8) -> Char8 -> P -> Property-prop_scanr1CL :: (Char8 -> Char8 -> Char8) -> P -> Property--prop_scanl1CL f = eqnotnull2-    C.scanl1-    (scanl1 :: (Char -> Char -> Char) -> [Char] -> [Char])-    (castFn f)--prop_scanrCL f (Char8 c) = eqnotnull3-    C.scanr-    (scanr  :: (Char -> Char -> Char) -> Char -> [Char] -> [Char])-    (castFn f)-    c--prop_scanr1CL f = eqnotnull2-    C.scanr1-    (scanr1 :: (Char -> Char -> Char) -> [Char] -> [Char])-    (castFn f)--prop_packZipWithPL   = P.packZipWith  `eq3` (zipWith :: (W -> W -> W) -> [W] -> [W] -> [W])--prop_zipWithPL    = (P.zipWith  :: (W -> W -> X) -> P   -> P   -> [X]) `eq3`-                      (zipWith  :: (W -> W -> X) -> [W] -> [W] -> [X])--prop_zipWithPL_rules   = (P.zipWith  :: (W -> W -> W) -> P -> P -> [W]) `eq3`-                         (zipWith    :: (W -> W -> W) -> [W] -> [W] -> [W])--prop_eqPL      = eq2-    ((==) :: P   -> P   -> Bool)-    ((==) :: [W] -> [W] -> Bool)-prop_comparePL = eq2-    ((compare) :: P   -> P   -> Ordering)-    ((compare) :: [W] -> [W] -> Ordering)-prop_foldlPL   = eq3-    (P.foldl  :: (X -> W -> X) -> X -> P        -> X)-    (  foldl  :: (X -> W -> X) -> X -> [W]      -> X)-prop_foldlPL'  = eq3-    (P.foldl' :: (X -> W -> X) -> X -> P        -> X)-    (  foldl' :: (X -> W -> X) -> X -> [W]      -> X)-prop_foldrPL   = eq3-    (P.foldr  :: (W -> X -> X) -> X -> P        -> X)-    (  foldr  :: (W -> X -> X) -> X -> [W]      -> X)-prop_mapAccumLPL= eq3-    (P.mapAccumL :: (X -> W -> (X,W)) -> X -> P -> (X, P))-    (  mapAccumL :: (X -> W -> (X,W)) -> X -> [W] -> (X, [W]))-prop_mapAccumRPL= eq3-    (P.mapAccumR :: (X -> W -> (X,W)) -> X -> P -> (X, P))-    (  mapAccumR :: (X -> W -> (X,W)) -> X -> [W] -> (X, [W]))-prop_unfoldrPL =-  forAll arbitrarySizedIntegral $-  eq3-    ((\n f a ->      fst $-        P.unfoldrN n f a) :: Int -> (X -> Maybe (W,X)) -> X -> P)-    ((\n f a ->   take n $-          unfoldr    f a) :: Int -> (X -> Maybe (W,X)) -> X -> [W])-------------------------------------------------------------------------------- These are miscellaneous tests left over. Or else they test some--- property internal to a type (i.e. head . sort == minimum), without--- reference to a model type.-----invariant :: L.ByteString -> Bool-invariant Empty       = True-invariant (Chunk c cs) = not (P.null c) && invariant cs--prop_invariant = invariant--prop_eq_refl  x     = x        == (x :: ByteString)-prop_eq_symm  x y   = (x == y) == (y == (x :: ByteString))--prop_eq1 xs      = xs == (unpack . pack $ xs)-prop_eq2 xs      = xs == (xs :: ByteString)-prop_eq3 xs ys   = (xs == ys) == (unpack xs == unpack ys)--prop_compare1 xs   = (pack xs        `compare` pack xs) == EQ-prop_compare2 xs c = (pack (xs++[c]) `compare` pack xs) == GT-prop_compare3 xs c = (pack xs `compare` pack (xs++[c])) == LT--prop_compare4 xs    = (not (null xs)) ==> (pack xs  `compare` L.empty) == GT-prop_compare5 xs    = (not (null xs)) ==> (L.empty `compare` pack xs) == LT-prop_compare6 xs ys = (not (null ys)) ==> (pack (xs++ys)  `compare` pack xs) == GT--prop_compare7 x  y  = x  `compare` y  == (L.singleton x `compare` L.singleton y)-prop_compare8 xs ys = xs `compare` ys == (L.pack xs `compare` L.pack ys)-prop_compare9       = (L.singleton 255 `compare` L.singleton 127) == GT--prop_compare7LL (Char8 x) (Char8 y) =-                      x  `compare` y  == (LC.singleton x `compare` LC.singleton y)--prop_empty1 = L.length L.empty == 0-prop_empty2 = L.unpack L.empty == []--prop_packunpack s = (L.unpack . L.pack) s == id s-prop_unpackpack s = (L.pack . L.unpack) s == id s--prop_null xs = null (L.unpack xs) == L.null xs--prop_length1 xs = fromIntegral (length xs) == L.length (L.pack xs)--prop_length2 xs = L.length xs == length1 xs-  where length1 ys-            | L.null ys = 0-            | otherwise = 1 + length1 (L.tail ys)--prop_cons1 c xs = unpack (L.cons c (pack xs)) == (c:xs)-prop_cons2 c    = L.singleton c == (c `L.cons` L.empty)-prop_cons3 c    = unpack (L.singleton c) == (c:[])-prop_cons4 c    = (c `L.cons` L.empty)  == pack (c:[])--prop_snoc1 xs c = xs ++ [c] == unpack ((pack xs) `L.snoc` c)--prop_head  xs = (not (null xs)) ==> head xs == (L.head . pack) xs-prop_head1 xs = not (L.null xs) ==> L.head xs == head (L.unpack xs)--prop_tail xs  = not (L.null xs) ==> L.tail xs == pack (tail (unpack xs))-prop_tail1 xs = (not (null xs)) ==> tail xs   == (unpack . L.tail . pack) xs--prop_last xs  = (not (null xs)) ==> last xs    == (L.last . pack) xs--prop_init xs  =-    (not (null xs)) ==>-    init xs   == (unpack . L.init . pack) xs--prop_append1 xs    = (xs ++ xs) == (unpack $ pack xs `L.append` pack xs)-prop_append2 xs ys = (xs ++ ys) == (unpack $ pack xs `L.append` pack ys)-prop_append3 xs ys = L.append xs ys == pack (unpack xs ++ unpack ys)-prop_appendLazy xs = L.head (L.pack [xs] `L.append` error "Tail should be lazy") == xs--prop_map1 f xs   = L.map f (pack xs)    == pack (map f xs)-prop_map2 f g xs = L.map f (L.map g xs) == L.map (f . g) xs-prop_map3 f xs   = map f xs == (unpack . L.map f .  pack) xs--prop_filter1 c xs = (filter (/=c) xs) == (unpack $ L.filter (/=c) (pack xs))-prop_filter2 p xs = (filter p xs) == (unpack $ L.filter p (pack xs))--prop_reverse  xs = reverse xs          == (unpack . L.reverse . pack) xs-prop_reverse1 xs = L.reverse (pack xs) == pack (reverse xs)-prop_reverse2 xs = reverse (unpack xs) == (unpack . L.reverse) xs--prop_transpose xs = (transpose xs) == ((map unpack) . L.transpose . (map pack)) xs--prop_foldl f c xs = L.foldl f c (pack xs) == foldl f c xs-    where _ = c :: Char--prop_foldr f c xs = L.foldl f c (pack xs) == foldl f c xs-    where _ = c :: Char--prop_foldl_1 xs = L.foldl (\xs c -> c `L.cons` xs) L.empty xs == L.reverse xs-prop_foldr_1 xs = L.foldr (\c xs -> c `L.cons` xs) L.empty xs == id xs--prop_foldl1_1 xs =-    (not . L.null) xs ==>-    L.foldl1 (\x c -> if c > x then c else x)   xs ==-    L.foldl  (\x c -> if c > x then c else x) 0 xs--prop_foldl1_2 xs =-    (not . L.null) xs ==>-    L.foldl1 const xs == L.head xs--prop_foldl1_3 xs =-    (not . L.null) xs ==>-    L.foldl1 (flip const) xs == L.last xs--prop_foldr1_1 xs =-    (not . L.null) xs ==>-    L.foldr1 (\c x -> if c > x then c else x)   xs ==-    L.foldr  (\c x -> if c > x then c else x) 0 xs--prop_foldr1_2 xs =-    (not . L.null) xs ==>-    L.foldr1 (flip const) xs == L.last xs--prop_foldr1_3 xs =-    (not . L.null) xs ==>-    L.foldr1 const xs == L.head xs--prop_concat1 xs = (concat [xs,xs]) == (unpack $ L.concat [pack xs, pack xs])-prop_concat2 xs = (concat [xs,[]]) == (unpack $ L.concat [pack xs, pack []])-prop_concat3    = forAll (sized $ \n -> resize (n `div` 2) arbitrary) $ \xss ->-                  L.concat (map pack xss) == pack (concat xss)--prop_concatMap xs = L.concatMap L.singleton xs == (pack . concatMap (:[]) . unpack) xs--prop_any xs a = (any (== a) xs) == (L.any (== a) (pack xs))-prop_all xs a = (all (== a) xs) == (L.all (== a) (pack xs))--prop_maximum xs = (not (null xs)) ==> (maximum xs) == (L.maximum ( pack xs ))-prop_minimum xs = (not (null xs)) ==> (minimum xs) == (L.minimum ( pack xs ))--prop_compareLength1 xs  =  (L.pack xs         `L.compareLength` fromIntegral (length xs)) == EQ-prop_compareLength2 xs c = (L.pack (xs ++ [c]) `L.compareLength` fromIntegral (length xs)) == GT-prop_compareLength3 xs c = (L.pack xs `L.compareLength` fromIntegral (length (xs ++ [c]))) == LT-prop_compareLength4 xs c = ((L.pack xs `L.append` L.pack [c] `L.append` L.pack [undefined])-                            `L.compareLength` fromIntegral (length xs)) == GT-prop_compareLength5 xs l = L.compareLength xs l == compare (L.length xs) l--prop_replicate1 c =-    forAll arbitrary $ \(Positive n) ->-    unpack (L.replicate (fromIntegral n) c) == replicate n c--prop_replicate2 c = unpack (L.replicate 0 c) == replicate 0 c--prop_take1 i xs = L.take (fromIntegral i) (pack xs) == pack (take i xs)-prop_takeEnd i xs = P.takeEnd i xs == P.drop (P.length xs - i) xs--prop_drop1 i xs = L.drop (fromIntegral i) (pack xs) == pack (drop i xs)-prop_dropEnd i xs = P.dropEnd i xs == P.take (P.length xs - i) xs--prop_splitAt i xs = --collect (i >= 0 && i < length xs) $-    L.splitAt (fromIntegral i) (pack xs) == let (a,b) = splitAt i xs in (pack a, pack b)--prop_takeWhile f xs = L.takeWhile f (pack xs) == pack (takeWhile f xs)-prop_dropWhile f xs = L.dropWhile f (pack xs) == pack (dropWhile f xs)-prop_takeWhileEnd f = P.takeWhileEnd f `eq1` (P.reverse . P.takeWhile f . P.reverse)-prop_dropWhileEnd f = P.dropWhileEnd f `eq1` (P.reverse . P.dropWhile f . P.reverse)--prop_break f xs = L.break f (pack xs) ==-    let (a,b) = break f xs in (pack a, pack b)--prop_breakspan xs c = L.break (==c) xs == L.span (/=c) xs--prop_span xs a = (span (/=a) xs) == (let (x,y) = L.span (/=a) (pack xs) in (unpack x, unpack y))--prop_split c xs = (map L.unpack . map checkInvariant . L.split c $ xs)-               == (map P.unpack . P.split c . P.pack . L.unpack $ xs)--prop_splitWith_empty f = L.splitWith f mempty == []--prop_splitWith f xs = (l1 == l2 || l1 == l2+1) &&-        sum (map L.length splits) == L.length xs - l2-  where splits = L.splitWith f xs-        l1 = fromIntegral (length splits)-        l2 = L.length (L.filter f xs)--prop_splitWith_D_empty f = D.splitWith f mempty == []--prop_splitWith_D f xs = (l1 == l2 || l1 == l2+1) &&-        sum (map D.length splits) == D.length xs - l2-  where splits = D.splitWith f xs-        l1 = fromIntegral (length splits)-        l2 = D.length (D.filter f xs)--prop_splitWith_C_empty f = C.splitWith f mempty == []--prop_splitWith_C f xs = (l1 == l2 || l1 == l2+1) &&-        sum (map C.length splits) == C.length xs - l2-  where splits = C.splitWith f xs-        l1 = fromIntegral (length splits)-        l2 = C.length (C.filter f xs)--prop_split_empty c = L.split c mempty == []--prop_joinsplit c xs = L.intercalate (pack [c]) (L.split c xs) == id xs--prop_group xs       = group xs == (map unpack . L.group . pack) xs-prop_groupBy  f xs  = groupBy f xs == (map unpack . L.groupBy f . pack) xs--prop_groupBy_LC :: (Char8 -> Char8 -> Bool) -> String8 -> Bool-prop_groupBy_LC f' (String8 xs) =-    groupBy f xs == (map LC.unpack . LC.groupBy f .  LC.pack) xs-  where-    f :: Char -> Char -> Bool-    f = castFn f'---- prop_joinjoinByte xs ys c = L.joinWithByte c xs ys == L.join (L.singleton c) [xs,ys]--prop_index xs =-  not (null xs) ==>-    forAll indices $ \i -> (xs !! i) == L.pack xs `L.index` (fromIntegral i)-  where indices = choose (0, length xs -1)--prop_index_D (String8 xs) =-  not (null xs) ==>-    forAll indices $ \i -> (xs !! i) == D.pack xs `D.index` (fromIntegral i)-  where indices = choose (0, length xs -1)--prop_index_C (String8 xs) =-  not (null xs) ==>-    forAll indices $ \i -> (xs !! i) == C.pack xs `C.index` (fromIntegral i)-  where indices = choose (0, length xs -1)---- | Test 'indexMaybe' for Lazy and Strict 'ByteString's.---   If we are testing within the bounds it should return a 'Just' value.---   If we are testing outside of the bounds it should return a 'Nothing' value.-prop_indexMaybe_Just_L xs =-  not (null xs) ==>-    forAll indices $ \i -> isJust (ys `L.indexMaybe` (fromIntegral i))-  where-    ys = L.pack xs-    indices = choose (0, length xs -1)--prop_indexMaybe_Just_P xs =-  not (null xs) ==>-    forAll indices $ \i -> isJust (ys `P.indexMaybe` (fromIntegral i))-  where-    ys = P.pack xs-    indices = choose (0, length xs -1)--prop_indexMaybe_Nothing_L xs =-  not (null xs) ==>-    forAll indices $ \i -> isNothing (ys `L.indexMaybe` (fromIntegral i))-  where-      ys = L.pack xs-      outOfBounds = choose (-100, length xs + 100)-      indices = suchThat outOfBounds (\n -> n < 0 || n >= length xs)--prop_indexMaybe_Nothing_P xs =-  not (null xs) ==>-    forAll indices $ \i -> isNothing (ys `P.indexMaybe` (fromIntegral i))-  where-    ys = P.pack xs-    outOfBounds = choose (-100, length xs + 100)-    indices = suchThat outOfBounds (\n -> n < 0 || n >= length xs)--prop_elemIndex xs c = (elemIndex c xs) == fmap fromIntegral (L.elemIndex c (pack xs))--prop_elemIndexCL :: String8 -> Char8 -> Bool-prop_elemIndexCL (String8 xs) (Char8 c) =-    (elemIndex c xs) == (C.elemIndex c (C.pack xs))--prop_elemIndices xs c = elemIndices c xs == map fromIntegral (L.elemIndices c (pack xs))--prop_count c xs = length (L.elemIndices c xs) == fromIntegral (L.count c xs)--prop_findIndex xs f = (findIndex f xs) == fmap fromIntegral (L.findIndex f (pack xs))-prop_findIndexEnd xs f = (findIndexEnd f xs) == fmap fromIntegral (L.findIndexEnd f (pack xs))-prop_findIndicies xs f = (findIndices f xs) == map fromIntegral (L.findIndices f (pack xs))--prop_elem    xs c = (c `elem` xs)    == (c `L.elem` (pack xs))-prop_notElem xs c = (c `notElem` xs) == (L.notElem c (pack xs))-prop_elem_notelem xs c = c `L.elem` xs == not (c `L.notElem` xs)---- prop_filterByte  xs c = L.filterByte c xs == L.filter (==c) xs--- prop_filterByte2 xs c = unpack (L.filterByte c xs) == filter (==c) (unpack xs)---- prop_filterNotByte  xs c = L.filterNotByte c xs == L.filter (/=c) xs--- prop_filterNotByte2 xs c = unpack (L.filterNotByte c xs) == filter (/=c) (unpack xs)--prop_find p xs = find p xs == L.find p (pack xs)--prop_find_findIndex p xs =-    L.find p xs == case L.findIndex p xs of-                                Just n -> Just (xs `L.index` n)-                                _      -> Nothing--prop_isPrefixOf xs ys = isPrefixOf xs ys == (pack xs `L.isPrefixOf` pack ys)-prop_stripPrefix xs ys = (pack <$> stripPrefix xs ys) == (pack xs `L.stripPrefix` pack ys)--prop_isSuffixOf xs ys = isSuffixOf xs ys == (pack xs `L.isSuffixOf` pack ys)-prop_stripSuffix xs ys = (pack <$> stripSuffix xs ys) == (pack xs `L.stripSuffix` pack ys)--{--prop_sort1 xs = sort xs == (unpack . L.sort . pack) xs-prop_sort2 xs = (not (null xs)) ==> (L.head . L.sort . pack $ xs) == minimum xs-prop_sort3 xs = (not (null xs)) ==> (L.last . L.sort . pack $ xs) == maximum xs-prop_sort4 xs ys =-        (not (null xs)) ==>-        (not (null ys)) ==>-        (L.head . L.sort) (L.append (pack xs) (pack ys)) == min (minimum xs) (minimum ys)--prop_sort5 xs ys =-        (not (null xs)) ==>-        (not (null ys)) ==>-        (L.last . L.sort) (L.append (pack xs) (pack ys)) == max (maximum xs) (maximum ys)---}----------------------------------------------------------------------------- Misc ByteString properties--prop_nil1BB = P.length P.empty == 0-prop_nil2BB = P.unpack P.empty == []-prop_nil1BB_monoid = P.length mempty == 0-prop_nil2BB_monoid = P.unpack mempty == []--prop_nil1LL_monoid = L.length mempty == 0-prop_nil2LL_monoid = L.unpack mempty == []--prop_tailSBB xs = not (P.null xs) ==> P.tail xs == P.pack (tail (P.unpack xs))--prop_nullBB xs = null (P.unpack xs) == P.null xs--prop_lengthBB xs = P.length xs == length1 xs-    where-        length1 ys-            | P.null ys = 0-            | otherwise = 1 + length1 (P.tail ys)--prop_lengthSBB xs = length xs == P.length (P.pack xs)--prop_indexBB xs =-  not (null xs) ==>-    forAll indices $ \i -> (xs !! i) == P.pack xs `P.index` i-  where indices = choose (0, length xs -1)--prop_unsafeIndexBB xs =-  not (null xs) ==>-    forAll indices $ \i -> (xs !! i) == P.pack xs `P.unsafeIndex` i-  where indices = choose (0, length xs -1)--prop_mapfusionBB f g xs = P.map f (P.map g xs) == P.map (f . g) xs--prop_filterBB f xs = P.filter f (P.pack xs) == P.pack (filter f xs)--prop_filterfusionBB f g xs = P.filter f (P.filter g xs) == P.filter (\c -> f c && g c) xs--prop_elemSBB x xs = P.elem x (P.pack xs) == elem x xs--prop_takeSBB i xs = P.take i (P.pack xs) == P.pack (take i xs)-prop_dropSBB i xs = P.drop i (P.pack xs) == P.pack (drop i xs)--prop_splitAtSBB i xs = -- collect (i >= 0 && i < length xs) $-    P.splitAt i (P.pack xs) ==-    let (a,b) = splitAt i xs in (P.pack a, P.pack b)--prop_foldlBB f c xs = P.foldl f c (P.pack xs) == foldl f c xs-  where _ = c :: Char--prop_scanlfoldlBB f z xs = not (P.null xs) ==> P.last (P.scanl f z xs) == P.foldl f z xs--prop_foldrBB f c xs = P.foldl f c (P.pack xs) == foldl f c xs-  where _ = c :: Char--prop_takeWhileSBB f xs = P.takeWhile f (P.pack xs) == P.pack (takeWhile f xs)-prop_dropWhileSBB f xs = P.dropWhile f (P.pack xs) == P.pack (dropWhile f xs)--prop_spanSBB f xs = P.span f (P.pack xs) ==-    let (a,b) = span f xs in (P.pack a, P.pack b)--prop_breakSBB f xs = P.break f (P.pack xs) ==-    let (a,b) = break f xs in (P.pack a, P.pack b)--prop_breakspan_1BB xs c = P.break (== c) xs == P.span (/= c) xs--prop_linesSBB (String8 xs) = C.lines (C.pack xs) == map C.pack (lines xs)--prop_unlinesSBB xss = C.unlines (map C.pack xss) == C.pack (unlines xss)--prop_wordsSBB (String8 xs) =-    C.words (C.pack xs) == map C.pack (words xs)--prop_wordsLC (String8 xs) =-    LC.words (LC.pack xs) == map LC.pack (words xs)--prop_unwordsSBB xss = C.unwords (map C.pack xss) == C.pack (unwords xss)-prop_unwordsSLC xss = LC.unwords (map LC.pack xss) == LC.pack (unwords xss)--prop_splitWithBB_empty f = P.splitWith f mempty == []--prop_splitWithBB f xs = (l1 == l2 || l1 == l2+1) &&-        sum (map P.length splits) == P.length xs - l2-  where splits = P.splitWith f xs-        l1 = length splits-        l2 = P.length (P.filter f xs)--prop_splitBB_empty c = P.split c mempty == []--prop_joinsplitBB c xs = P.intercalate (P.pack [c]) (P.split c xs) == xs--prop_intercalatePL c x y =--    P.intercalate (P.singleton c) (x : y : []) ==- --     intercalate (singleton c) (s1 : s2 : [])--    P.pack (intercalate [c] [P.unpack x,P.unpack y])---- prop_linessplitBB xs =---     (not . C.null) xs ==>---     C.lines' xs == C.split '\n' xs---- false:-{--prop_linessplit2BB xs =-   (not . C.null) xs ==>-    C.lines xs == C.split '\n' xs ++ (if C.last xs == '\n' then [C.empty] else [])--}--prop_splitsplitWithBB c xs = P.split c xs == P.splitWith (== c) xs--prop_bijectionBB  (Char8 c) = (P.w2c . P.c2w) c == id c-prop_bijectionBB'        w  = (P.c2w . P.w2c) w == id w--prop_packunpackBB  s = (P.unpack . P.pack) s == id s-prop_packunpackBB' s = (P.pack . P.unpack) s == id s--prop_eq1BB xs      = xs            == (P.unpack . P.pack $ xs)-prop_eq2BB xs      = xs == (xs :: P.ByteString)-prop_eq3BB xs ys   = (xs == ys) == (P.unpack xs == P.unpack ys)--prop_compare1BB xs  = (P.pack xs         `compare` P.pack xs) == EQ-prop_compare2BB xs c = (P.pack (xs++[c]) `compare` P.pack xs) == GT-prop_compare3BB xs c = (P.pack xs `compare` P.pack (xs++[c])) == LT--prop_compare4BB xs  = (not (null xs)) ==> (P.pack xs  `compare` P.empty) == GT-prop_compare5BB xs  = (not (null xs)) ==> (P.empty `compare` P.pack xs) == LT-prop_compare6BB xs ys= (not (null ys)) ==> (P.pack (xs++ys)  `compare` P.pack xs) == GT--prop_compare7BB (Char8 x) (Char8 y) =-                        x  `compare` y  == (C.singleton x `compare` C.singleton y)-prop_compare8BB xs ys = xs `compare` ys == (P.pack xs `compare` P.pack ys)--prop_consBB  c xs = P.unpack (P.cons c (P.pack xs)) == (c:xs)-prop_cons1BB (String8 xs)-                  = 'X' : xs == C.unpack ('X' `C.cons` (C.pack xs))-prop_cons2BB xs c = c : xs == P.unpack (c `P.cons` (P.pack xs))-prop_cons3BB (Char8 c)-                  = C.unpack (C.singleton c) == (c:[])-prop_cons4BB c    = (c `P.cons` P.empty)  == P.pack (c:[])--prop_snoc1BB xs c = xs ++ [c] == P.unpack ((P.pack xs) `P.snoc` c)--prop_head1BB xs     = (not (null xs)) ==> head  xs  == (P.head . P.pack) xs-prop_head2BB xs    = (not (null xs)) ==> head xs   == (P.unsafeHead . P.pack) xs-prop_head3BB xs    = not (P.null xs) ==> P.head xs == head (P.unpack xs)--prop_tailBB xs     = (not (null xs)) ==> tail xs    == (P.unpack . P.tail . P.pack) xs-prop_tail1BB xs    = (not (null xs)) ==> tail xs    == (P.unpack . P.unsafeTail. P.pack) xs--prop_lastBB xs     = (not (null xs)) ==> last xs    == (P.last . P.pack) xs-prop_last1BB xs    = (not (null xs)) ==> last xs    == (P.unsafeLast . P.pack) xs--prop_initBB xs     =-    (not (null xs)) ==>-    init xs    == (P.unpack . P.init . P.pack) xs-prop_init1BB xs     =-    (not (null xs)) ==>-    init xs    == (P.unpack . P.unsafeInit . P.pack) xs---- prop_null xs = (null xs) ==> null xs == (nullPS (pack xs))--prop_append1BB xs    = (xs ++ xs) == (P.unpack $ P.pack xs `P.append` P.pack xs)-prop_append2BB xs ys = (xs ++ ys) == (P.unpack $ P.pack xs `P.append` P.pack ys)-prop_append3BB xs ys = P.append xs ys == P.pack (P.unpack xs ++ P.unpack ys)--prop_append1BB_monoid xs    = (xs ++ xs) == (P.unpack $ P.pack xs `mappend` P.pack xs)-prop_append2BB_monoid xs ys = (xs ++ ys) == (P.unpack $ P.pack xs `mappend` P.pack ys)-prop_append3BB_monoid xs ys = mappend xs ys == P.pack (P.unpack xs ++ P.unpack ys)--prop_append1LL_monoid xs    = (xs ++ xs) == (L.unpack $ L.pack xs `mappend` L.pack xs)-prop_append2LL_monoid xs ys = (xs ++ ys) == (L.unpack $ L.pack xs `mappend` L.pack ys)-prop_append3LL_monoid xs ys = mappend xs ys == L.pack (L.unpack xs ++ L.unpack ys)--prop_map1BB f xs   = P.map f (P.pack xs)    == P.pack (map f xs)-prop_map2BB f g xs = P.map f (P.map g xs) == P.map (f . g) xs-prop_map3BB f xs   = map f xs == (P.unpack . P.map f .  P.pack) xs--- prop_mapBB' f xs   = P.map' f (P.pack xs) == P.pack (map f xs)--prop_filter1BB (String8 xs) = (filter (=='X') xs) == (C.unpack $ C.filter (=='X') (C.pack xs))-prop_filter2BB p        xs  = (filter p       xs) == (P.unpack $ P.filter p (P.pack xs))--prop_findBB p xs = find p xs == P.find p (P.pack xs)--prop_find_findIndexBB p xs =-    P.find p xs == case P.findIndex p xs of-                                Just n -> Just (xs `P.unsafeIndex` n)-                                _      -> Nothing--prop_foldl1BB xs a = ((foldl (\x c -> if c == a then x else c:x) [] xs)) ==-                   (P.unpack $ P.foldl (\x c -> if c == a then x else c `P.cons` x) P.empty (P.pack xs))-prop_foldl2BB xs = P.foldl (\xs c -> c `P.cons` xs) P.empty (P.pack xs) == P.reverse (P.pack xs)--prop_foldr1BB xs a = ((foldr (\c x -> if c == a then x else c:x) [] xs)) ==-                (P.unpack $ P.foldr (\c x -> if c == a then x else c `P.cons` x)-                    P.empty (P.pack xs))--prop_foldr2BB xs = P.foldr (\c xs -> c `P.cons` xs) P.empty (P.pack xs) == (P.pack xs)--prop_foldl1_1BB xs =-    (not . P.null) xs ==>-    P.foldl1 (\x c -> if c > x then c else x)   xs ==-    P.foldl  (\x c -> if c > x then c else x) 0 xs--prop_foldl1_2BB xs =-    (not . P.null) xs ==>-    P.foldl1 const xs == P.head xs--prop_foldl1_3BB xs =-    (not . P.null) xs ==>-    P.foldl1 (flip const) xs == P.last xs--prop_foldr1_1BB xs =-    (not . P.null) xs ==>-    P.foldr1 (\c x -> if c > x then c else x)   xs ==-    P.foldr  (\c x -> if c > x then c else x) 0 xs--prop_foldr1_2BB xs =-    (not . P.null) xs ==>-    P.foldr1 (flip const) xs == P.last xs--prop_foldr1_3BB xs =-    (not . P.null) xs ==>-    P.foldr1 const xs == P.head xs--prop_takeWhileBB_ne xs a =-  (takeWhile (/= a) xs) == (P.unpack . (P.takeWhile (/= a)) . P.pack) xs-prop_takeWhileBB_eq xs a =-  (takeWhile (== a) xs) == (P.unpack . (P.takeWhile (== a)) . P.pack) xs--prop_dropWhileBB_ne xs a =-  (dropWhile (/= a) xs) == (P.unpack . (P.dropWhile (/= a)) . P.pack) xs-prop_dropWhileBB_eq xs a =-  (dropWhile (== a) xs) == (P.unpack . (P.dropWhile (== a)) . P.pack) xs--prop_dropWhileCC_isSpace (String8 xs) =-        (dropWhile isSpace xs) ==-       (C.unpack .  (C.dropWhile isSpace) . C.pack) xs--prop_takeBB xs = (take 10 xs) == (P.unpack . (P.take 10) . P.pack) xs--prop_dropBB xs = (drop 10 xs) == (P.unpack . (P.drop 10) . P.pack) xs--prop_splitAtBB i xs = -- collect (i >= 0 && i < length xs) $-    splitAt i xs ==-    let (x,y) = P.splitAt i (P.pack xs) in (P.unpack x, P.unpack y)--prop_spanBB xs a = (span (/=a) xs) == (let (x,y) = P.span (/=a) (P.pack xs)-                                     in (P.unpack x, P.unpack y))--prop_breakBB xs a = (break (/=a) xs) == (let (x,y) = P.break (/=a) (P.pack xs)-                                       in (P.unpack x, P.unpack y))--prop_reverse1BB xs = (reverse xs) == (P.unpack . P.reverse . P.pack) xs-prop_reverse2BB xs = P.reverse (P.pack xs) == P.pack (reverse xs)-prop_reverse3BB xs = reverse (P.unpack xs) == (P.unpack . P.reverse) xs--prop_elemBB xs a = (a `elem` xs) == (a `P.elem` (P.pack xs))--prop_notElemBB c xs = P.notElem c (P.pack xs) == notElem c xs---- should try to stress it-prop_concat1BB xs = (concat [xs,xs]) == (P.unpack $ P.concat [P.pack xs, P.pack xs])-prop_concat2BB xs = (concat [xs,[]]) == (P.unpack $ P.concat [P.pack xs, P.pack []])-prop_concatBB xss = P.concat (map P.pack xss) == P.pack (concat xss)--prop_concat1BB_monoid xs = (concat [xs,xs]) == (P.unpack $ mconcat [P.pack xs, P.pack xs])-prop_concat2BB_monoid xs = (concat [xs,[]]) == (P.unpack $ mconcat [P.pack xs, P.pack []])-prop_concatBB_monoid xss = mconcat (map P.pack xss) == P.pack (concat xss)--prop_concat1LL_monoid xs = (concat [xs,xs]) == (L.unpack $ mconcat [L.pack xs, L.pack xs])-prop_concat2LL_monoid xs = (concat [xs,[]]) == (L.unpack $ mconcat [L.pack xs, L.pack []])-prop_concatLL_monoid xss = mconcat (map L.pack xss) == L.pack (concat xss)--prop_concatMapBB xs = C.concatMap C.singleton xs == (C.pack . concatMap (:[]) . C.unpack) xs--prop_anyBB xs a = (any (== a) xs) == (P.any (== a) (P.pack xs))-prop_allBB xs a = (all (== a) xs) == (P.all (== a) (P.pack xs))--prop_linesBB (String8 xs) =-    (lines xs) == ((map C.unpack) . C.lines . C.pack) xs--prop_unlinesBB (String8 xs) =-    (unlines.lines) xs == (C.unpack. C.unlines . C.lines .C.pack) xs-prop_unlinesLC (String8 xs) =-    (unlines.lines) xs == (LC.unpack. LC.unlines .  LC.lines .LC.pack) xs--prop_lines_lazy1 =-    head (LC.lines (LC.append (LC.pack "a\nb\n") undefined)) == LC.pack "a"-prop_lines_lazy2 =-    head (tail (LC.lines (LC.append (LC.pack "a\nb\n") undefined))) == LC.pack "b"--prop_wordsBB (String8 xs) =-    (words xs) == ((map C.unpack) . C.words . C.pack) xs--- prop_wordstokensBB xs = C.words xs == C.tokens isSpace xs--prop_unwordsBB (String8 xs) =-    (C.pack.unwords.words) xs == (C.unwords . C.words .C.pack) xs--prop_groupBB xs   = group xs == (map P.unpack . P.group . P.pack) xs--prop_groupByBB  xs = groupBy (==) xs == (map P.unpack . P.groupBy (==) . P.pack) xs-prop_groupBy1BB xs = groupBy (/=) xs == (map P.unpack . P.groupBy (/=) . P.pack) xs-prop_groupBy1CC (String8 xs) = groupBy (==) xs == (map C.unpack . C.groupBy (==) . C.pack) xs-prop_groupBy2CC (String8 xs) = groupBy (/=) xs == (map C.unpack . C.groupBy (/=) . C.pack) xs--prop_joinBB (String8 xs) (String8 ys) =-    (concat . (intersperse ys) . lines) xs ==-    (C.unpack $ C.intercalate (C.pack ys) (C.lines (C.pack xs)))--prop_elemIndex1BB (String8 xs)           = (elemIndex 'X' xs) == (C.elemIndex 'X' (C.pack xs))-prop_elemIndex2BB (String8 xs) (Char8 c) = (elemIndex  c  xs) == (C.elemIndex  c  (C.pack xs))---- prop_lineIndices1BB xs = C.elemIndices '\n' xs == C.lineIndices xs--prop_countBB c xs = length (P.elemIndices c xs) == P.count c xs--prop_elemIndexEnd1BB c xs =-  P.elemIndexEnd c (P.pack xs) ==-    case P.elemIndex c (P.pack (reverse xs)) of-      Nothing -> Nothing-      Just i  -> Just (length xs - 1 - i)--prop_elemIndexEnd1CC (Char8 c) (String8 xs) =-  C.elemIndexEnd c (C.pack xs) ==-    case C.elemIndex c (C.pack (reverse xs)) of-      Nothing -> Nothing-      Just i  -> Just (length xs - 1 - i)--prop_elemIndexEnd1LL c xs =-  L.elemIndexEnd c (L.pack xs) ==-    case L.elemIndex c (L.pack (reverse xs)) of-      Nothing -> Nothing-      Just i  -> Just (fromIntegral (length xs) - 1 - i)--prop_elemIndexEnd1DD (Char8 c) (String8 xs) =-  D.elemIndexEnd c (D.pack xs) ==-    case D.elemIndex c (D.pack (reverse xs)) of-      Nothing -> Nothing-      Just i  -> Just (fromIntegral (length xs) - 1 - i)--prop_elemIndicesBB xs c = elemIndices c xs == P.elemIndices c (P.pack xs)--prop_findIndexBB xs a = (findIndex (==a) xs) == (P.findIndex (==a) (P.pack xs))--prop_findIndexEndBB xs a = (findIndexEnd (==a) xs) == (P.findIndexEnd (==a) (P.pack xs))--prop_findIndexEndLL xs a = (findIndexEnd (==a) xs) == fmap fromIntegral (L.findIndexEnd (==a) (L.pack xs))--prop_findIndexEndDD (String8 xs) (Char8 a) = (findIndexEnd (==a) xs) == fmap fromIntegral (D.findIndexEnd (==a) (D.pack xs))--prop_findIndiciesBB xs c = (findIndices (==c) xs) == (P.findIndices (==c) (P.pack xs))---- example properties from QuickCheck.Batch-prop_sort1BB xs = sort xs == (P.unpack . P.sort . P.pack) xs-prop_sort2BB xs = (not (null xs)) ==> (P.head . P.sort . P.pack $ xs) == minimum xs-prop_sort3BB xs = (not (null xs)) ==> (P.last . P.sort . P.pack $ xs) == maximum xs-prop_sort4BB xs ys =-        (not (null xs)) ==>-        (not (null ys)) ==>-        (P.head . P.sort) (P.append (P.pack xs) (P.pack ys)) == min (minimum xs) (minimum ys)-prop_sort5BB xs ys =-        (not (null xs)) ==>-        (not (null ys)) ==>-        (P.last . P.sort) (P.append (P.pack xs) (P.pack ys)) == max (maximum xs) (maximum ys)--prop_intersperseBB c xs = (intersperse c xs) == (P.unpack $ P.intersperse c (P.pack xs))---- prop_transposeBB xs = (transpose xs) == ((map P.unpack) . P.transpose .  (map P.pack)) xs--prop_maximumBB xs = (not (null xs)) ==> (maximum xs) == (P.maximum ( P.pack xs ))-prop_minimumBB xs = (not (null xs)) ==> (minimum xs) == (P.minimum ( P.pack xs ))--prop_strip = C.strip `eq1` (C.dropSpace . C.reverse . C.dropSpace . C.reverse)---- prop_dropSpaceBB xs    = dropWhile isSpace xs == C.unpack (C.dropSpace (C.pack xs))--- prop_dropSpaceEndBB xs = (C.reverse . (C.dropWhile isSpace) . C.reverse) (C.pack xs) ==---                        (C.dropSpaceEnd (C.pack xs))---- prop_breakSpaceBB xs =---     (let (x,y) = C.breakSpace (C.pack xs)---      in (C.unpack x, C.unpack y)) == (break isSpace xs)--prop_spanEndBB xs =-        (C.spanEnd (not . isSpace) (C.pack xs)) ==-        (let (x,y) = C.span (not.isSpace) (C.reverse (C.pack xs)) in (C.reverse y,C.reverse x))--prop_breakEndBB p xs = P.breakEnd (not.p) xs == P.spanEnd p xs-prop_breakEndCC p xs = C.breakEnd (not.p) xs == C.spanEnd p xs--{--prop_breakCharBB c xs =-        (break (==c) xs) ==-        (let (x,y) = C.breakChar c (C.pack xs) in (C.unpack x, C.unpack y))--prop_spanCharBB c xs =-        (break (/=c) xs) ==-        (let (x,y) = C.spanChar c (C.pack xs) in (C.unpack x, C.unpack y))--prop_spanChar_1BB c xs =-        (C.span (==c) xs) == C.spanChar c xs--prop_wordsBB' xs =-    (C.unpack . C.unwords  . C.words' . C.pack) xs ==-    (map (\c -> if isSpace c then ' ' else c) xs)---- prop_linesBB' xs = (C.unpack . C.unlines' . C.lines' . C.pack) xs == (xs)--}--prop_unfoldrBB c =-    forAll arbitrarySizedIntegral $ \n ->-      (fst $ C.unfoldrN n fn c) == (C.pack $ take n $ unfoldr fn c)-  where-    fn x = Just (x, if x == maxBound then x else succ x)--prop_prefixBB xs ys = isPrefixOf xs ys == (P.pack xs `P.isPrefixOf` P.pack ys)-prop_prefixLL xs ys = isPrefixOf xs ys == (L.pack xs `L.isPrefixOf` L.pack ys)-prop_suffixBB xs ys = isSuffixOf xs ys == (P.pack xs `P.isSuffixOf` P.pack ys)-prop_suffixLL xs ys = isSuffixOf xs ys == (L.pack xs `L.isSuffixOf` L.pack ys)--prop_stripPrefixBB xs ys = (P.pack <$> stripPrefix xs ys) == (P.pack xs `P.stripPrefix` P.pack ys)-prop_stripPrefixLL xs ys = (L.pack <$> stripPrefix xs ys) == (L.pack xs `L.stripPrefix` L.pack ys)-prop_stripSuffixBB xs ys = (P.pack <$> stripSuffix xs ys) == (P.pack xs `P.stripSuffix` P.pack ys)-prop_stripSuffixLL xs ys = (L.pack <$> stripSuffix xs ys) == (L.pack xs `L.stripSuffix` L.pack ys)--prop_copyBB xs = let p = P.pack xs in P.copy p == p-prop_copyLL xs = let p = L.pack xs in L.copy p == p--prop_initsBB xs = inits xs == map P.unpack (P.inits (P.pack xs))--prop_tailsBB xs = tails xs == map P.unpack (P.tails (P.pack xs))---- correspondance between break and breakSubstring-prop_breakSubstringBB c l-    = P.break (== c) l == P.breakSubstring (P.singleton c) l--prop_breakSubstring_isInfixOf s l-    = P.isInfixOf s l == if P.null s then True-                                     else case P.breakSubstring s l of-                                            (x,y) | P.null y  -> False-                                                  | otherwise -> True--prop_replicate1BB c = forAll arbitrarySizedIntegral $ \n ->-                      P.unpack (P.replicate n c) == replicate n c-prop_replicate2BB c = forAll arbitrarySizedIntegral $ \n ->-                      P.replicate n c == fst (P.unfoldrN n (\u -> Just (u,u)) c)--prop_replicate3BB c = P.unpack (P.replicate 0 c) == replicate 0 c--prop_readintBB n = (fst . fromJust . C.readInt . C.pack . show) n == (n :: Int)-prop_readintLL n = (fst . fromJust . D.readInt . D.pack . show) n == (n :: Int)--prop_readBB x = (read . show) x == (x :: P.ByteString)-prop_readLL x = (read . show) x == (x :: L.ByteString)--prop_readint2BB (String8 s) =-    let s' = filter (\c -> c `notElem` ['0'..'9']) s-    in C.readInt (C.pack s') == Nothing--prop_readintegerBB n = (fst . fromJust . C.readInteger . C.pack . show) n == (n :: Integer)-prop_readintegerLL n = (fst . fromJust . D.readInteger . D.pack . show) n == (n :: Integer)--prop_readinteger2BB (String8 s) =-    let s' = filter (\c -> c `notElem` ['0'..'9']) s-    in C.readInteger (C.pack s') == Nothing----- Ensure that readInt and readInteger over lazy ByteStrings are not--- excessively strict.-prop_readIntSafe         = (fst . fromJust . D.readInt) (Chunk (C.pack "1z") Empty)         == 1-prop_readIntUnsafe       = (fst . fromJust . D.readInt) (Chunk (C.pack "2z") undefined)     == 2-prop_readIntegerSafe     = (fst . fromJust . D.readInteger) (Chunk (C.pack "1z") Empty)     == 1-prop_readIntegerUnsafe   = (fst . fromJust . D.readInteger) (Chunk (C.pack "2z") undefined) == 2---- prop_filterChar1BB c xs = (filter (==c) xs) == ((C.unpack . C.filterChar c . C.pack) xs)--- prop_filterChar2BB c xs = (C.filter (==c) (C.pack xs)) == (C.filterChar c (C.pack xs))--- prop_filterChar3BB c xs = C.filterChar c xs == C.replicate (C.count c xs) c---- prop_filterNotChar1BB c xs = (filter (/=c) xs) == ((C.unpack . C.filterNotChar c . C.pack) xs)--- prop_filterNotChar2BB c xs = (C.filter (/=c) (C.pack xs)) == (C.filterNotChar c (C.pack xs))---- prop_joinjoinpathBB xs ys c = C.joinWithChar c xs ys == C.join (C.singleton c) [xs,ys]--prop_zipBB  xs ys = zip xs ys == P.zip (P.pack xs) (P.pack ys)-prop_zipLC (String8 xs) (String8 ys)-                  = zip xs ys == LC.zip (LC.pack xs) (LC.pack ys)-prop_zip1BB xs ys = P.zip xs ys == zip (P.unpack xs) (P.unpack ys)--prop_zipWithBB xs ys = P.zipWith (,) xs ys == P.zip xs ys-prop_zipWithCC xs ys = C.zipWith (,) xs ys == C.zip xs ys-prop_zipWithLC xs ys = LC.zipWith (,) xs ys == LC.zip xs ys--prop_packZipWithBB f xs ys = P.pack (P.zipWith f xs ys) == P.packZipWith f xs ys-prop_packZipWithLL f xs ys = L.pack (L.zipWith f xs ys) == L.packZipWith f xs ys-prop_packZipWithBC f xs ys = C.pack (C.zipWith f xs ys) == C.packZipWith f xs ys-prop_packZipWithLC f xs ys = LC.pack (LC.zipWith f xs ys) == LC.packZipWith f xs ys---prop_unzipBB x = let (xs,ys) = unzip x in (P.pack xs, P.pack ys) == P.unzip x--#if MIN_VERSION_base(4,9,0)-prop_stimesBB :: NonNegative Int -> P.ByteString -> Bool-prop_stimesBB (NonNegative i) bs = stimes i bs == mtimesDefault i bs--prop_stimesLL :: NonNegative Int -> L.ByteString -> Bool-prop_stimesLL (NonNegative i) bs = stimes i bs == mtimesDefault i bs-#endif---- prop_zipwith_spec f p q =---   P.pack (P.zipWith f p q) == P.zipWith' f p q---   where _ = f :: Word8 -> Word8 -> Word8---- prop_join_spec c s1 s2 =---  P.join (P.singleton c) (s1 : s2 : []) == P.joinWithByte c s1 s2------------------------------------------------------------------------------ Test IsString, Show, Read, pack, unpack-prop_isstring    :: String8 -> Bool-prop_isstring_lc :: String8 -> Bool--prop_isstring    (String8 x) = C.unpack  (fromString x :: C.ByteString) == x-prop_isstring_lc (String8 x) = LC.unpack (fromString x :: LC.ByteString) == x--prop_showP1 x = show x == show (C.unpack x)-prop_showL1 x = show x == show (LC.unpack x)--prop_readP1 x = read (show x) == (x :: P.ByteString)-prop_readP2 x = read (show x) == C.pack (x :: String)--prop_readL1 x = read (show x) == (x :: L.ByteString)-prop_readL2 x = read (show x) == LC.pack (x :: String)--prop_packunpack_s x = (P.unpack . P.pack) x == x-prop_unpackpack_s x = (P.pack . P.unpack) x == x--prop_packunpack_c (String8 x) = (C.unpack . C.pack) x == x-prop_unpackpack_c          x  = (C.pack . C.unpack) x == x--prop_packunpack_l x = (L.unpack . L.pack) x == x-prop_unpackpack_l x = (L.pack . L.unpack) x == x--prop_packunpack_lc (String8 x) = (LC.unpack . LC.pack) x == x-prop_unpackpack_lc          x  = (LC.pack . LC.unpack) x == x--prop_toFromChunks x = (L.fromChunks . L.toChunks) x == x-prop_fromToChunks x = (L.toChunks . L.fromChunks) x == filter (not . P.null) x--prop_toFromStrict x = (L.fromStrict . L.toStrict) x == x-prop_fromToStrict x = (L.toStrict . L.fromStrict) x == x--prop_packUptoLenBytes cs =-    forAll (choose (0, length cs + 1)) $ \n ->-      let (bs, cs') = P.packUptoLenBytes n cs-       in P.length bs == min n (length cs)-       && take n cs == P.unpack bs-       && P.pack (take n cs) == bs-       && drop n cs == cs'--prop_packUptoLenChars (String8 cs) =-    forAll (choose (0, length cs + 1)) $ \n ->-      let (bs, cs') = P.packUptoLenChars n cs-       in P.length bs == min n (length cs)-       && take n cs == C.unpack bs-       && C.pack (take n cs) == bs-       && drop n cs == cs'--prop_unpack_s cs =-    forAll (choose (0, length cs)) $ \n ->-      P.unpack (P.drop n $ P.pack cs) == drop n cs-prop_unpack_c (String8 cs) =-    forAll (choose (0, length cs)) $ \n ->-      C.unpack (C.drop n $ C.pack cs) == drop n cs--prop_unpack_l  cs =-    forAll (choose (0, length cs)) $ \n ->-      L.unpack (L.drop (fromIntegral n) $ L.pack cs) == drop n cs-prop_unpack_lc (String8 cs) =-    forAll (choose (0, length cs)) $ \n ->-      LC.unpack (L.drop (fromIntegral n) $ LC.pack cs) == drop n cs--prop_unpackBytes cs =-    forAll (choose (0, length cs)) $ \n ->-      P.unpackBytes (P.drop n $ P.pack cs) == drop n cs-prop_unpackChars (String8 cs) =-    forAll (choose (0, length cs)) $ \n ->-      P.unpackChars (P.drop n $ C.pack cs) == drop n cs--prop_unpackBytes_l =-    forAll (sized $ \n -> resize (n * 10) arbitrary) $ \cs ->-    forAll (choose (0, length cs)) $ \n ->-      L.unpackBytes (L.drop (fromIntegral n) $ L.pack cs) == drop n cs-prop_unpackChars_l =-    forAll (sized $ \n -> resize (n * 10) arbitrary) $ \(String8 cs) ->-    forAll (choose (0, length cs)) $ \n ->-      L.unpackChars (L.drop (fromIntegral n) $ LC.pack cs) == drop n cs--prop_unpackAppendBytesLazy cs' =-    forAll (sized $ \n -> resize (n * 10) arbitrary) $ \cs ->-    forAll (choose (0, 2)) $ \n ->-      P.unpackAppendBytesLazy (P.drop n $ P.pack cs) cs' == drop n cs ++ cs'-prop_unpackAppendCharsLazy (String8 cs') =-    forAll (sized $ \n -> resize (n * 10) arbitrary) $ \(String8 cs) ->-    forAll (choose (0, 2)) $ \n ->-      P.unpackAppendCharsLazy (P.drop n $ C.pack cs) cs' == drop n cs ++ cs'--prop_unpackAppendBytesStrict cs cs' =-    forAll (choose (0, length cs)) $ \n ->-      P.unpackAppendBytesStrict (P.drop n $ P.pack cs) cs' == drop n cs ++ cs'--prop_unpackAppendCharsStrict (String8 cs) (String8 cs') =-    forAll (choose (0, length cs)) $ \n ->-      P.unpackAppendCharsStrict (P.drop n $ C.pack cs) cs' == drop n cs ++ cs'----------------------------------------------------------------------------- Unsafe functions---- Test unsafePackAddress-prop_unsafePackAddress (CByteString x) = ioProperty $ do-        let (p,_,_) = P.toForeignPtr (x `P.snoc` 0)-        y <- withForeignPtr p $ \(Ptr addr) ->-            P.unsafePackAddress addr-        return (y == x)---- Test unsafePackAddressLen-prop_unsafePackAddressLen x = ioProperty $ do-        let i = P.length x-            (p,_,_) = P.toForeignPtr (x `P.snoc` 0)-        y <- withForeignPtr p $ \(Ptr addr) ->-            P.unsafePackAddressLen i addr-        return (y == x)--prop_unsafeUseAsCString x = ioProperty $ do-        let n = P.length x-        y <- P.unsafeUseAsCString x $ \cstr ->-                    sequence [ do a <- peekElemOff cstr i-                                  let b = x `P.index` i-                                  return (a == fromIntegral b)-                             | i <- [0.. n-1]     ]-        return (and y)--prop_unsafeUseAsCStringLen x = ioProperty $ do-        let n = P.length x-        y <- P.unsafeUseAsCStringLen x $ \(cstr,_) ->-                    sequence [ do a <- peekElemOff cstr i-                                  let b = x `P.index` i-                                  return (a == fromIntegral b)-                             | i <- [0.. n-1]     ]-        return (and y)--prop_internal_invariant x = L.invariant x--prop_useAsCString x = ioProperty $ do-        let n = P.length x-        y <- P.useAsCString x $ \cstr ->-                    sequence [ do a <- peekElemOff cstr i-                                  let b = x `P.index` i-                                  return (a == fromIntegral b)-                             | i <- [0.. n-1]     ]-        return (and y)--prop_packCString (CByteString x) = ioProperty $ do-        y <- P.useAsCString x $ P.unsafePackCString-        return (y == x)--prop_packCString_safe (CByteString x) = ioProperty $ do-        y <- P.useAsCString x $ P.packCString-        return (y == x)--prop_packCStringLen x = ioProperty $ do-        y <- P.useAsCStringLen x $ P.unsafePackCStringLen-        return (y == x && P.length y == P.length x)--prop_packCStringLen_safe x = ioProperty $ do-        y <- P.useAsCStringLen x $ P.packCStringLen-        return (y == x && P.length y == P.length x)--prop_packMallocCString (CByteString x) = ioProperty $ do--         let (fp,_,_) = P.toForeignPtr x-         ptr <- mallocArray0 (P.length x) :: IO (Ptr Word8)-         forM_ [0 .. P.length x] $ \n -> pokeElemOff ptr n 0-         withForeignPtr fp $ \qtr -> copyArray ptr qtr (P.length x)-         y   <- P.unsafePackMallocCString (castPtr ptr)--         let !z = y == x-         free ptr `seq` return z--prop_unsafeFinalize    x =-    P.length x > 0 ==>-      ioProperty $ do-        x <- P.unsafeFinalize x-        return (x == ())--prop_packCStringFinaliser x = ioProperty $ do-        y <- P.useAsCString x $ \cstr -> P.unsafePackCStringFinalizer (castPtr cstr) (P.length x) (return ())-        return (y == x)--prop_fromForeignPtr x = (let (a,b,c) = (P.toForeignPtr x)-                                in P.fromForeignPtr a b c) == x----------------------------------------------------------------------------- IO--prop_read_write_file_P x = ioProperty $ do-    (fn, h) <- openTempFile "." "prop-compiled.tmp"-    hClose h-    P.writeFile fn x-    y <- P.readFile fn-    removeFile fn-    return (x == y)--prop_read_write_file_C x = ioProperty $ do-    (fn, h) <- openTempFile "." "prop-compiled.tmp"-    hClose h-    C.writeFile fn x-    y <- C.readFile fn-    removeFile fn-    return (x == y)--prop_read_write_file_L x = ioProperty $ do-    (fn, h) <- openTempFile "." "prop-compiled.tmp"-    hClose h-    L.writeFile fn x-    y <- L.readFile fn-    L.length y `seq` removeFile fn-    return (x == y)--prop_read_write_file_D x = ioProperty $ do-    (fn, h) <- openTempFile "." "prop-compiled.tmp"-    hClose h-    D.writeFile fn x-    y <- D.readFile fn-    D.length y `seq` removeFile fn-    return (x == y)----------------------------------------------------------------------------prop_append_file_P x y = ioProperty $ do-    (fn, h) <- openTempFile "." "prop-compiled.tmp"-    hClose h-    P.writeFile fn x-    P.appendFile fn y-    z <- P.readFile fn-    removeFile fn-    return (z == x `P.append` y)--prop_append_file_C x y = ioProperty $ do-    (fn, h) <- openTempFile "." "prop-compiled.tmp"-    hClose h-    C.writeFile fn x-    C.appendFile fn y-    z <- C.readFile fn-    removeFile fn-    return (z == x `C.append` y)--prop_append_file_L x y = ioProperty $ do-    (fn, h) <- openTempFile "." "prop-compiled.tmp"-    hClose h-    L.writeFile fn x-    L.appendFile fn y-    z <- L.readFile fn-    L.length y `seq` removeFile fn-    return (z == x `L.append` y)--prop_append_file_D x y = ioProperty $ do-    (fn, h) <- openTempFile "." "prop-compiled.tmp"-    hClose h-    D.writeFile fn x-    D.appendFile fn y-    z <- D.readFile fn-    D.length y `seq` removeFile fn-    return (z == x `D.append` y)--prop_packAddress = C.pack "this is a test"-            ==-                   C.pack "this is a test"--prop_isSpaceWord8 w = isSpace c == P.isSpaceChar8 c-   where c = chr (fromIntegral (w :: Word8))------------------------------------------------------------------------------ ByteString.Short-----prop_short_pack_unpack xs =-    (Short.unpack . Short.pack) xs == xs-prop_short_toShort_fromShort bs =-    (Short.fromShort . Short.toShort) bs == bs--prop_short_toShort_unpack bs =-    (Short.unpack . Short.toShort) bs == P.unpack bs-prop_short_pack_fromShort xs =-    (Short.fromShort . Short.pack) xs == P.pack xs--prop_short_empty =-    Short.empty == Short.toShort P.empty- && Short.empty == Short.pack []- && Short.null (Short.toShort P.empty)- && Short.null (Short.pack [])- && Short.null Short.empty--prop_short_null_toShort bs =-    P.null bs == Short.null (Short.toShort bs)-prop_short_null_pack xs =-    null xs == Short.null (Short.pack xs)--prop_short_length_toShort bs =-    P.length bs == Short.length (Short.toShort bs)-prop_short_length_pack xs =-    length xs == Short.length (Short.pack xs)--prop_short_index_pack xs =-    all (\i -> Short.pack xs `Short.index` i == xs !! i)-        [0 .. length xs - 1]-prop_short_index_toShort bs =-    all (\i -> Short.toShort bs `Short.index` i == bs `P.index` i)-        [0 .. P.length bs - 1]--prop_short_eq xs ys =-    (xs == ys) == (Short.pack xs == Short.pack ys)-prop_short_ord xs ys =-    (xs `compare` ys) == (Short.pack xs `compare` Short.pack ys)--prop_short_mappend_empty_empty =-    Short.empty `mappend` Short.empty  == Short.empty-prop_short_mappend_empty xs =-    Short.empty `mappend` Short.pack xs == Short.pack xs- && Short.pack xs `mappend` Short.empty == Short.pack xs-prop_short_mappend xs ys =-    (xs `mappend` ys) == Short.unpack (Short.pack xs `mappend` Short.pack ys)-prop_short_mconcat xss =-    mconcat xss == Short.unpack (mconcat (map Short.pack xss))--prop_short_fromString s =-    fromString s == Short.fromShort (fromString s)--prop_short_show xs =-    show (Short.pack xs) == show (map P.w2c xs)-prop_short_show' xs =-    show (Short.pack xs) == show (P.pack xs)--prop_short_read xs =-    read (show (Short.pack xs)) == Short.pack xs--prop_short_pinned :: NonNegative Int -> Property-prop_short_pinned (NonNegative (I# len#)) = runST $ ST $ \s ->-  case newPinnedByteArray# len# s of-    (# s', mba# #) -> case unsafeFreezeByteArray# mba# s' of-      (# s'', ba# #) -> let sbs = Short.SBS ba# in-        (# s'', sbs === Short.toShort (Short.fromShort sbs) #)--stripSuffix :: [W] -> [W] -> Maybe [W]-stripSuffix xs ys = reverse <$> stripPrefix (reverse xs) (reverse ys)--short_tests =-    [ testProperty "pack/unpack"              prop_short_pack_unpack-    , testProperty "toShort/fromShort"        prop_short_toShort_fromShort-    , testProperty "toShort/unpack"           prop_short_toShort_unpack-    , testProperty "pack/fromShort"           prop_short_pack_fromShort-    , testProperty "empty"                    prop_short_empty-    , testProperty "null/toShort"             prop_short_null_toShort-    , testProperty "null/pack"                prop_short_null_pack-    , testProperty "length/toShort"           prop_short_length_toShort-    , testProperty "length/pack"              prop_short_length_pack-    , testProperty "index/pack"               prop_short_index_pack-    , testProperty "index/toShort"            prop_short_index_toShort-    , testProperty "Eq"                       prop_short_eq-    , testProperty "Ord"                      prop_short_ord-    , testProperty "mappend/empty/empty"      prop_short_mappend_empty_empty-    , testProperty "mappend/empty"            prop_short_mappend_empty-    , testProperty "mappend"                  prop_short_mappend-    , testProperty "mconcat"                  prop_short_mconcat-    , testProperty "fromString"               prop_short_fromString-    , testProperty "show"                     prop_short_show-    , testProperty "show'"                    prop_short_show'-    , testProperty "read"                     prop_short_read-    , testProperty "pinned"                   prop_short_pinned-    ]----------------------------------------------------------------------------- The entry point--main :: IO ()-main = defaultMain $ testGroup "All" tests------- And now a list of all the properties to test.-----tests = misc_tests-     ++ bl_tests-     ++ cc_tests-     ++ bp_tests-     ++ pl_tests-     ++ bb_tests-     ++ ll_tests-     ++ io_tests-     ++ short_tests-     ++ rules------- 'morally sound' IO----io_tests =-    [ testProperty "readFile.writeFile" prop_read_write_file_P-    , testProperty "readFile.writeFile" prop_read_write_file_C-    , testProperty "readFile.writeFile" prop_read_write_file_L-    , testProperty "readFile.writeFile" prop_read_write_file_D--    , testProperty "appendFile        " prop_append_file_P-    , testProperty "appendFile        " prop_append_file_C-    , testProperty "appendFile        " prop_append_file_L-    , testProperty "appendFile        " prop_append_file_D--    , testProperty "packAddress       " prop_packAddress--    ]--misc_tests =-    [ testProperty "packunpack (bytes)"     prop_packunpack_s-    , testProperty "unpackpack (bytes)"     prop_unpackpack_s-    , testProperty "packunpack (chars)"     prop_packunpack_c-    , testProperty "unpackpack (chars)"     prop_unpackpack_c-    , testProperty "packunpack (lazy bytes)" prop_packunpack_l-    , testProperty "unpackpack (lazy bytes)" prop_unpackpack_l-    , testProperty "packunpack (lazy chars)" prop_packunpack_lc-    , testProperty "unpackpack (lazy chars)" prop_unpackpack_lc-    , testProperty "unpack (bytes)"         prop_unpack_s-    , testProperty "unpack (chars)"         prop_unpack_c-    , testProperty "unpack (lazy bytes)"    prop_unpack_l-    , testProperty "unpack (lazy chars)"    prop_unpack_lc-    , testProperty "packUptoLenBytes"       prop_packUptoLenBytes-    , testProperty "packUptoLenChars"       prop_packUptoLenChars-    , testProperty "unpackBytes"            prop_unpackBytes-    , testProperty "unpackChars"            prop_unpackChars-    , testProperty "unpackBytes"            prop_unpackBytes_l-    , testProperty "unpackChars"            prop_unpackChars_l-    , testProperty "unpackAppendBytesLazy"  prop_unpackAppendBytesLazy-    , testProperty "unpackAppendCharsLazy"  prop_unpackAppendCharsLazy-    , testProperty "unpackAppendBytesStrict"prop_unpackAppendBytesStrict-    , testProperty "unpackAppendCharsStrict"prop_unpackAppendCharsStrict-    , testProperty "toFromChunks"           prop_toFromChunks-    , testProperty "fromToChunks"           prop_fromToChunks-    , testProperty "toFromStrict"           prop_toFromStrict-    , testProperty "fromToStrict"           prop_fromToStrict--    , testProperty "invariant"              prop_invariant-    , testProperty "unsafe pack address"    prop_unsafePackAddress-    , testProperty "unsafe pack address len"prop_unsafePackAddressLen-    , testProperty "unsafeUseAsCString"     prop_unsafeUseAsCString-    , testProperty "unsafeUseAsCStringLen"  prop_unsafeUseAsCStringLen-    , testProperty "useAsCString"           prop_useAsCString-    , testProperty "packCString"            prop_packCString-    , testProperty "packCString safe"       prop_packCString_safe-    , testProperty "packCStringLen"         prop_packCStringLen-    , testProperty "packCStringLen safe"    prop_packCStringLen_safe-    , testProperty "packCStringFinaliser"   prop_packCStringFinaliser-    , testProperty "packMallocString"       prop_packMallocCString-    , testProperty "unsafeFinalise"         prop_unsafeFinalize-    , testProperty "invariant"              prop_internal_invariant-    , testProperty "show 1"                 prop_showP1-    , testProperty "show 2"                 prop_showL1-    , testProperty "read 1"                 prop_readP1-    , testProperty "read 2"                 prop_readP2-    , testProperty "read 3"                 prop_readL1-    , testProperty "read 4"                 prop_readL2-    , testProperty "fromForeignPtr"         prop_fromForeignPtr-    ]----------------------------------------------------------------------------- ByteString.Lazy <=> List--bl_tests =-    [ testProperty "all"         prop_allBL-    , testProperty "any"         prop_anyBL-    , testProperty "append"      prop_appendBL-    , testProperty "compare"     prop_compareBL-    , testProperty "concat"      prop_concatBL-    , testProperty "cons"        prop_consBL-    , testProperty "eq"          prop_eqBL-    , testProperty "filter"      prop_filterBL-    , testProperty "find"        prop_findBL-    , testProperty "findIndex"   prop_findIndexBL-    , testProperty "findIndexEnd"prop_findIndexEndBL-    , testProperty "findIndices" prop_findIndicesBL-    , testProperty "foldl"       prop_foldlBL-    , testProperty "foldl'"      prop_foldlBL'-    , testProperty "foldl1"      prop_foldl1BL-    , testProperty "foldl1'"     prop_foldl1BL'-    , testProperty "foldr"       prop_foldrBL-    , testProperty "foldr1"      prop_foldr1BL-    , testProperty "mapAccumL"   prop_mapAccumLBL-    , testProperty "mapAccumR"   prop_mapAccumRBL-    , testProperty "mapAccumR"   prop_mapAccumRDL-    , testProperty "mapAccumR"   prop_mapAccumRCC-    , testProperty "unfoldr"     prop_unfoldrBL-    , testProperty "unfoldr"     prop_unfoldrLC-    , testProperty "unfoldr"     prop_cycleLC-    , testProperty "iterate"     prop_iterateLC-    , testProperty "iterate"     prop_iterateLC_2-    , testProperty "iterate"     prop_iterateL-    , testProperty "repeat"      prop_repeatLC-    , testProperty "repeat"      prop_repeatL-    , testProperty "head"        prop_headBL-    , testProperty "init"        prop_initBL-    , testProperty "isPrefixOf"  prop_isPrefixOfBL-    , testProperty "isSuffixOf"  prop_isSuffixOfBL-    , testProperty "stripPrefix" prop_stripPrefixBL-    , testProperty "stripSuffix" prop_stripSuffixBL-    , testProperty "last"        prop_lastBL-    , testProperty "length"      prop_lengthBL-    , testProperty "map"         prop_mapBL-    , testProperty "maximum"     prop_maximumBL-    , testProperty "minimum"     prop_minimumBL-    , testProperty "null"        prop_nullBL-    , testProperty "reverse"     prop_reverseBL-    , testProperty "snoc"        prop_snocBL-    , testProperty "tail"        prop_tailBL-    , testProperty "transpose"   prop_transposeBL-    , testProperty "replicate"   prop_replicateBL-    , testProperty "take"        prop_takeBL-    , testProperty "drop"        prop_dropBL-    , testProperty "splitAt"     prop_splitAtBL-    , testProperty "takeWhile"   prop_takeWhileBL-    , testProperty "dropWhile"   prop_dropWhileBL-    , testProperty "break"       prop_breakBL-    , testProperty "span"        prop_spanBL-    , testProperty "group"       prop_groupBL-    , testProperty "groupBy"     prop_groupByBL-    , testProperty "inits"       prop_initsBL-    , testProperty "tails"       prop_tailsBL-    , testProperty "elem"        prop_elemBL-    , testProperty "notElem"     prop_notElemBL-    , testProperty "lines"       prop_linesBL-    , testProperty "elemIndex"   prop_elemIndexBL-    , testProperty "elemIndexEnd"prop_elemIndexEndBL-    , testProperty "elemIndices" prop_elemIndicesBL-    , testProperty "concatMap"   prop_concatMapBL-    , testProperty "zipWith/packZipWithLazy" prop_packZipWithBL-    ]----------------------------------------------------------------------------- ByteString.Lazy <=> ByteString--cc_tests =-    [ testProperty "prop_concatCC"      prop_concatCC-    , testProperty "prop_nullCC"        prop_nullCC-    , testProperty "prop_reverseCC"     prop_reverseCC-    , testProperty "prop_transposeCC"   prop_transposeCC-    , testProperty "prop_groupCC"       prop_groupCC-    , testProperty "prop_groupByCC"     prop_groupByCC-    , testProperty "prop_initsCC"       prop_initsCC-    , testProperty "prop_tailsCC"       prop_tailsCC-    , testProperty "prop_allCC"         prop_allCC-    , testProperty "prop_anyCC"         prop_anyCC-    , testProperty "prop_appendCC"      prop_appendCC-    , testProperty "prop_breakCC"       prop_breakCC-    , testProperty "prop_concatMapCC"   prop_concatMapCC-    , testProperty "prop_consCC"        prop_consCC-    , testProperty "prop_consCC'"       prop_consCC'-    , testProperty "prop_unconsCC"      prop_unconsCC-    , testProperty "prop_unsnocCC"      prop_unsnocCC-    , testProperty "prop_countCC"       prop_countCC-    , testProperty "prop_dropCC"        prop_dropCC-    , testProperty "prop_dropWhileCC"   prop_dropWhileCC-    , testProperty "prop_filterCC"      prop_filterCC-    , testProperty "prop_findCC"        prop_findCC-    , testProperty "prop_findIndexCC"   prop_findIndexCC-    , testProperty "prop_findIndexEndCC" prop_findIndexEndCC-    , testProperty "prop_findIndicesCC" prop_findIndicesCC-    , testProperty "prop_isPrefixCC"    prop_isPrefixOfCC-    , testProperty "prop_isSuffixCC"    prop_isSuffixOfCC-    , testProperty "prop_stripPrefixCC" prop_stripPrefixCC-    , testProperty "prop_stripSuffixCC" prop_stripSuffixCC-    , testProperty "prop_mapCC"         prop_mapCC-    , testProperty "prop_replicateCC"   prop_replicateCC-    , testProperty "prop_snocCC"        prop_snocCC-    , testProperty "prop_spanCC"        prop_spanCC-    , testProperty "prop_splitCC"       prop_splitCC-    , testProperty "prop_splitAtCC"     prop_splitAtCC-    , testProperty "prop_takeCC"        prop_takeCC-    , testProperty "prop_takeWhileCC"   prop_takeWhileCC-    , testProperty "prop_elemCC"        prop_elemCC-    , testProperty "prop_notElemCC"     prop_notElemCC-    , testProperty "prop_elemIndexCC"   prop_elemIndexCC-    , testProperty "prop_elemIndicesCC" prop_elemIndicesCC-    , testProperty "prop_lengthCC"      prop_lengthCC-    , testProperty "prop_headCC"        prop_headCC-    , testProperty "prop_initCC"        prop_initCC-    , testProperty "prop_lastCC"        prop_lastCC-    , testProperty "prop_maximumCC"     prop_maximumCC-    , testProperty "prop_minimumCC"     prop_minimumCC-    , testProperty "prop_tailCC"        prop_tailCC-    , testProperty "prop_foldl1CC"      prop_foldl1CC-    , testProperty "prop_foldl1CC'"     prop_foldl1CC'-    , testProperty "prop_foldr1CC"      prop_foldr1CC-    , testProperty "prop_foldr1CC'"     prop_foldr1CC'-    , testProperty "prop_scanlCC"       prop_scanlCC-    , testProperty "prop_intersperseCC" prop_intersperseCC--    , testProperty "prop_foldlCC"       prop_foldlCC-    , testProperty "prop_foldlCC'"      prop_foldlCC'-    , testProperty "prop_foldrCC"       prop_foldrCC-    , testProperty "prop_foldrCC'"      prop_foldrCC'-    , testProperty "prop_mapAccumLCC"   prop_mapAccumLCC---    , testProperty "prop_mapIndexedCC" prop_mapIndexedCC---    , testProperty "prop_mapIndexedPL" prop_mapIndexedPL-    ]--bp_tests =-    [ testProperty "all"         prop_allBP-    , testProperty "any"         prop_anyBP-    , testProperty "append"      prop_appendBP-    , testProperty "compare"     prop_compareBP-    , testProperty "concat"      prop_concatBP-    , testProperty "cons"        prop_consBP-    , testProperty "cons'"       prop_consBP'-    , testProperty "uncons"      prop_unconsBP-    , testProperty "unsnoc"      prop_unsnocBP-    , testProperty "eq"          prop_eqBP-    , testProperty "filter"      prop_filterBP-    , testProperty "find"        prop_findBP-    , testProperty "findIndex"   prop_findIndexBP-    , testProperty "findIndexEnd"prop_findIndexEndBP-    , testProperty "findIndices" prop_findIndicesBP-    , testProperty "foldl"       prop_foldlBP-    , testProperty "foldl'"      prop_foldlBP'-    , testProperty "foldl1"      prop_foldl1BP-    , testProperty "foldl1'"     prop_foldl1BP'-    , testProperty "foldr"       prop_foldrBP-    , testProperty "foldr'"      prop_foldrBP'-    , testProperty "foldr1"      prop_foldr1BP-    , testProperty "foldr1'"     prop_foldr1BP'-    , testProperty "mapAccumL"   prop_mapAccumLBP---  , testProperty "mapAccumL"   prop_mapAccumL_mapIndexedBP-    , testProperty "unfoldr"     prop_unfoldrBP-    , testProperty "unfoldr 2"   prop_unfoldr2BP-    , testProperty "unfoldr 2"   prop_unfoldr2CP-    , testProperty "head"        prop_headBP-    , testProperty "init"        prop_initBP-    , testProperty "isPrefixOf"  prop_isPrefixOfBP-    , testProperty "isSuffixOf"  prop_isSuffixOfBP-    , testProperty "stripPrefix" prop_stripPrefixBP-    , testProperty "stripSuffix" prop_stripSuffixBP-    , testProperty "last"        prop_lastBP-    , testProperty "length"      prop_lengthBP-    , testProperty "readInt"     prop_readIntBP-    , testProperty "lines"       prop_linesBP-    , testProperty "lines \\n"   prop_linesNLBP-    , testProperty "map"         prop_mapBP-    , testProperty "maximum   "  prop_maximumBP-    , testProperty "minimum"     prop_minimumBP-    , testProperty "null"        prop_nullBP-    , testProperty "reverse"     prop_reverseBP-    , testProperty "snoc"        prop_snocBP-    , testProperty "tail"        prop_tailBP-    , testProperty "scanl"       prop_scanlBP-    , testProperty "transpose"   prop_transposeBP-    , testProperty "replicate"   prop_replicateBP-    , testProperty "take"        prop_takeBP-    , testProperty "drop"        prop_dropBP-    , testProperty "splitAt"     prop_splitAtBP-    , testProperty "takeWhile"   prop_takeWhileBP-    , testProperty "dropWhile"   prop_dropWhileBP-    , testProperty "break"       prop_breakBP-    , testProperty "span"        prop_spanBP-    , testProperty "split"       prop_splitBP-    , testProperty "count"       prop_countBP-    , testProperty "group"       prop_groupBP-    , testProperty "groupBy"     prop_groupByBP-    , testProperty "inits"       prop_initsBP-    , testProperty "tails"       prop_tailsBP-    , testProperty "elem"        prop_elemBP-    , testProperty "notElem"     prop_notElemBP-    , testProperty "elemIndex"   prop_elemIndexBP-    , testProperty "elemIndexEnd"prop_elemIndexEndBP-    , testProperty "elemIndices" prop_elemIndicesBP-    , testProperty "intersperse" prop_intersperseBP-    , testProperty "concatMap"   prop_concatMapBP-    ]----------------------------------------------------------------------------- ByteString <=> List--pl_tests =-    [ testProperty "all"         prop_allPL-    , testProperty "any"         prop_anyPL-    , testProperty "append"      prop_appendPL-    , testProperty "compare"     prop_comparePL-    , testProperty "concat"      prop_concatPL-    , testProperty "cons"        prop_consPL-    , testProperty "eq"          prop_eqPL-    , testProperty "filter"      prop_filterPL-    , testProperty "filter rules"prop_filterPL_rule-    , testProperty "filter rules"prop_filterLC_rule-    , testProperty "partition"   prop_partitionPL-    , testProperty "partition"   prop_partitionLL-    , testProperty "find"        prop_findPL-    , testProperty "findIndex"   prop_findIndexPL-    , testProperty "findIndexEnd"prop_findIndexEndPL-    , testProperty "findIndices" prop_findIndicesPL-    , testProperty "foldl"       prop_foldlPL-    , testProperty "foldl'"      prop_foldlPL'-    , testProperty "foldl1"      prop_foldl1PL-    , testProperty "foldl1'"     prop_foldl1PL'-    , testProperty "foldr1"      prop_foldr1PL-    , testProperty "foldr"       prop_foldrPL-    , testProperty "mapAccumL"   prop_mapAccumLPL-    , testProperty "mapAccumR"   prop_mapAccumRPL-    , testProperty "unfoldr"     prop_unfoldrPL-    , testProperty "scanl"       prop_scanlPL-    , testProperty "scanl1"      prop_scanl1PL-    , testProperty "scanl1"      prop_scanl1CL-    , testProperty "scanr"       prop_scanrCL-    , testProperty "scanr"       prop_scanrPL-    , testProperty "scanr1"      prop_scanr1PL-    , testProperty "scanr1"      prop_scanr1CL-    , testProperty "head"        prop_headPL-    , testProperty "init"        prop_initPL-    , testProperty "last"        prop_lastPL-    , testProperty "maximum"     prop_maximumPL-    , testProperty "minimum"     prop_minimumPL-    , testProperty "tail"        prop_tailPL-    , testProperty "zip"         prop_zipPL-    , testProperty "zip"         prop_zipLL-    , testProperty "zip"         prop_zipCL-    , testProperty "unzip"       prop_unzipPL-    , testProperty "unzip"       prop_unzipLL-    , testProperty "unzip"       prop_unzipCL-    , testProperty "unzip"       prop_unzipDL-    , testProperty "zipWithPL"          prop_zipWithPL-    , testProperty "zipWithPL rules"   prop_zipWithPL_rules-    , testProperty "packZipWithPL" prop_packZipWithPL--    , testProperty "isPrefixOf"  prop_isPrefixOfPL-    , testProperty "isSuffixOf"  prop_isSuffixOfPL-    , testProperty "isInfixOf"   prop_isInfixOfPL-    , testProperty "stripPrefix" prop_stripPrefixPL-    , testProperty "stripSuffix" prop_stripSuffixPL-    , testProperty "length"      prop_lengthPL-    , testProperty "map"         prop_mapPL-    , testProperty "null"        prop_nullPL-    , testProperty "reverse"     prop_reversePL-    , testProperty "snoc"        prop_snocPL-    , testProperty "transpose"   prop_transposePL-    , testProperty "replicate"   prop_replicatePL-    , testProperty "take"        prop_takePL-    , testProperty "drop"        prop_dropPL-    , testProperty "splitAt"     prop_splitAtPL-    , testProperty "takeWhile"   prop_takeWhilePL-    , testProperty "dropWhile"   prop_dropWhilePL-    , testProperty "break"       prop_breakPL-    , testProperty "span"        prop_spanPL-    , testProperty "group"       prop_groupPL-    , testProperty "groupBy"     prop_groupByPL-    , testProperty "inits"       prop_initsPL-    , testProperty "tails"       prop_tailsPL-    , testProperty "elem"        prop_elemPL-    , testProperty "notElem"     prop_notElemPL-    , testProperty "lines"       prop_linesPL-    , testProperty "elemIndex"   prop_elemIndexPL-    , testProperty "elemIndex"   prop_elemIndexCL-    , testProperty "elemIndices" prop_elemIndicesPL-    , testProperty "concatMap"   prop_concatMapPL-    , testProperty "IsString"    prop_isstring-    , testProperty "IsString LC" prop_isstring_lc-    ]----------------------------------------------------------------------------- extra ByteString properties--bb_tests =-    [ testProperty "bijection"      prop_bijectionBB-    , testProperty "bijection'"     prop_bijectionBB'-    , testProperty "pack/unpack"    prop_packunpackBB-    , testProperty "unpack/pack"    prop_packunpackBB'-    , testProperty "eq 1"           prop_eq1BB-    , testProperty "eq 2"           prop_eq2BB-    , testProperty "eq 3"           prop_eq3BB-    , testProperty "compare 1"      prop_compare1BB-    , testProperty "compare 2"      prop_compare2BB-    , testProperty "compare 3"      prop_compare3BB-    , testProperty "compare 4"      prop_compare4BB-    , testProperty "compare 5"      prop_compare5BB-    , testProperty "compare 6"      prop_compare6BB-    , testProperty "compare 7"      prop_compare7BB-    , testProperty "compare 7"      prop_compare7LL-    , testProperty "compare 8"      prop_compare8BB-    , testProperty "empty 1"        prop_nil1BB-    , testProperty "empty 2"        prop_nil2BB-    , testProperty "empty 1 monoid" prop_nil1LL_monoid-    , testProperty "empty 2 monoid" prop_nil2LL_monoid-    , testProperty "empty 1 monoid" prop_nil1BB_monoid-    , testProperty "empty 2 monoid" prop_nil2BB_monoid--    , testProperty "null"           prop_nullBB-    , testProperty "length 1"       prop_lengthBB-    , testProperty "length 2"       prop_lengthSBB-    , testProperty "cons 1"         prop_consBB-    , testProperty "cons 2"         prop_cons1BB-    , testProperty "cons 3"         prop_cons2BB-    , testProperty "cons 4"         prop_cons3BB-    , testProperty "cons 5"         prop_cons4BB-    , testProperty "snoc"           prop_snoc1BB-    , testProperty "head 1"         prop_head1BB-    , testProperty "head 2"         prop_head2BB-    , testProperty "head 3"         prop_head3BB-    , testProperty "tail"           prop_tailBB-    , testProperty "tail 1"         prop_tail1BB-    , testProperty "last"           prop_lastBB-    , testProperty "last 1"         prop_last1BB-    , testProperty "init"           prop_initBB-    , testProperty "init 1"         prop_init1BB-    , testProperty "append 1"       prop_append1BB-    , testProperty "append 2"       prop_append2BB-    , testProperty "append 3"       prop_append3BB-    , testProperty "mappend 1"      prop_append1BB_monoid-    , testProperty "mappend 2"      prop_append2BB_monoid-    , testProperty "mappend 3"      prop_append3BB_monoid--    , testProperty "map 1"          prop_map1BB-    , testProperty "map 2"          prop_map2BB-    , testProperty "map 3"          prop_map3BB-    , testProperty "filter1"        prop_filter1BB-    , testProperty "filter2"        prop_filter2BB-    , testProperty "map fusion"     prop_mapfusionBB-    , testProperty "filter fusion"  prop_filterfusionBB-    , testProperty "reverse 1"      prop_reverse1BB-    , testProperty "reverse 2"      prop_reverse2BB-    , testProperty "reverse 3"      prop_reverse3BB-    , testProperty "foldl 1"        prop_foldl1BB-    , testProperty "foldl 2"        prop_foldl2BB-    , testProperty "foldr 1"        prop_foldr1BB-    , testProperty "foldr 2"        prop_foldr2BB-    , testProperty "foldl1 1"       prop_foldl1_1BB-    , testProperty "foldl1 2"       prop_foldl1_2BB-    , testProperty "foldl1 3"       prop_foldl1_3BB-    , testProperty "foldr1 1"       prop_foldr1_1BB-    , testProperty "foldr1 2"       prop_foldr1_2BB-    , testProperty "foldr1 3"       prop_foldr1_3BB-    , testProperty "scanl/foldl"    prop_scanlfoldlBB-    , testProperty "all"            prop_allBB-    , testProperty "any"            prop_anyBB-    , testProperty "take"           prop_takeBB-    , testProperty "drop"           prop_dropBB-    , testProperty "takeWhile_ne"   prop_takeWhileBB_ne-    , testProperty "takeWhile_eq"   prop_takeWhileBB_eq-    , testProperty "dropWhile_ne"   prop_dropWhileBB_ne-    , testProperty "dropWhile_eq"   prop_dropWhileBB_eq-    , testProperty "dropWhile_isSpace" prop_dropWhileCC_isSpace-    , testProperty "splitAt"        prop_splitAtBB-    , testProperty "span"           prop_spanBB-    , testProperty "break"          prop_breakBB-    , testProperty "elem"           prop_elemBB-    , testProperty "notElem"        prop_notElemBB--    , testProperty "concat 1"       prop_concat1BB-    , testProperty "concat 2"       prop_concat2BB-    , testProperty "concat 3"       prop_concatBB-    , testProperty "mconcat 1"      prop_concat1BB_monoid-    , testProperty "mconcat 2"      prop_concat2BB_monoid-    , testProperty "mconcat 3"      prop_concatBB_monoid--    , testProperty "mconcat 1"      prop_concat1LL_monoid-    , testProperty "mconcat 2"      prop_concat2LL_monoid-    , testProperty "mconcat 3"      prop_concatLL_monoid--    , testProperty "lines"          prop_linesBB-    , testProperty "unlines"        prop_unlinesBB-    , testProperty "unlines"        prop_unlinesLC-    , testProperty "lines_lazy1"    prop_lines_lazy1-    , testProperty "lines_lazy2"    prop_lines_lazy2-    , testProperty "words"          prop_wordsBB-    , testProperty "words"          prop_wordsLC-    , testProperty "unwords"        prop_unwordsBB-    , testProperty "group"          prop_groupBB-    , testProperty "groupBy 0"      prop_groupByBB-    , testProperty "groupBy 1"      prop_groupBy1CC-    , testProperty "groupBy 2"      prop_groupBy1BB-    , testProperty "groupBy 3"      prop_groupBy2CC-    , testProperty "join"           prop_joinBB-    , testProperty "elemIndex 1"    prop_elemIndex1BB-    , testProperty "elemIndex 2"    prop_elemIndex2BB-    , testProperty "findIndex"      prop_findIndexBB-    , testProperty "findIndexEnd"   prop_findIndexEndBB-    , testProperty "findIndexEnd"   prop_findIndexEndLL-    , testProperty "findIndexEnd"   prop_findIndexEndDD-    , testProperty "findIndicies"   prop_findIndiciesBB-    , testProperty "elemIndices"    prop_elemIndicesBB-    , testProperty "find"           prop_findBB-    , testProperty "find/findIndex" prop_find_findIndexBB-    , testProperty "sort 1"         prop_sort1BB-    , testProperty "sort 2"         prop_sort2BB-    , testProperty "sort 3"         prop_sort3BB-    , testProperty "sort 4"         prop_sort4BB-    , testProperty "sort 5"         prop_sort5BB-    , testProperty "intersperse"    prop_intersperseBB-    , testProperty "maximum"        prop_maximumBB-    , testProperty "minimum"        prop_minimumBB-    , testProperty "strip"          prop_strip---  , testProperty "breakChar"      prop_breakCharBB---  , testProperty "spanChar 1"     prop_spanCharBB---  , testProperty "spanChar 2"     prop_spanChar_1BB---  , testProperty "breakSpace"     prop_breakSpaceBB---  , testProperty "dropSpace"      prop_dropSpaceBB-    , testProperty "spanEnd"        prop_spanEndBB-    , testProperty "breakEnd"       prop_breakEndBB-    , testProperty "breakEnd"       prop_breakEndCC-    , testProperty "elemIndexEnd"   prop_elemIndexEnd1BB-    , testProperty "elemIndexEnd"   prop_elemIndexEnd1CC-    , testProperty "elemIndexEnd"   prop_elemIndexEnd1LL-    , testProperty "elemIndexEnd"   prop_elemIndexEnd1DD---  , testProperty "words'"         prop_wordsBB'---  , testProperty "lines'"         prop_linesBB'---  , testProperty "dropSpaceEnd"   prop_dropSpaceEndBB-    , testProperty "unfoldr"        prop_unfoldrBB-    , testProperty "prefix"         prop_prefixBB-    , testProperty "prefix"         prop_prefixLL-    , testProperty "suffix"         prop_suffixBB-    , testProperty "suffix"         prop_suffixLL-    , testProperty "stripPrefix"    prop_stripPrefixBB-    , testProperty "stripPrefix"    prop_stripPrefixLL-    , testProperty "stripSuffix"    prop_stripSuffixBB-    , testProperty "stripSuffix"    prop_stripSuffixLL-    , testProperty "copy"           prop_copyBB-    , testProperty "copy"           prop_copyLL-    , testProperty "inits"          prop_initsBB-    , testProperty "tails"          prop_tailsBB-    , testProperty "breakSubstring 1"prop_breakSubstringBB-    , testProperty "breakSubstring 3"prop_breakSubstring_isInfixOf--    , testProperty "replicate1"     prop_replicate1BB-    , testProperty "replicate2"     prop_replicate2BB-    , testProperty "replicate3"     prop_replicate3BB-    , testProperty "readInt"        prop_readintBB-    , testProperty "readInt 2"      prop_readint2BB-    , testProperty "readInteger"    prop_readintegerBB-    , testProperty "readInteger 2"  prop_readinteger2BB-    , testProperty "read"           prop_readLL-    , testProperty "read"           prop_readBB-    , testProperty "Lazy.readInt"   prop_readintLL-    , testProperty "Lazy.readInt"   prop_readintLL-    , testProperty "Lazy.readInteger" prop_readintegerLL--    , testProperty "readIntSafe"       prop_readIntSafe-    , testProperty "readIntUnsafe"     prop_readIntUnsafe-    , testProperty "readIntegerSafe"   prop_readIntegerSafe-    , testProperty "readIntegerUnsafe" prop_readIntegerUnsafe--    , testProperty "mconcat 1"      prop_append1LL_monoid-    , testProperty "mconcat 2"      prop_append2LL_monoid-    , testProperty "mconcat 3"      prop_append3LL_monoid---  , testProperty "filterChar1"    prop_filterChar1BB---  , testProperty "filterChar2"    prop_filterChar2BB---  , testProperty "filterChar3"    prop_filterChar3BB---  , testProperty "filterNotChar1" prop_filterNotChar1BB---  , testProperty "filterNotChar2" prop_filterNotChar2BB-    , testProperty "tail"           prop_tailSBB-    , testProperty "index"          prop_indexBB-    , testProperty "unsafeIndex"    prop_unsafeIndexBB---  , testProperty "map'"           prop_mapBB'-    , testProperty "filter"         prop_filterBB-    , testProperty "elem"           prop_elemSBB-    , testProperty "take"           prop_takeSBB-    , testProperty "drop"           prop_dropSBB-    , testProperty "splitAt"        prop_splitAtSBB-    , testProperty "foldl"          prop_foldlBB-    , testProperty "foldr"          prop_foldrBB-    , testProperty "takeWhile "     prop_takeWhileSBB-    , testProperty "dropWhile "     prop_dropWhileSBB-    , testProperty "span "          prop_spanSBB-    , testProperty "break "         prop_breakSBB-    , testProperty "breakspan"      prop_breakspan_1BB-    , testProperty "lines "         prop_linesSBB-    , testProperty "unlines "       prop_unlinesSBB-    , testProperty "words "         prop_wordsSBB-    , testProperty "unwords "       prop_unwordsSBB-    , testProperty "unwords "       prop_unwordsSLC---     , testProperty "wordstokens"    prop_wordstokensBB-    , testProperty "splitWith_empty" prop_splitWithBB_empty-    , testProperty "splitWith"      prop_splitWithBB-    , testProperty "split_empty"    prop_splitBB_empty-    , testProperty "joinsplit"      prop_joinsplitBB-    , testProperty "intercalate"    prop_intercalatePL---     , testProperty "lineIndices"    prop_lineIndices1BB-    , testProperty "count"          prop_countBB---  , testProperty "linessplit"     prop_linessplit2BB-    , testProperty "splitsplitWith" prop_splitsplitWithBB---  , testProperty "joinjoinpath"   prop_joinjoinpathBB-    , testProperty "zip"            prop_zipBB-    , testProperty "zip"            prop_zipLC-    , testProperty "zip1"           prop_zip1BB-    , testProperty "zipWithBB"        prop_zipWithBB-    , testProperty "zipWithCC"        prop_zipWithCC-    , testProperty "zipWithLC"        prop_zipWithLC-    , testProperty "packZipWithBB"    prop_packZipWithBB-    , testProperty "packZipWithLL"    prop_packZipWithLL-    , testProperty "packZipWithBC"    prop_packZipWithBC-    , testProperty "packZipWithLC"    prop_packZipWithLC-    , testProperty "unzip"          prop_unzipBB-    , testProperty "concatMap"      prop_concatMapBB---  , testProperty "join/joinByte"  prop_join_spec-#if MIN_VERSION_base(4,9,0)-    , testProperty "stimes strict"  prop_stimesBB-    , testProperty "stimes lazy"    prop_stimesLL-#endif-    ]------------------------------------------------------------------------------ Extra lazy properties--ll_tests =-    [ testProperty "eq 1"               prop_eq1-    , testProperty "eq 2"               prop_eq2-    , testProperty "eq 3"               prop_eq3-    , testProperty "eq refl"            prop_eq_refl-    , testProperty "eq symm"            prop_eq_symm-    , testProperty "compare 1"          prop_compare1-    , testProperty "compare 2"          prop_compare2-    , testProperty "compare 3"          prop_compare3-    , testProperty "compare 4"          prop_compare4-    , testProperty "compare 5"          prop_compare5-    , testProperty "compare 6"          prop_compare6-    , testProperty "compare 7"          prop_compare7-    , testProperty "compare 8"          prop_compare8-    , testProperty "compare 9"          prop_compare9-    , testProperty "empty 1"            prop_empty1-    , testProperty "empty 2"            prop_empty2-    , testProperty "pack/unpack"        prop_packunpack-    , testProperty "unpack/pack"        prop_unpackpack-    , testProperty "null"               prop_null-    , testProperty "length 1"           prop_length1-    , testProperty "length 2"           prop_length2-    , testProperty "cons 1"             prop_cons1-    , testProperty "cons 2"             prop_cons2-    , testProperty "cons 3"             prop_cons3-    , testProperty "cons 4"             prop_cons4-    , testProperty "snoc"               prop_snoc1-    , testProperty "head/pack"          prop_head-    , testProperty "head/unpack"        prop_head1-    , testProperty "tail/pack"          prop_tail-    , testProperty "tail/unpack"        prop_tail1-    , testProperty "last"               prop_last-    , testProperty "init"               prop_init-    , testProperty "append 1"           prop_append1-    , testProperty "appendLazy"         prop_appendLazy-    , testProperty "append 2"           prop_append2-    , testProperty "append 3"           prop_append3-    , testProperty "map 1"              prop_map1-    , testProperty "map 2"              prop_map2-    , testProperty "map 3"              prop_map3-    , testProperty "filter 1"           prop_filter1-    , testProperty "filter 2"           prop_filter2-    , testProperty "reverse"            prop_reverse-    , testProperty "reverse1"           prop_reverse1-    , testProperty "reverse2"           prop_reverse2-    , testProperty "transpose"          prop_transpose-    , testProperty "foldl"              prop_foldl-    , testProperty "foldl/reverse"      prop_foldl_1-    , testProperty "foldr"              prop_foldr-    , testProperty "foldr/id"           prop_foldr_1-    , testProperty "foldl1/foldl"       prop_foldl1_1-    , testProperty "foldl1/head"        prop_foldl1_2-    , testProperty "foldl1/tail"        prop_foldl1_3-    , testProperty "foldr1/foldr"       prop_foldr1_1-    , testProperty "foldr1/last"        prop_foldr1_2-    , testProperty "foldr1/head"        prop_foldr1_3-    , testProperty "concat 1"           prop_concat1-    , testProperty "concat 2"           prop_concat2-    , testProperty "concat/pack"        prop_concat3-    , testProperty "any"                prop_any-    , testProperty "all"                prop_all-    , testProperty "maximum"            prop_maximum-    , testProperty "minimum"            prop_minimum-    , testProperty "compareLength 1"    prop_compareLength1-    , testProperty "compareLength 2"    prop_compareLength2-    , testProperty "compareLength 3"    prop_compareLength3-    , testProperty "compareLength 4"    prop_compareLength4-    , testProperty "compareLength 5"    prop_compareLength5-    , testProperty "replicate 1"        prop_replicate1-    , testProperty "replicate 2"        prop_replicate2-    , testProperty "take"               prop_take1-    , testProperty "takeEnd"            prop_takeEnd-    , testProperty "drop"               prop_drop1-    , testProperty "dropEnd"            prop_dropEnd-    , testProperty "splitAt"            prop_drop1-    , testProperty "takeWhile"          prop_takeWhile-    , testProperty "dropWhile"          prop_dropWhile-    , testProperty "takeWhileEnd"       prop_takeWhileEnd-    , testProperty "dropWhileEnd"       prop_dropWhileEnd-    , testProperty "break"              prop_break-    , testProperty "span"               prop_span-    , testProperty "splitAt"            prop_splitAt-    , testProperty "break/span"         prop_breakspan-    , testProperty "split"              prop_split-    , testProperty "splitWith_empty"    prop_splitWith_empty-    , testProperty "splitWith"          prop_splitWith-    , testProperty "splitWith_empty"    prop_splitWith_D_empty-    , testProperty "splitWith"          prop_splitWith_D-    , testProperty "splitWith_empty"    prop_splitWith_C_empty-    , testProperty "splitWith"          prop_splitWith_C-    , testProperty "split_empty"        prop_split_empty-    , testProperty "join.split/id"      prop_joinsplit---  , testProperty "join/joinByte"      prop_joinjoinByte-    , testProperty "group"              prop_group-    , testProperty "groupBy"            prop_groupBy-    , testProperty "groupBy"            prop_groupBy_LC-    , testProperty "index"              prop_index-    , testProperty "index"              prop_index_D-    , testProperty "index"              prop_index_C-    , testProperty "indexMaybe"         prop_indexMaybe_Just_P-    , testProperty "indexMaybe"         prop_indexMaybe_Just_L-    , testProperty "indexMaybe"         prop_indexMaybe_Nothing_P-    , testProperty "indexMaybe"         prop_indexMaybe_Nothing_L-    , testProperty "elemIndex"          prop_elemIndex-    , testProperty "elemIndices"        prop_elemIndices-    , testProperty "count/elemIndices"  prop_count-    , testProperty "findIndex"          prop_findIndex-    , testProperty "findIndexEnd"       prop_findIndexEnd-    , testProperty "findIndices"        prop_findIndicies-    , testProperty "find"               prop_find-    , testProperty "find/findIndex"     prop_find_findIndex-    , testProperty "elem"               prop_elem-    , testProperty "notElem"            prop_notElem-    , testProperty "elem/notElem"       prop_elem_notelem---  , testProperty "filterByte 1"       prop_filterByte---  , testProperty "filterByte 2"       prop_filterByte2---  , testProperty "filterNotByte 1"    prop_filterNotByte---  , testProperty "filterNotByte 2"    prop_filterNotByte2-    , testProperty "isPrefixOf"         prop_isPrefixOf-    , testProperty "isSuffixOf"         prop_isSuffixOf-    , testProperty "stripPrefix"        prop_stripPrefix-    , testProperty "stripSuffix"        prop_stripSuffix-    , testProperty "concatMap"          prop_concatMap-    , testProperty "isSpace"            prop_isSpaceWord8-    ]--findIndexEnd :: (a -> Bool) -> [a] -> Maybe Int-findIndexEnd p = go . findIndices p-  where-    go [] = Nothing-    go (k:[]) = Just k-    go (k:ks) = go ks--elemIndexEnd :: Eq a => a -> [a] -> Maybe Int-elemIndexEnd = findIndexEnd . (==)+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE MagicHash #-}+{-# LANGUAGE UnboxedTuples #-}++module Properties (testSuite) where++import Foreign.C.String (withCString)+import Foreign.Storable+import Foreign.ForeignPtr+import Foreign.Marshal.Alloc+import Foreign.Marshal.Array+import GHC.Ptr+import Test.Tasty.QuickCheck+import Control.Applicative+import Control.Monad+import Control.Concurrent+import Control.Exception+import System.Posix.Internals (c_unlink)++import qualified Data.List as List+import Data.Char+import Data.Word+import Data.Maybe+import Data.Int (Int64)+import Data.Semigroup+import GHC.Exts (Int(..), newPinnedByteArray#, unsafeFreezeByteArray#)+import GHC.ST (ST(..), runST)++import Text.Printf+import Data.String++import System.Environment+import System.IO++import Data.ByteString.Lazy (ByteString(..), pack , unpack)+import qualified Data.ByteString.Lazy as L+import Data.ByteString.Lazy.Internal (ByteString(..))++import qualified Data.ByteString            as P+import qualified Data.ByteString.Internal   as P+import qualified Data.ByteString.Unsafe     as P+import qualified Data.ByteString.Char8      as C+import qualified Data.ByteString.Short      as Short++import qualified Data.ByteString.Lazy.Char8 as LC+import qualified Data.ByteString.Lazy.Char8 as D++import qualified Data.ByteString.Lazy.Internal as L+import Prelude hiding (abs)++import QuickCheckUtils+import Test.Tasty+import Test.Tasty.QuickCheck++import qualified Properties.ByteString as PropBS+import qualified Properties.ByteStringChar8 as PropBS8+import qualified Properties.ByteStringLazy as PropBL+import qualified Properties.ByteStringLazyChar8 as PropBL8++prop_unsafeIndexBB xs =+  not (null xs) ==>+    forAll indices $ \i -> (xs !! i) == P.pack xs `P.unsafeIndex` i+  where indices = choose (0, length xs -1)++prop_bijectionBB  (Char8 c) = (P.w2c . P.c2w) c == id c+prop_bijectionBB'        w  = (P.c2w . P.w2c) w == id w++prop_head2BB xs    = (not (null xs)) ==> head xs   == (P.unsafeHead . P.pack) xs++prop_tail1BB xs    = (not (null xs)) ==> tail xs    == (P.unpack . P.unsafeTail. P.pack) xs++prop_last1BB xs    = (not (null xs)) ==> last xs    == (P.unsafeLast . P.pack) xs++prop_init1BB xs     =+    (not (null xs)) ==>+    init xs    == (P.unpack . P.unsafeInit . P.pack) xs++prop_lines_lazy1 =+    head (LC.lines (LC.append (LC.pack "a\nb\n") undefined)) == LC.pack "a"+prop_lines_lazy2 =+    head (tail (LC.lines (LC.append (LC.pack "a\nb\n") undefined))) == LC.pack "b"++prop_strip x = C.strip x == (C.dropSpace . C.reverse . C.dropSpace . C.reverse) x++-- Ensure that readInt and readInteger over lazy ByteStrings are not+-- excessively strict.+prop_readIntSafe         = (fst . fromJust . D.readInt) (Chunk (C.pack "1z") Empty)         == 1+prop_readIntUnsafe       = (fst . fromJust . D.readInt) (Chunk (C.pack "2z") undefined)     == 2+prop_readIntegerSafe     = (fst . fromJust . D.readInteger) (Chunk (C.pack "1z") Empty)     == 1+prop_readIntegerUnsafe   = (fst . fromJust . D.readInteger) (Chunk (C.pack "2z") undefined) == 2++------------------------------------------------------------------------++prop_packUptoLenBytes cs =+    forAll (choose (0, length cs + 1)) $ \n ->+      let (bs, cs') = P.packUptoLenBytes n cs+       in P.length bs == min n (length cs)+       && take n cs == P.unpack bs+       && P.pack (take n cs) == bs+       && drop n cs == cs'++prop_packUptoLenChars (String8 cs) =+    forAll (choose (0, length cs + 1)) $ \n ->+      let (bs, cs') = P.packUptoLenChars n cs+       in P.length bs == min n (length cs)+       && take n cs == C.unpack bs+       && C.pack (take n cs) == bs+       && drop n cs == cs'++prop_unpackAppendBytesLazy cs' =+    forAll (sized $ \n -> resize (n * 10) arbitrary) $ \cs ->+    forAll (choose (0, 2)) $ \n ->+      P.unpackAppendBytesLazy (P.drop n $ P.pack cs) cs' == drop n cs ++ cs'+prop_unpackAppendCharsLazy (String8 cs') =+    forAll (sized $ \n -> resize (n * 10) arbitrary) $ \(String8 cs) ->+    forAll (choose (0, 2)) $ \n ->+      P.unpackAppendCharsLazy (P.drop n $ C.pack cs) cs' == drop n cs ++ cs'++prop_unpackAppendBytesStrict cs cs' =+    forAll (choose (0, length cs)) $ \n ->+      P.unpackAppendBytesStrict (P.drop n $ P.pack cs) cs' == drop n cs ++ cs'++prop_unpackAppendCharsStrict (String8 cs) (String8 cs') =+    forAll (choose (0, length cs)) $ \n ->+      P.unpackAppendCharsStrict (P.drop n $ C.pack cs) cs' == drop n cs ++ cs'++------------------------------------------------------------------------+-- Unsafe functions++-- Test unsafePackAddress+prop_unsafePackAddress (CByteString x) = ioProperty $ do+        let (p,_,_) = P.toForeignPtr (x `P.snoc` 0)+        y <- withForeignPtr p $ \(Ptr addr) ->+            P.unsafePackAddress addr+        return (y == x)++-- Test unsafePackAddressLen+prop_unsafePackAddressLen x = ioProperty $ do+        let i = P.length x+            (p,_,_) = P.toForeignPtr (x `P.snoc` 0)+        y <- withForeignPtr p $ \(Ptr addr) ->+            P.unsafePackAddressLen i addr+        return (y == x)++prop_unsafeUseAsCString x = ioProperty $ do+        let n = P.length x+        y <- P.unsafeUseAsCString x $ \cstr ->+                    sequence [ do a <- peekElemOff cstr i+                                  let b = x `P.index` i+                                  return (a == fromIntegral b)+                             | i <- [0.. n-1]     ]+        return (and y)++prop_unsafeUseAsCStringLen x = ioProperty $ do+        let n = P.length x+        y <- P.unsafeUseAsCStringLen x $ \(cstr,_) ->+                    sequence [ do a <- peekElemOff cstr i+                                  let b = x `P.index` i+                                  return (a == fromIntegral b)+                             | i <- [0.. n-1]     ]+        return (and y)++prop_useAsCString x = ioProperty $ do+        let n = P.length x+        y <- P.useAsCString x $ \cstr ->+                    sequence [ do a <- peekElemOff cstr i+                                  let b = x `P.index` i+                                  return (a == fromIntegral b)+                             | i <- [0.. n-1]     ]+        return (and y)++prop_packCString (CByteString x) = ioProperty $ do+        y <- P.useAsCString x $ P.unsafePackCString+        return (y == x)++prop_packCString_safe (CByteString x) = ioProperty $ do+        y <- P.useAsCString x $ P.packCString+        return (y == x)++prop_packCStringLen x = ioProperty $ do+        y <- P.useAsCStringLen x $ P.unsafePackCStringLen+        return (y == x && P.length y == P.length x)++prop_packCStringLen_safe x = ioProperty $ do+        y <- P.useAsCStringLen x $ P.packCStringLen+        return (y == x && P.length y == P.length x)++prop_packMallocCString (CByteString x) = ioProperty $ do++         let (fp,_,_) = P.toForeignPtr x+         ptr <- mallocArray0 (P.length x) :: IO (Ptr Word8)+         forM_ [0 .. P.length x] $ \n -> pokeElemOff ptr n 0+         withForeignPtr fp $ \qtr -> copyArray ptr qtr (P.length x)+         y   <- P.unsafePackMallocCString (castPtr ptr)++         let !z = y == x+         free ptr `seq` return z++prop_unsafeFinalize    x =+    P.length x > 0 ==>+      ioProperty $ do+        x <- P.unsafeFinalize x+        return (x == ())++prop_packCStringFinaliser x = ioProperty $ do+        y <- P.useAsCString x $ \cstr -> P.unsafePackCStringFinalizer (castPtr cstr) (P.length x) (return ())+        return (y == x)++prop_fromForeignPtr x = (let (a,b,c) = (P.toForeignPtr x)+                                in P.fromForeignPtr a b c) == x++------------------------------------------------------------------------+-- IO++prop_read_write_file_P x = ioProperty $ do+    (fn, h) <- openTempFile "." "prop-compiled.tmp"+    hClose h+    P.writeFile fn x+    y <- P.readFile fn+    removeFile fn+    return (x == y)++prop_read_write_file_C x = ioProperty $ do+    (fn, h) <- openTempFile "." "prop-compiled.tmp"+    hClose h+    C.writeFile fn x+    y <- C.readFile fn+    removeFile fn+    return (x == y)++prop_read_write_file_L x = ioProperty $ do+    (fn, h) <- openTempFile "." "prop-compiled.tmp"+    hClose h+    L.writeFile fn x+    y <- L.readFile fn+    L.length y `seq` removeFile fn+    return (x == y)++prop_read_write_file_D x = ioProperty $ do+    (fn, h) <- openTempFile "." "prop-compiled.tmp"+    hClose h+    D.writeFile fn x+    y <- D.readFile fn+    D.length y `seq` removeFile fn+    return (x == y)++------------------------------------------------------------------------++prop_append_file_P x y = ioProperty $ do+    (fn, h) <- openTempFile "." "prop-compiled.tmp"+    hClose h+    P.writeFile fn x+    P.appendFile fn y+    z <- P.readFile fn+    removeFile fn+    return (z == x `P.append` y)++prop_append_file_C x y = ioProperty $ do+    (fn, h) <- openTempFile "." "prop-compiled.tmp"+    hClose h+    C.writeFile fn x+    C.appendFile fn y+    z <- C.readFile fn+    removeFile fn+    return (z == x `C.append` y)++prop_append_file_L x y = ioProperty $ do+    (fn, h) <- openTempFile "." "prop-compiled.tmp"+    hClose h+    L.writeFile fn x+    L.appendFile fn y+    z <- L.readFile fn+    L.length y `seq` removeFile fn+    return (z == x `L.append` y)++prop_append_file_D x y = ioProperty $ do+    (fn, h) <- openTempFile "." "prop-compiled.tmp"+    hClose h+    D.writeFile fn x+    D.appendFile fn y+    z <- D.readFile fn+    D.length y `seq` removeFile fn+    return (z == x `D.append` y)++prop_packAddress = C.pack "this is a test"+            ==+                   C.pack "this is a test"++prop_isSpaceWord8 w = isSpace c == P.isSpaceChar8 c+   where c = chr (fromIntegral (w :: Word8))+++------------------------------------------------------------------------+-- ByteString.Short+--++prop_short_pack_unpack xs =+    (Short.unpack . Short.pack) xs == xs+prop_short_toShort_fromShort bs =+    (Short.fromShort . Short.toShort) bs == bs++prop_short_toShort_unpack bs =+    (Short.unpack . Short.toShort) bs == P.unpack bs+prop_short_pack_fromShort xs =+    (Short.fromShort . Short.pack) xs == P.pack xs++prop_short_empty =+    Short.empty == Short.toShort P.empty+ && Short.empty == Short.pack []+ && Short.null (Short.toShort P.empty)+ && Short.null (Short.pack [])+ && Short.null Short.empty++prop_short_null_toShort bs =+    P.null bs == Short.null (Short.toShort bs)+prop_short_null_pack xs =+    null xs == Short.null (Short.pack xs)++prop_short_length_toShort bs =+    P.length bs == Short.length (Short.toShort bs)+prop_short_length_pack xs =+    length xs == Short.length (Short.pack xs)++prop_short_index_pack xs =+    all (\i -> Short.pack xs `Short.index` i == xs !! i)+        [0 .. length xs - 1]+prop_short_index_toShort bs =+    all (\i -> Short.toShort bs `Short.index` i == bs `P.index` i)+        [0 .. P.length bs - 1]++prop_short_eq xs ys =+    (xs == ys) == (Short.pack xs == Short.pack ys)+prop_short_ord xs ys =+    (xs `compare` ys) == (Short.pack xs `compare` Short.pack ys)++prop_short_mappend_empty_empty =+    Short.empty `mappend` Short.empty  == Short.empty+prop_short_mappend_empty xs =+    Short.empty `mappend` Short.pack xs == Short.pack xs+ && Short.pack xs `mappend` Short.empty == Short.pack xs+prop_short_mappend xs ys =+    (xs `mappend` ys) == Short.unpack (Short.pack xs `mappend` Short.pack ys)+prop_short_mconcat xss =+    mconcat xss == Short.unpack (mconcat (map Short.pack xss))++prop_short_fromString s =+    fromString s == Short.fromShort (fromString s)++prop_short_show xs =+    show (Short.pack xs) == show (map P.w2c xs)+prop_short_show' xs =+    show (Short.pack xs) == show (P.pack xs)++prop_short_read xs =+    read (show (Short.pack xs)) == Short.pack xs++prop_short_pinned :: NonNegative Int -> Property+prop_short_pinned (NonNegative (I# len#)) = runST $ ST $ \s ->+  case newPinnedByteArray# len# s of+    (# s', mba# #) -> case unsafeFreezeByteArray# mba# s' of+      (# s'', ba# #) -> let sbs = Short.SBS ba# in+        (# s'', sbs === Short.toShort (Short.fromShort sbs) #)++short_tests =+    [ testProperty "pack/unpack"              prop_short_pack_unpack+    , testProperty "toShort/fromShort"        prop_short_toShort_fromShort+    , testProperty "toShort/unpack"           prop_short_toShort_unpack+    , testProperty "pack/fromShort"           prop_short_pack_fromShort+    , testProperty "empty"                    prop_short_empty+    , testProperty "null/toShort"             prop_short_null_toShort+    , testProperty "null/pack"                prop_short_null_pack+    , testProperty "length/toShort"           prop_short_length_toShort+    , testProperty "length/pack"              prop_short_length_pack+    , testProperty "index/pack"               prop_short_index_pack+    , testProperty "index/toShort"            prop_short_index_toShort+    , testProperty "Eq"                       prop_short_eq+    , testProperty "Ord"                      prop_short_ord+    , testProperty "mappend/empty/empty"      prop_short_mappend_empty_empty+    , testProperty "mappend/empty"            prop_short_mappend_empty+    , testProperty "mappend"                  prop_short_mappend+    , testProperty "mconcat"                  prop_short_mconcat+    , testProperty "fromString"               prop_short_fromString+    , testProperty "show"                     prop_short_show+    , testProperty "show'"                    prop_short_show'+    , testProperty "read"                     prop_short_read+    , testProperty "pinned"                   prop_short_pinned+    ]++------------------------------------------------------------------------+-- Strictness checks.++explosiveTail :: L.ByteString -> L.ByteString+explosiveTail = (`L.append` error "Tail of this byte string is undefined!")++------------------------------------------------------------------------+-- The entry point++testSuite :: TestTree+testSuite = testGroup "Properties"+  [ testGroup "StrictWord8" PropBS.tests+  , testGroup "StrictChar8" PropBS8.tests+  , testGroup "LazyWord8"   PropBL.tests+  , testGroup "LazyChar8"   PropBL8.tests+  , testGroup "Misc"        misc_tests+  , testGroup "IO"          io_tests+  , testGroup "Short"       short_tests+  , testGroup "Strictness"  strictness_checks+  ]++io_tests =+    [ testProperty "readFile.writeFile" prop_read_write_file_P+    , testProperty "readFile.writeFile" prop_read_write_file_C+    , testProperty "readFile.writeFile" prop_read_write_file_L+    , testProperty "readFile.writeFile" prop_read_write_file_D++    , testProperty "appendFile        " prop_append_file_P+    , testProperty "appendFile        " prop_append_file_C+    , testProperty "appendFile        " prop_append_file_L+    , testProperty "appendFile        " prop_append_file_D++    , testProperty "packAddress       " prop_packAddress+    ]++misc_tests =+    [ testProperty "packUptoLenBytes"       prop_packUptoLenBytes+    , testProperty "packUptoLenChars"       prop_packUptoLenChars+    , testProperty "unpackAppendBytesLazy"  prop_unpackAppendBytesLazy+    , testProperty "unpackAppendCharsLazy"  prop_unpackAppendCharsLazy+    , testProperty "unpackAppendBytesStrict"prop_unpackAppendBytesStrict+    , testProperty "unpackAppendCharsStrict"prop_unpackAppendCharsStrict++    , testProperty "unsafe pack address"    prop_unsafePackAddress+    , testProperty "unsafe pack address len"prop_unsafePackAddressLen+    , testProperty "unsafeUseAsCString"     prop_unsafeUseAsCString+    , testProperty "unsafeUseAsCStringLen"  prop_unsafeUseAsCStringLen+    , testProperty "useAsCString"           prop_useAsCString+    , testProperty "packCString"            prop_packCString+    , testProperty "packCString safe"       prop_packCString_safe+    , testProperty "packCStringLen"         prop_packCStringLen+    , testProperty "packCStringLen safe"    prop_packCStringLen_safe+    , testProperty "packCStringFinaliser"   prop_packCStringFinaliser+    , testProperty "packMallocString"       prop_packMallocCString+    , testProperty "unsafeFinalise"         prop_unsafeFinalize+    , testProperty "fromForeignPtr"         prop_fromForeignPtr++    , testProperty "w2c . c2w"      prop_bijectionBB+    , testProperty "c2w . w2c"      prop_bijectionBB'++    , testProperty "unsafeHead"     prop_head2BB+    , testProperty "unsafeTail"     prop_tail1BB+    , testProperty "unsafeLast"     prop_last1BB+    , testProperty "unsafeInit"     prop_init1BB+    , testProperty "unsafeIndex"    prop_unsafeIndexBB++    , testProperty "lines_lazy1"    prop_lines_lazy1+    , testProperty "lines_lazy2"    prop_lines_lazy2+    , testProperty "strip"          prop_strip+    , testProperty "isSpace"        prop_isSpaceWord8++    , testProperty "readIntSafe"       prop_readIntSafe+    , testProperty "readIntUnsafe"     prop_readIntUnsafe+    , testProperty "readIntegerSafe"   prop_readIntegerSafe+    , testProperty "readIntegerUnsafe" prop_readIntegerUnsafe+    ]++strictness_checks =+  [ testGroup "Lazy Word8"+    [ testProperty "foldr is lazy" $ \ xs ->+        List.genericTake (L.length xs) (L.foldr (:) [ ] (explosiveTail xs)) === L.unpack xs+    , testProperty "foldr' is strict" $ expectFailure $ \ xs ys ->+        List.genericTake (L.length xs) (L.foldr' (:) [ ] (explosiveTail (xs <> ys))) === L.unpack xs+    , testProperty "foldr1 is lazy" $ \ xs -> L.length xs > 0 ==>+        L.foldr1 const (explosiveTail (xs <> L.singleton 1)) === L.head xs+    , testProperty "foldr1' is strict" $ expectFailure $ \ xs ys -> L.length xs > 0 ==>+        L.foldr1' const (explosiveTail (xs <> L.singleton 1 <> ys)) === L.head xs+    , testProperty "scanl is lazy" $ \ xs ->+        L.take (L.length xs + 1) (L.scanl (+) 0 (explosiveTail (xs <> L.singleton 1))) === (L.pack . fmap (L.foldr (+) 0) . L.inits) xs+    , testProperty "scanl1 is lazy" $ \ xs -> L.length xs > 0 ==>+        L.take (L.length xs) (L.scanl1 (+) (explosiveTail (xs <> L.singleton 1))) === (L.pack . fmap (L.foldr1 (+)) . tail . L.inits) xs+    ]+  , testGroup "Lazy Char"+    [ testProperty "foldr is lazy" $ \ xs ->+        List.genericTake (D.length xs) (D.foldr (:) [ ] (explosiveTail xs)) === D.unpack xs+    , testProperty "foldr' is strict" $ expectFailure $ \ xs ys ->+        List.genericTake (D.length xs) (D.foldr' (:) [ ] (explosiveTail (xs <> ys))) === D.unpack xs+    , testProperty "foldr1 is lazy" $ \ xs -> D.length xs > 0 ==>+        D.foldr1 const (explosiveTail (xs <> D.singleton 'x')) === D.head xs+    , testProperty "foldr1' is strict" $ expectFailure $ \ xs ys -> D.length xs > 0 ==>+        D.foldr1' const (explosiveTail (xs <> D.singleton 'x' <> ys)) === D.head xs+    , testProperty "scanl is lazy" $ \ xs -> let char1 +. char2 = toEnum (fromEnum char1 + fromEnum char2) in+        D.take (D.length xs + 1) (D.scanl (+.) '\NUL' (explosiveTail (xs <> D.singleton '\SOH'))) === (D.pack . fmap (D.foldr (+.) '\NUL') . D.inits) xs+    , testProperty "scanl1 is lazy" $ \ xs -> D.length xs > 0 ==> let char1 +. char2 = toEnum (fromEnum char1 + fromEnum char2) in+        D.take (D.length xs) (D.scanl1 (+.) (explosiveTail (xs <> D.singleton '\SOH'))) === (D.pack . fmap (D.foldr1 (+.)) . tail . D.inits) xs+    ]+  ]  removeFile :: String -> IO () removeFile fn = void $ withCString fn c_unlink
+ tests/Properties/ByteString.hs view
@@ -0,0 +1,622 @@+-- |+-- Module      : Properties.ByteString+-- Copyright   : (c) Andrew Lelechenko 2021+-- License     : BSD-style++{-# LANGUAGE CPP #-}+{-# LANGUAGE ViewPatterns #-}++-- We are happy to sacrifice optimizations in exchange for faster compilation,+-- but need to test rewrite rules. As one can check using -ddump-rule-firings,+-- rewrite rules do not fire in -O0 mode, so we use -O1, but disable almost all+-- optimizations. It roughly halves compilation time.+{-# OPTIONS_GHC -O1 -fenable-rewrite-rules+  -fmax-simplifier-iterations=1 -fsimplifier-phases=0+  -fno-call-arity -fno-case-merge -fno-cmm-elim-common-blocks -fno-cmm-sink+  -fno-cpr-anal -fno-cse -fno-do-eta-reduction -fno-float-in -fno-full-laziness+  -fno-loopification -fno-specialise -fno-strictness #-}++-- BYTESTRING_CHAR8 and BYTESTRING_LAZY are defined in+-- Properties.ByteString{Char8,Lazy,LazyChar8}, which include this file.+#ifndef BYTESTRING_CHAR8++#ifndef BYTESTRING_LAZY+module Properties.ByteString (tests) where+import qualified Data.ByteString as B+import GHC.IO.Encoding+#else+module Properties.ByteStringLazy (tests) where+import qualified Data.ByteString.Lazy as B+import qualified Data.ByteString.Lazy.Internal as B (invariant)+#endif++import Data.Word++#else++#ifndef BYTESTRING_LAZY+module Properties.ByteStringChar8 (tests) where+import qualified Data.ByteString.Char8 as B+#else+module Properties.ByteStringLazyChar8 (tests) where+import qualified Data.ByteString.Lazy.Char8 as B+import qualified Data.ByteString.Lazy.Internal as B (invariant)+#endif++import Text.Read++#endif++import Control.Arrow+import Data.Char+import Data.Foldable+import qualified Data.List as List+import Data.Semigroup+import Data.String+import Data.Tuple+import Test.Tasty+import Test.Tasty.QuickCheck+import QuickCheckUtils++#ifndef BYTESTRING_CHAR8+toElem :: Word8 -> Word8+toElem = id+#else+toElem :: Char8 -> Char+toElem (Char8 c) = c+#endif++tests :: [TestTree]+tests =+  [ testProperty "pack . unpack" $+    \x -> x === B.pack (B.unpack x)+  , testProperty "unpack . pack" $+    \(map toElem -> xs) -> xs === B.unpack (B.pack xs)+  , testProperty "read . show" $+    \x -> (x :: B.ByteString) === read (show x)+  , testProperty "fromStrict . toStrict" $+    \x -> B.fromStrict (B.toStrict x) === x+  , testProperty "toStrict . fromStrict" $+    \x -> B.toStrict (B.fromStrict x) === x+#ifndef BYTESTRING_LAZY+#ifndef BYTESTRING_CHAR8+  , testProperty "toFilePath >>= fromFilePath" $+    \x -> ioProperty $ do+      r <- B.toFilePath x >>= B.fromFilePath+      pure (r === x)+  , testProperty "fromFilePath >>= toFilePath" $ ioProperty $ do+    let prop x = ioProperty $ do+          r <- B.fromFilePath x >>= B.toFilePath+          pure (r === x)+    -- Normally getFileSystemEncoding returns a Unicode encoding,+    -- but if it is ASCII, we should not generate Unicode filenames.+    enc <- getFileSystemEncoding+    pure $ case textEncodingName enc of+      "ASCII" -> property (prop . getASCIIString)+      _       -> property prop+#endif+#endif++  , testProperty "==" $+    \x y -> (x == y) === (B.unpack x == B.unpack y)+  , testProperty "== refl" $+    \x -> (x :: B.ByteString) == x+  , testProperty "== symm" $+    \x y -> ((x :: B.ByteString) == y) === (y == x)+  , testProperty "== pack unpack" $+    \x -> x == B.pack (B.unpack x)+  , testProperty "== copy" $+    \x -> x == B.copy x++  , testProperty "compare" $+    \x y -> compare x y === compare (B.unpack x) (B.unpack y)+  , testProperty "compare EQ" $+    \x -> compare (x :: B.ByteString) x == EQ+  , testProperty "compare GT" $+    \x (toElem -> c) -> compare (B.snoc x c) x == GT+  , testProperty "compare LT" $+    \x (toElem -> c) -> compare x (B.snoc x c) == LT+  , testProperty "compare GT empty" $+    \x -> not (B.null x) ==> compare x B.empty == GT+  , testProperty "compare LT empty" $+    \x -> not (B.null x) ==> compare B.empty x == LT+  , testProperty "compare GT concat" $+    \x y -> not (B.null y) ==> compare (x <> y) x == GT+  , testProperty "compare char" $+    \(toElem -> c) (toElem -> d) -> compare c d == compare (B.singleton c) (B.singleton d)+#ifndef BYTESTRING_CHAR8+  , testProperty "compare unsigned" $ once $+    compare (B.singleton 255) (B.singleton 127) == GT+#endif++  , testProperty "null" $+    \x -> B.null x === null (B.unpack x)+  , testProperty "empty 0" $ once $+    B.length B.empty === 0+  , testProperty "empty []" $ once $+    B.unpack B.empty === []+  , testProperty "mempty 0" $ once $+    B.length mempty === 0+  , testProperty "mempty []" $ once $+    B.unpack mempty === []++  , testProperty "concat" $+    \(Sqrt xs) -> B.unpack (B.concat xs) === concat (map B.unpack xs)+  , testProperty "concat [x,x]" $+    \x -> B.unpack (B.concat [x, x]) === concat [B.unpack x, B.unpack x]+  , testProperty "concat [x,[]]" $+    \x -> B.unpack (B.concat [x, B.empty]) === concat [B.unpack x, []]+  , testProperty "mconcat" $+    \(Sqrt xs) -> B.unpack (mconcat xs) === mconcat (map B.unpack xs)+  , testProperty "mconcat [x,x]" $+    \x -> B.unpack (mconcat [x, x]) === mconcat [B.unpack x, B.unpack x]+  , testProperty "mconcat [x,[]]" $+    \x -> B.unpack (mconcat [x, B.empty]) === mconcat [B.unpack x, []]++  , testProperty "null" $+    \x -> B.null x === null (B.unpack x)+  , testProperty "reverse" $+    \x -> B.unpack (B.reverse x) === reverse (B.unpack x)+  , testProperty "transpose" $+    \xs -> map B.unpack (B.transpose xs) === List.transpose (map B.unpack xs)+  , testProperty "group" $+    \x -> map B.unpack (B.group x) === List.group (B.unpack x)+  , testProperty "groupBy" $+    \f x -> map B.unpack (B.groupBy f x) === List.groupBy f (B.unpack x)+  , testProperty "groupBy ==" $+    \x -> map B.unpack (B.groupBy (==) x) === List.groupBy (==) (B.unpack x)+  , testProperty "groupBy /=" $+    \x -> map B.unpack (B.groupBy (/=) x) === List.groupBy (/=) (B.unpack x)+  , testProperty "inits" $+    \x -> map B.unpack (B.inits x) === List.inits (B.unpack x)+  , testProperty "tails" $+    \x -> map B.unpack (B.tails x) === List.tails (B.unpack x)+  , testProperty "all" $+    \f x -> B.all f x === all f (B.unpack x)+  , testProperty "all ==" $+    \(toElem -> c) x -> B.all (== c) x === all (== c) (B.unpack x)+  , testProperty "any" $+    \f x -> B.any f x === any f (B.unpack x)+  , testProperty "any ==" $+    \(toElem -> c) x -> B.any (== c) x === any (== c) (B.unpack x)+  , testProperty "append" $+    \x y -> B.unpack (B.append x y) === B.unpack x ++ B.unpack y+  , testProperty "mappend" $+    \x y -> B.unpack (mappend x y) === B.unpack x `mappend` B.unpack y+  , testProperty "<>" $+    \x y -> B.unpack (x <> y) === B.unpack x <> B.unpack y+  , testProperty "stimes" $+    \(Sqrt (NonNegative n)) (Sqrt x) -> stimes (n :: Int) (x :: B.ByteString) === mtimesDefault n x++  , testProperty "break" $+    \f x -> (B.unpack *** B.unpack) (B.break f x) === break f (B.unpack x)+  , testProperty "break ==" $+    \(toElem -> c) x -> (B.unpack *** B.unpack) (B.break (== c) x) === break (== c) (B.unpack x)+  , testProperty "break /=" $+    \(toElem -> c) x -> (B.unpack *** B.unpack) (B.break (/= c) x) === break (/= c) (B.unpack x)+  , testProperty "break span" $+    \f x -> B.break f x === B.span (not . f) x+  , testProperty "breakEnd" $+    \f x -> B.breakEnd f x === swap ((B.reverse *** B.reverse) (B.break f (B.reverse x)))+  , testProperty "breakEnd" $+    \f x -> B.breakEnd f x === B.spanEnd (not . f) x++#ifndef BYTESTRING_LAZY+  , testProperty "break breakSubstring" $+    \(toElem -> c) x -> B.break (== c) x === B.breakSubstring (B.singleton c) x+  , testProperty "breakSubstring" $+    \x y -> not (B.null x) ==> B.null (snd (B.breakSubstring x y)) === not (B.isInfixOf x y)+  , testProperty "breakSubstring empty" $+    \x -> B.breakSubstring B.empty x === (B.empty, x)+#endif+#ifdef BYTESTRING_CHAR8+  , testProperty "break isSpace" $+    \x -> (B.unpack *** B.unpack) (B.break isSpace x) === break isSpace (B.unpack x)+#endif++  , testProperty "concatMap" $+    \f x -> B.unpack (B.concatMap f x) === concatMap (B.unpack . f) (B.unpack x)+  , testProperty "concatMap singleton" $+    \x -> B.unpack (B.concatMap B.singleton x) === concatMap (: []) (B.unpack x)++  , testProperty "singleton" $+    \(toElem -> c) -> B.unpack (B.singleton c) === [c]+  , testProperty "cons" $+    \(toElem -> c) x -> B.unpack (B.cons c x) === c : B.unpack x+  , testProperty "cons []" $+    \(toElem -> c) -> B.unpack (B.cons c B.empty) === [c]+  , testProperty "uncons" $+    \x -> fmap (second B.unpack) (B.uncons x) === List.uncons (B.unpack x)+  , testProperty "snoc" $+    \(toElem -> c) x -> B.unpack (B.snoc x c) === B.unpack x ++ [c]+  , testProperty "snoc []" $+    \(toElem -> c) -> B.unpack (B.snoc B.empty c) === [c]+  , testProperty "unsnoc" $+    \x -> fmap (first B.unpack) (B.unsnoc x) === unsnoc (B.unpack x)+#ifdef BYTESTRING_LAZY+  , testProperty "cons'" $+    \(toElem -> c) x -> B.unpack (B.cons' c x) === c : B.unpack x+#endif++  , testProperty "drop" $+    \n x -> B.unpack (B.drop n x) === List.genericDrop n (B.unpack x)+  , testProperty "drop 10" $+    \x -> let n = 10 in B.unpack (B.drop n x) === List.genericDrop n (B.unpack x)+  , testProperty "drop 2^31" $+    \x -> let n = 2^31 in B.unpack (B.drop n x) === List.genericDrop n (B.unpack x)+  , testProperty "dropWhile" $+    \f x -> B.unpack (B.dropWhile f x) === dropWhile f (B.unpack x)+  , testProperty "dropWhile ==" $+    \(toElem -> c) x -> B.unpack (B.dropWhile (== c) x) === dropWhile (== c) (B.unpack x)+  , testProperty "dropWhile /=" $+    \(toElem -> c) x -> B.unpack (B.dropWhile (/= c) x) === dropWhile (/= c) (B.unpack x)+#ifdef BYTESTRING_CHAR8+  , testProperty "dropWhile isSpace" $+    \x -> B.unpack (B.dropWhile isSpace x) === dropWhile isSpace (B.unpack x)+#endif++  , testProperty "take" $+    \n x -> B.unpack (B.take n x) === List.genericTake n (B.unpack x)+  , testProperty "take 10" $+    \x -> let n = 10 in B.unpack (B.take n x) === List.genericTake n (B.unpack x)+  , testProperty "take 2^31" $+    \x -> let n = 2^31 in B.unpack (B.take n x) === List.genericTake n (B.unpack x)+  , testProperty "takeWhile" $+    \f x -> B.unpack (B.takeWhile f x) === takeWhile f (B.unpack x)+  , testProperty "takeWhile ==" $+    \(toElem -> c) x -> B.unpack (B.takeWhile (== c) x) === takeWhile (== c) (B.unpack x)+  , testProperty "takeWhile /=" $+    \(toElem -> c) x -> B.unpack (B.takeWhile (/= c) x) === takeWhile (/= c) (B.unpack x)+#ifdef BYTESTRING_CHAR8+  , testProperty "takeWhile isSpace" $+    \x -> B.unpack (B.takeWhile isSpace x) === takeWhile isSpace (B.unpack x)+#endif++  , testProperty "dropEnd" $+    \n x -> B.dropEnd n x === B.take (B.length x - n) x+  , testProperty "dropWhileEnd" $+    \f x -> B.dropWhileEnd f x === B.reverse (B.dropWhile f (B.reverse x))+  , testProperty "takeEnd" $+    \n x -> B.takeEnd n x === B.drop (B.length x - n) x+  , testProperty "takeWhileEnd" $+    \f x -> B.takeWhileEnd f x === B.reverse (B.takeWhile f (B.reverse x))++#ifdef BYTESTRING_LAZY+  , testProperty "invariant" $+    \x -> B.invariant x+  , testProperty "fromChunks . toChunks" $+    \x -> B.fromChunks (B.toChunks x) === x+  , testProperty "toChunks . fromChunks" $+    \xs -> B.toChunks (B.fromChunks xs) === filter (/= mempty) xs+  , testProperty "append lazy" $+    \(toElem -> c) -> B.head (B.singleton c <> undefined) === c+  , testProperty "compareLength 1" $+    \x -> B.compareLength x (B.length x) === EQ+  , testProperty "compareLength 2" $+    \x (toElem -> c) -> B.compareLength (B.snoc x c) (B.length x) === GT+  , testProperty "compareLength 3" $+    \x -> B.compareLength x (B.length x + 1) === LT+  , testProperty "compareLength 4" $+    \x (toElem -> c) -> B.compareLength (B.snoc x c <> undefined) (B.length x) === GT+  , testProperty "compareLength 5" $+    \x n -> B.compareLength x n === compare (B.length x) n+  , testProperty "dropEnd lazy" $+    \(toElem -> c) -> B.take 1 (B.dropEnd 1 (B.singleton c <> B.singleton c <> B.singleton c <> undefined)) === B.singleton c+  , testProperty "dropWhileEnd lazy" $+    \(toElem -> c) -> B.take 1 (B.dropWhileEnd (const False) (B.singleton c <> undefined)) === B.singleton c+  , testProperty "breakEnd lazy" $+    \(toElem -> c) -> B.take 1 (fst $ B.breakEnd (const True) (B.singleton c <> undefined)) === B.singleton c+  , testProperty "spanEnd lazy" $+    \(toElem -> c) -> B.take 1 (fst $ B.spanEnd (const False) (B.singleton c <> undefined)) === B.singleton c+#endif++  , testProperty "length" $+    \x -> B.length x === fromIntegral (length (B.unpack x))+  , testProperty "count" $+    \(toElem -> c) x -> B.count c x === fromIntegral (length (List.elemIndices c (B.unpack x)))+  -- for long strings, the multiplier is non-round (and not power of 2)+  -- to ensure non-trivial prefix or suffix of the string is handled outside any possible SIMD-based loop,+  -- which typically handles chunks of 16 or 32 or 64 etc bytes.+  , testProperty "count (long strings)" $+    \(toElem -> c) x (Positive n) -> B.count c x * fromIntegral n === B.count c (B.concat $ replicate n x)+  , testProperty "filter" $+    \f x -> B.unpack (B.filter f x) === filter f (B.unpack x)+  , testProperty "filter compose" $+    \f g x -> B.filter f (B.filter g x) === B.filter (\c -> f c && g c) x+  , testProperty "filter ==" $+    \(toElem -> c) x -> B.unpack (B.filter (== c) x) === filter (== c) (B.unpack x)+  , testProperty "filter /=" $+    \(toElem -> c) x -> B.unpack (B.filter (/= c) x) === filter (/= c) (B.unpack x)+  , testProperty "partition" $+    \f x -> (B.unpack *** B.unpack) (B.partition f x) === List.partition f (B.unpack x)++  , testProperty "find" $+    \f x -> B.find f x === find f (B.unpack x)+  , testProperty "findIndex" $+    \f x -> B.findIndex f x === fmap fromIntegral (List.findIndex f (B.unpack x))+  , testProperty "findIndexEnd" $+    \f x -> B.findIndexEnd f x === fmap fromIntegral (findIndexEnd f (B.unpack x))+  , testProperty "findIndices" $+    \f x -> B.findIndices f x === fmap fromIntegral (List.findIndices f (B.unpack x))+  , testProperty "findIndices ==" $+    \(toElem -> c) x -> B.findIndices (== c) x === fmap fromIntegral (List.findIndices (== c) (B.unpack x))++  , testProperty "elem" $+    \(toElem -> c) x -> B.elem c x === elem c (B.unpack x)+  , testProperty "notElem" $+    \(toElem -> c) x -> B.notElem c x === notElem c (B.unpack x)+  , testProperty "elemIndex" $+    \(toElem -> c) x -> B.elemIndex c x === fmap fromIntegral (List.elemIndex c (B.unpack x))+  , testProperty "elemIndexEnd" $+    \(toElem -> c) x -> B.elemIndexEnd c x === fmap fromIntegral (elemIndexEnd c (B.unpack x))+  , testProperty "elemIndices" $+    \(toElem -> c) x -> B.elemIndices c x === fmap fromIntegral (List.elemIndices c (B.unpack x))++  , testProperty "isPrefixOf" $+    \x y -> B.isPrefixOf x y === List.isPrefixOf (B.unpack x) (B.unpack y)+  , testProperty "stripPrefix" $+    \x y -> fmap B.unpack (B.stripPrefix x y) === List.stripPrefix (B.unpack x) (B.unpack y)+  , testProperty "isSuffixOf" $+    \x y -> B.isSuffixOf x y === List.isSuffixOf (B.unpack x) (B.unpack y)+  , testProperty "stripSuffix" $+    \x y -> fmap B.unpack (B.stripSuffix x y) === stripSuffix (B.unpack x) (B.unpack y)+#ifndef BYTESTRING_LAZY+  , testProperty "isInfixOf" $+    \x y -> B.isInfixOf x y === List.isInfixOf (B.unpack x) (B.unpack y)+#endif++  , testProperty "map" $+    \f x -> B.unpack (B.map (toElem . f) x) === map (toElem . f) (B.unpack x)+  , testProperty "map compose" $+    \f g x -> B.map (toElem . f) (B.map (toElem . g) x) === B.map (toElem . f . toElem . g) x+  , testProperty "replicate" $+    \n (toElem -> c) -> B.unpack (B.replicate (fromIntegral n) c) === replicate n c+  , testProperty "replicate 0" $+    \(toElem -> c) -> B.unpack (B.replicate 0 c) === replicate 0 c++  , testProperty "span" $+    \f x -> (B.unpack *** B.unpack) (B.span f x) === span f (B.unpack x)+  , testProperty "span ==" $+    \(toElem -> c) x -> (B.unpack *** B.unpack) (B.span (== c) x) === span (== c) (B.unpack x)+  , testProperty "span /=" $+    \(toElem -> c) x -> (B.unpack *** B.unpack) (B.span (/= c) x) === span (/= c) (B.unpack x)+  , testProperty "spanEnd" $+    \f x -> B.spanEnd f x === swap ((B.reverse *** B.reverse) (B.span f (B.reverse x)))+  , testProperty "split" $+    \(toElem -> c) x -> map B.unpack (B.split c x) === split c (B.unpack x)+  , testProperty "split empty" $+    \(toElem -> c) -> B.split c B.empty === []+  , testProperty "splitWith" $+    \f x -> map B.unpack (B.splitWith f x) === splitWith f (B.unpack x)+  , testProperty "splitWith split" $+    \(toElem -> c) x -> B.splitWith (== c) x === B.split c x+  , testProperty "splitWith empty" $+    \f -> B.splitWith f B.empty === []+  , testProperty "splitWith length" $+    \f x -> let splits = B.splitWith f x; l1 = fromIntegral (length splits); l2 = B.length (B.filter f x) in+      (l1 == l2 || l1 == l2 + 1) && sum (map B.length splits) + l2 == B.length x++  , testProperty "splitAt" $+    \n x -> (B.unpack *** B.unpack) (B.splitAt n x) === List.genericSplitAt n (B.unpack x)+  , testProperty "splitAt 10" $+    \x -> let n = 10 in (B.unpack *** B.unpack) (B.splitAt n x) === List.genericSplitAt n (B.unpack x)+  , testProperty "splitAt (2^31)" $+    \x -> let n = 2^31 in (B.unpack *** B.unpack) (B.splitAt n x) === List.genericSplitAt n (B.unpack x)++  , testProperty "head" $+    \x -> not (B.null x) ==> B.head x === head (B.unpack x)+  , testProperty "last" $+    \x -> not (B.null x) ==> B.last x === last (B.unpack x)+  , testProperty "tail" $+    \x -> not (B.null x) ==> B.unpack (B.tail x) === tail (B.unpack x)+  , testProperty "tail length" $+    \x -> not (B.null x) ==> B.length x === 1 + B.length (B.tail x)+  , testProperty "init" $+    \x -> not (B.null x) ==> B.unpack (B.init x) === init (B.unpack x)+  , testProperty "init length" $+    \x -> not (B.null x) ==> B.length x === 1 + B.length (B.init x)+  , testProperty "maximum" $+    \x -> not (B.null x) ==> B.maximum x === maximum (B.unpack x)+  , testProperty "minimum" $+    \x -> not (B.null x) ==> B.minimum x === minimum (B.unpack x)++  , testProperty "foldl" $+    \f (toElem -> c) x -> B.foldl ((toElem .) . f) c x === foldl ((toElem .) . f) c (B.unpack x)+  , testProperty "foldl'" $+    \f (toElem -> c) x -> B.foldl' ((toElem .) . f) c x === foldl' ((toElem .) . f) c (B.unpack x)+  , testProperty "foldr" $+    \f (toElem -> c) x -> B.foldr ((toElem .) . f) c x === foldr ((toElem .) . f) c (B.unpack x)+  , testProperty "foldr'" $+    \f (toElem -> c) x -> B.foldr' ((toElem .) . f) c x === foldr' ((toElem .) . f) c (B.unpack x)++  , testProperty "foldl cons" $+    \x -> B.foldl (flip B.cons) B.empty x === B.reverse x+  , testProperty "foldr cons" $+    \x -> B.foldr B.cons B.empty x === x+  , testProperty "foldl special" $+    \(Sqrt x) (toElem -> c) -> B.unpack (B.foldl (\acc t -> if t == c then acc else B.cons t acc) B.empty x) ===+      foldl (\acc t -> if t == c then acc else t : acc) [] (B.unpack x)+  , testProperty "foldr special" $+    \(Sqrt x) (toElem -> c) -> B.unpack (B.foldr (\t acc -> if t == c then acc else B.cons t acc) B.empty x) ===+      foldr (\t acc -> if t == c then acc else t : acc) [] (B.unpack x)++  , testProperty "foldl1" $+    \f x -> not (B.null x) ==> B.foldl1 ((toElem .) . f) x === foldl1 ((toElem .) . f) (B.unpack x)+  , testProperty "foldl1'" $+    \f x -> not (B.null x) ==> B.foldl1' ((toElem .) . f) x === List.foldl1' ((toElem .) . f) (B.unpack x)+  , testProperty "foldr1" $+    \f x -> not (B.null x) ==> B.foldr1 ((toElem .) . f) x === foldr1 ((toElem .) . f) (B.unpack x)+  , testProperty "foldr1'" $ -- there is not Data.List.foldr1'+    \f x -> not (B.null x) ==> B.foldr1' ((toElem .) . f) x === foldr1 ((toElem .) . f) (B.unpack x)++  , testProperty "foldl1 const" $+    \x -> not (B.null x) ==> B.foldl1 const x === B.head x+  , testProperty "foldl1 flip const" $+    \x -> not (B.null x) ==> B.foldl1 (flip const) x === B.last x+  , testProperty "foldr1 const" $+    \x -> not (B.null x) ==> B.foldr1 const x === B.head x+  , testProperty "foldr1 flip const" $+    \x -> not (B.null x) ==> B.foldr1 (flip const) x === B.last x+  , testProperty "foldl1 max" $+    \x -> not (B.null x) ==> B.foldl1 max x === B.foldl max minBound x+  , testProperty "foldr1 max" $+    \x -> not (B.null x) ==> B.foldr1 max x === B.foldr max minBound x++  , testProperty "scanl" $+    \f (toElem -> c) x -> B.unpack (B.scanl ((toElem .) . f) c x) === scanl ((toElem .) . f) c (B.unpack x)+  , testProperty "scanl foldl" $+    \f (toElem -> c) x -> not (B.null x) ==> B.last (B.scanl ((toElem .) . f) c x) === B.foldl ((toElem .) . f) c x++  , testProperty "scanr" $+    \f (toElem -> c) x -> B.unpack (B.scanr ((toElem .) . f) c x) === scanr ((toElem .) . f) c (B.unpack x)+  , testProperty "scanl1" $+    \f x -> B.unpack (B.scanl1 ((toElem .) . f) x) === scanl1 ((toElem .) . f) (B.unpack x)+  , testProperty "scanl1 empty" $+    \f -> B.scanl1 f B.empty === B.empty+  , testProperty "scanr1" $+    \f x -> B.unpack (B.scanr1 ((toElem .) . f) x) === scanr1 ((toElem .) . f) (B.unpack x)+  , testProperty "scanr1 empty" $+    \f -> B.scanr1 f B.empty === B.empty++#ifndef BYTESTRING_LAZY+  , testProperty "sort" $+    \x -> B.unpack (B.sort x) === List.sort (B.unpack x)+#endif++  , testProperty "intersperse" $+    \(toElem -> c) x -> B.unpack (B.intersperse c x) === List.intersperse c (B.unpack x)+  , testProperty "intercalate" $+    \(Sqrt x) (Sqrt ys) -> B.unpack (B.intercalate x ys) === List.intercalate (B.unpack x) (map B.unpack ys)+  , testProperty "intercalate 'c' [x,y]" $+    \(toElem -> c) x y -> B.unpack (B.intercalate (B.singleton c) [x, y]) === List.intercalate [c] [B.unpack x, B.unpack y]+  , testProperty "intercalate split" $+    \(toElem -> c) x -> B.intercalate (B.singleton c) (B.split c x) === x++  , testProperty "mapAccumL" $+    \f (toElem -> c) x -> second B.unpack (B.mapAccumL ((second toElem .) . f) c x) ===+      List.mapAccumL ((second toElem .) . f) c (B.unpack x)+  , testProperty "mapAccumR" $+    \f (toElem -> c) x -> second B.unpack (B.mapAccumR ((second toElem .) . f) c x) ===+      List.mapAccumR ((second toElem .) . f) c (B.unpack x)++  , testProperty "zip" $+    \x y -> B.zip x y === zip (B.unpack x) (B.unpack y)+  , testProperty "zipWith" $+    \f x y -> (B.zipWith f x y :: [Int]) === zipWith f (B.unpack x) (B.unpack y)+  , testProperty "packZipWith" $+    \f x y -> B.unpack (B.packZipWith ((toElem .) . f) x y) === zipWith ((toElem .) . f) (B.unpack x) (B.unpack y)+  , testProperty "unzip" $+    \(fmap (toElem *** toElem) -> xs) -> (B.unpack *** B.unpack) (B.unzip xs) === unzip xs++  , testProperty "index" $+    \(NonNegative n) x -> fromIntegral n < B.length x ==> B.index x (fromIntegral n) === B.unpack x !! n+  , testProperty "indexMaybe" $+    \(NonNegative n) x -> fromIntegral n < B.length x ==> B.indexMaybe x (fromIntegral n) === Just (B.unpack x !! n)+  , testProperty "indexMaybe Nothing" $+    \n x -> (n :: Int) < 0 || fromIntegral n >= B.length x ==> B.indexMaybe x (fromIntegral n) === Nothing+  , testProperty "!?" $+    \n x -> B.indexMaybe x (fromIntegral (n :: Int)) === x B.!? (fromIntegral n)++#ifdef BYTESTRING_CHAR8+  , testProperty "isString" $+    \x -> x === fromString (B.unpack x)+  , testProperty "readInt 1" $+    \x -> fmap (second B.unpack) (B.readInt x) === readInt (B.unpack x)+  , testProperty "readInt 2" $+    \n -> B.readInt (B.pack (show n)) === Just (n, B.empty)+  , testProperty "readInteger 1" $+    \x -> fmap (second B.unpack) (B.readInteger x) === readInteger (B.unpack x)+  , testProperty "readInteger 2" $+    \n -> B.readInteger (B.pack (show n)) === Just (n, B.empty)+  , testProperty "lines" $+    \x -> map B.unpack (B.lines x) === lines (B.unpack x)+  , testProperty "lines \\n" $ once $+    let x = B.pack "one\ntwo\n\n\nfive\n\nseven\n" in+    map B.unpack (B.lines x) === lines (B.unpack x)+  , testProperty "unlines" $+    \xs -> B.unpack (B.unlines xs) === unlines (map B.unpack xs)+  , testProperty "words" $+    \x -> map B.unpack (B.words x) === words (B.unpack x)+  , testProperty "unwords" $+    \xs -> B.unpack (B.unwords xs) === unwords (map B.unpack xs)+#endif++#ifndef BYTESTRING_LAZY+  , testProperty "unfoldrN" $+    \n f (toElem -> c) -> B.unpack (fst (B.unfoldrN n (fmap (first toElem) . f) c)) ===+      take (fromIntegral n) (List.unfoldr (fmap (first toElem) . f) c)+  , testProperty "unfoldrN replicate" $+    \n (toElem -> c) -> fst (B.unfoldrN n (\t -> Just (t, t)) c) === B.replicate n c+  , testProperty "unfoldr" $+    \n a (toElem -> c) -> B.unpack (B.unfoldr (\x -> if x <= 100 * n then Just (c, x + 1 :: Int) else Nothing) a) ===+      List.unfoldr (\x -> if x <= 100 * n then Just (c, x + 1) else Nothing) a+#endif++#ifdef BYTESTRING_LAZY+  , testProperty "unfoldr" $+    \n f (toElem -> a) -> B.unpack (B.take (fromIntegral n) (B.unfoldr (fmap (first toElem) . f) a)) ===+      take n (List.unfoldr (fmap (first toElem) . f) a)+  , testProperty "repeat" $+    \n (toElem -> c) -> B.take (fromIntegral (n :: Int)) (B.repeat c) ===+      B.take (fromIntegral n) (B.unfoldr (\a -> Just (a, a)) c)+  , testProperty "cycle" $+    \n x -> not (B.null x) ==> B.take (fromIntegral (n :: Int)) (B.cycle x) ===+      B.take (fromIntegral n) (B.concat (List.unfoldr (\a -> Just (a, a)) x))+  , testProperty "iterate" $+    \n f (toElem -> a) -> B.take (fromIntegral (n :: Int)) (B.iterate (toElem . f) a) ===+      B.take (fromIntegral n) (B.unfoldr (\x -> Just (toElem (f x), toElem (f x))) a)+#endif++#ifndef BYTESTRING_CHAR8+  -- issue #393+  , testProperty "fromString non-char8" $+    \s -> fromString s == B.pack (map (fromIntegral . ord :: Char -> Word8) s)+  , testProperty "fromString literal" $+    fromString "\0\1\2\3\4" == B.pack [0,1,2,3,4]+#endif+  ]++unsnoc :: [a] -> Maybe ([a], a)+unsnoc [] = Nothing+unsnoc xs = Just (init xs, last xs)++findIndexEnd :: (a -> Bool) -> [a] -> Maybe Int+findIndexEnd f xs = fmap (\n -> length xs - 1 - n) (List.findIndex f (reverse xs))++elemIndexEnd :: Eq a => a -> [a] -> Maybe Int+elemIndexEnd c xs = fmap (\n -> length xs - 1 - n) (List.elemIndex c (reverse xs))++stripSuffix :: Eq a => [a] -> [a] -> Maybe [a]+stripSuffix x y = fmap reverse (List.stripPrefix (reverse x) (reverse y))++split :: Eq a => a -> [a] -> [[a]]+split c = splitWith (== c)++splitWith :: (a -> Bool) -> [a] -> [[a]]+splitWith _ [] = []+splitWith f ys = go [] ys+  where+    go acc [] = [reverse acc]+    go acc (x : xs)+      | f x       = reverse acc : go [] xs+      | otherwise = go (x : acc) xs++#ifdef BYTESTRING_CHAR8+readInt :: String -> Maybe (Int, String)+readInt xs = case readInteger xs of+  Just (y, zs)+    | y' <- fromInteger y, toInteger y' == y -> Just (y', zs)+  otherwise -> Nothing++readInteger :: String -> Maybe (Integer, String)+readInteger ('+' : xs) = readIntegerUnsigned xs+readInteger ('-' : xs) = fmap (first negate) (readIntegerUnsigned xs)+readInteger xs = readIntegerUnsigned xs++readIntegerUnsigned :: String -> Maybe (Integer, String)+readIntegerUnsigned xs = case readMaybe ys of+  Just y -> Just (y, zs)+  otherwise -> Nothing+  where+    (ys, zs) = span isDigit xs+#endif
+ tests/Properties/ByteStringChar8.hs view
@@ -0,0 +1,5 @@+{-# LANGUAGE CPP #-}++#define BYTESTRING_CHAR8++#include "ByteString.hs"
+ tests/Properties/ByteStringLazy.hs view
@@ -0,0 +1,5 @@+{-# LANGUAGE CPP #-}++#define BYTESTRING_LAZY++#include "ByteString.hs"
+ tests/Properties/ByteStringLazyChar8.hs view
@@ -0,0 +1,6 @@+{-# LANGUAGE CPP #-}++#define BYTESTRING_LAZY+#define BYTESTRING_CHAR8++#include "ByteString.hs"
tests/QuickCheckUtils.hs view
@@ -1,17 +1,19 @@-{-# LANGUAGE CPP, MultiParamTypeClasses,-             FlexibleInstances, FlexibleContexts,-             TypeSynonymInstances #-}------ Uses multi-param type classes----module QuickCheckUtils where+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE TypeApplications #-} +module QuickCheckUtils+  ( Char8(..)+  , String8(..)+  , CByteString(..)+  , Sqrt(..)+  ) where+ import Test.Tasty.QuickCheck import Text.Show.Functions  import Control.Monad        ( liftM2 ) import Data.Char-import Data.List import Data.Word import Data.Int import System.IO@@ -34,6 +36,7 @@     bs <- sized sizedByteString     n  <- choose (0, 2)     return (P.drop n bs) -- to give us some with non-0 offset+  shrink = map P.pack . shrink . P.unpack  instance CoArbitrary P.ByteString where   coarbitrary s = coarbitrary (P.unpack s)@@ -72,6 +75,7 @@     where       toChar :: Word8 -> Char       toChar = toEnum . fromIntegral+  shrink (Char8 c) = fmap Char8 (shrink c)  instance CoArbitrary Char8 where   coarbitrary (Char8 c) = coarbitrary c@@ -86,112 +90,14 @@     where       toChar :: Word8 -> Char       toChar = toEnum . fromIntegral-------------------------------------------------------------------------------- We're doing two forms of testing here. Firstly, model based testing.--- For our Lazy and strict bytestring types, we have model types:------  i.e.    Lazy    ==   Byte---              \\      //---                 List------ That is, the Lazy type can be modeled by functions in both the Byte--- and List type. For each of the 3 models, we have a set of tests that--- check those types match.------ The Model class connects a type and its model type, via a conversion--- function.-------class Model a b where-  model :: a -> b  -- ^ Get the abstract value from a concrete value---- | Alias for 'model' that's a better name in the situations where we're--- really just converting functions that take or return Char8.-castFn :: Model a b => a -> b-castFn = model------- Connecting our Lazy and Strict types to their models. We also check--- the data invariant on Lazy types.------ These instances represent the arrows in the above diagram----instance Model B P      where model = abstr . checkInvariant-instance Model P [W]    where model = P.unpack-instance Model P [Char] where model = PC.unpack-instance Model B [W]    where model = L.unpack  . checkInvariant-instance Model B [Char] where model = LC.unpack . checkInvariant-instance Model Char8 Char where model (Char8 c) = c---- Types are trivially modeled by themselves-instance Model Bool  Bool         where model = id-instance Model Int   Int          where model = id-instance Model P     P            where model = id-instance Model B     B            where model = id-instance Model Int64 Int64        where model = id-instance Model Word8 Word8        where model = id-instance Model Ordering Ordering  where model = id-instance Model Char Char  where model = id---- More structured types are modeled recursively, using the NatTrans class from Gofer.-class (Functor f, Functor g) => NatTrans f g where-    eta :: f a -> g a---- The transformation of the same type is identity-instance NatTrans [] []             where eta = id-instance NatTrans Maybe Maybe       where eta = id-instance NatTrans ((->) X) ((->) X) where eta = id-instance NatTrans ((->) Char) ((->) Char) where eta = id-instance NatTrans ((->) Char8) ((->) Char) where eta f = f . Char8--instance NatTrans ((->) W) ((->) W) where eta = id---- We have a transformation of pairs, if the pairs are in Model-instance Model f g => NatTrans ((,) f) ((,) g) where eta (f,a) = (model f, a)---- And finally, we can take any (m a) to (n b), if we can Model m n, and a b-instance (NatTrans m n, Model a b) => Model (m a) (n b) where model x = fmap model (eta x)------------------------------------------------------------------------------ In a form more useful for QC testing (and it's lazy)-checkInvariant :: L.ByteString -> L.ByteString-checkInvariant = L.checkInvariant--abstr :: L.ByteString -> P.ByteString-abstr = P.concat . L.toChunks---- Some short hand.-type X = Int-type W = Word8-type P = P.ByteString-type B = L.ByteString-------------------------------------------------------------------------------- These comparison functions handle wrapping and equality.------ A single class for these would be nice, but note that they differe in--- the number of arguments, and those argument types, so we'd need HList--- tricks. See here: http://okmij.org/ftp/Haskell/vararg-fn.lhs-----eq1 f g = \a         ->-    model (f a)         == g (model a)-eq2 f g = \a b       ->-    model (f a b)       == g (model a) (model b)-eq3 f g = \a b c     ->-    model (f a b c)     == g (model a) (model b) (model c)+  shrink (String8 xs) = fmap String8 (shrink xs) ------ And for functions that take non-null input----eqnotnull1 f g = \x     -> (not (isNull x)) ==> eq1 f g x-eqnotnull2 f g = \x y   -> (not (isNull y)) ==> eq2 f g x y-eqnotnull3 f g = \x y z -> (not (isNull z)) ==> eq3 f g x y z+-- | If a test takes O(n^2) time or memory, it's useful to wrap its inputs+-- into 'Sqrt' so that increasing number of tests affects run time linearly.+newtype Sqrt a = Sqrt { unSqrt :: a }+  deriving (Eq, Show) -class    IsNull t            where isNull :: t -> Bool-instance IsNull L.ByteString where isNull = L.null-instance IsNull P.ByteString where isNull = P.null+instance Arbitrary a => Arbitrary (Sqrt a) where+  arbitrary = Sqrt <$> sized+    (\n -> resize (round @Double $ sqrt $ fromIntegral @Int n) arbitrary)+  shrink = map Sqrt . shrink . unSqrt
− tests/Rules.hs
@@ -1,41 +0,0 @@-module Rules where------ Tests to ensure rules are firing.-----import qualified Data.ByteString.Char8       as C-import qualified Data.ByteString             as P-import qualified Data.ByteString.Lazy        as L-import qualified Data.ByteString.Lazy.Char8  as D-import Data.List-import Data.Char-import Data.Word--import QuickCheckUtils--import Test.Tasty.QuickCheck--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`-                       (\s1 s2 -> intercalate [c] (s1 : s2 : []))--prop_break_isSpace_C = C.break isSpace `eq1` break isSpace-prop_dropWhile_isSpace_C = C.dropWhile isSpace `eq1` dropWhile isSpace--rules =-    [ testProperty "break (==)"        prop_break_C-    , testProperty "break (==)"        prop_break_P-    , testProperty "break isSpace"     prop_break_isSpace_C-    , testProperty "dropWhile isSpace" prop_dropWhile_isSpace_C-    , testProperty "intercalate"       prop_intercalate_P-    ]
tests/builder/Data/ByteString/Builder/Prim/TestUtils.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE CPP #-} {-# LANGUAGE ScopedTypeVariables #-} -- | -- Copyright   : (c) 2011 Simon Meier@@ -59,6 +60,8 @@   , double_list   , coerceFloatToWord32   , coerceDoubleToWord64+  , coerceWord32ToFloat+  , coerceWord64ToDouble    ) where @@ -76,13 +79,13 @@ import           Data.Word import           Foreign (Storable(..), castPtr, minusPtr, with) import           Numeric (showHex)-import           GHC.ByteOrder import           System.IO.Unsafe (unsafePerformIO)  import           Test.Tasty-import           Test.Tasty.HUnit (assertBool, testCase) import           Test.Tasty.QuickCheck (Arbitrary(..), testProperty) +#include <ghcautoconf.h>+ -- Helper functions ------------------- @@ -92,8 +95,8 @@                     => String -> (a -> Bool) -> TestTree testBoundedProperty name p = testGroup name   [ testProperty name p-  , testCase (name ++ " minBound") $ assertBool "minBound" (p (minBound :: a))-  , testCase (name ++ " maxBound") $ assertBool "minBound" (p (maxBound :: a))+  , testProperty (name ++ " minBound") (p (minBound :: a))+  , testProperty (name ++ " maxBound") (p (maxBound :: a))   ]  -- | Quote a 'String' nicely.@@ -330,10 +333,14 @@ littleEndian_list x =     map (fromIntegral . (x `shiftR`) . (8*)) $ [0..sizeOf x - 1] +-- See https://gitlab.haskell.org/ghc/ghc/-/issues/20338+-- and https://gitlab.haskell.org/ghc/ghc/-/issues/18445 hostEndian_list :: (Storable a, Bits a, Integral a) => a -> [Word8]-hostEndian_list = case targetByteOrder of-    LittleEndian -> littleEndian_list-    BigEndian    -> bigEndian_list+#if defined(WORDS_BIGENDIAN)+hostEndian_list = bigEndian_list+#else+hostEndian_list = littleEndian_list+#endif  float_list :: (Word32 -> [Word8]) -> Float -> [Word8] float_list f  = f . coerceFloatToWord32@@ -350,6 +357,16 @@ {-# NOINLINE coerceDoubleToWord64 #-} coerceDoubleToWord64 :: Double -> Word64 coerceDoubleToWord64 x = unsafePerformIO (with x (peek . castPtr))++-- | Convert a 'Word32' to a 'Float'.+{-# NOINLINE coerceWord32ToFloat #-}+coerceWord32ToFloat :: Word32 -> Float+coerceWord32ToFloat x = unsafePerformIO (with x (peek . castPtr))++-- | Convert a 'Word64' to a 'Double'.+{-# NOINLINE coerceWord64ToDouble #-}+coerceWord64ToDouble :: Word64 -> Double+coerceWord64ToDouble x = unsafePerformIO (with x (peek . castPtr))  -- | Parse a variable length encoding parseVar :: (Num a, Bits a) => [Word8] -> (a, [Word8])
tests/builder/Data/ByteString/Builder/Tests.hs view
@@ -1,4 +1,5 @@ {-# LANGUAGE BangPatterns     #-}+{-# LANGUAGE MagicHash        #-} {-# LANGUAGE CPP              #-} {-# OPTIONS_GHC -fno-warn-orphans #-} @@ -14,6 +15,8 @@  module Data.ByteString.Builder.Tests (tests) where +import           Prelude hiding (writeFile)+ import           Control.Applicative import           Control.Monad (unless, void) import           Control.Monad.Trans.State (StateT, evalStateT, evalState, put, get)@@ -23,8 +26,11 @@ import           Foreign (minusPtr)  import           Data.Char (chr)-import qualified Data.DList      as D+import           Data.Bits ((.|.), shiftL) import           Data.Foldable+#if !MIN_VERSION_base(4,11,0)+import           Data.Semigroup+#endif import           Data.Word  import qualified Data.ByteString          as S@@ -43,12 +49,14 @@ import           System.IO (openTempFile, hPutStr, hClose, hSetBinaryMode, hSetEncoding, utf8, hSetNewlineMode, noNewlineTranslation) import           Foreign (ForeignPtr, withForeignPtr, castPtr) import           Foreign.C.String (withCString)+import           Numeric (showFFloat) import           System.Posix.Internals (c_unlink)  import           Test.Tasty (TestTree, TestName, testGroup) import           Test.Tasty.QuickCheck                    ( Arbitrary(..), oneof, choose, listOf, elements-                   , counterexample, ioProperty, UnicodeString(..), Property, testProperty )+                   , counterexample, ioProperty, UnicodeString(..), Property, testProperty+                   , (===), (.&&.), conjoin )   tests :: [TestTree]@@ -58,10 +66,12 @@   , testHandlePutBuilderChar8   , testPut   , testRunBuilder+  , testWriteFile   ] ++   testsEncodingToBuilder ++   testsBinary ++   testsASCII +++  testsFloating ++   testsChar8 ++   testsUtf8 @@ -94,20 +104,10 @@     testRecipe :: (UnicodeString, UnicodeString, UnicodeString, Recipe) -> Property     testRecipe args =       ioProperty $ 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+        let { ( UnicodeString before+              , UnicodeString between+              , UnicodeString after+              , recipe) = args }         (tempFile, tempH) <- openTempFile "." "test-builder.tmp"         -- switch to UTF-8 encoding         hSetEncoding tempH utf8@@ -173,6 +173,32 @@         unless success (error msg)         return success +testWriteFile :: TestTree+testWriteFile =+    testProperty "writeFile" testRecipe+  where+    testRecipe :: Recipe -> Property+    testRecipe recipe =+        ioProperty $ do+            (tempFile, tempH) <- openTempFile "." "test-builder-writeFile.tmp"+            hClose tempH+            let b = fst $ recipeComponents recipe+            writeFile tempFile b+            lbs <- L.readFile tempFile+            _ <- evaluate (L.length $ lbs)+            removeFile tempFile+            let lbsRef = toLazyByteString b+            -- report+            let msg =+                    unlines+                        [ "recipe:   " ++ show recipe+                        , "via file: " ++ show lbs+                        , "direct :  " ++ show lbsRef+                        ]+                success = lbs == lbsRef+            unless success (error msg)+            return success+ removeFile :: String -> IO () removeFile fn = void $ withCString fn c_unlink @@ -207,31 +233,45 @@ data Recipe = Recipe Strategy Int Int L.ByteString [Action]      deriving( Eq, Ord, Show ) +newtype DList a = DList ([a] -> [a])++instance Semigroup (DList a) where+  DList f <> DList g = DList (f . g)++instance Monoid (DList a) where+  mempty = DList id+  mappend = (<>)++fromDList :: DList a -> [a]+fromDList (DList f) = f []++toDList :: [a] -> DList a+toDList xs = DList (xs <>)+ renderRecipe :: Recipe -> [Word8] renderRecipe (Recipe _ firstSize _ cont as) =-    D.toList $ evalState (execWriterT (traverse_ renderAction as)) firstSize-                 `D.append` renderLBS cont+  fromDList $ evalState (execWriterT (traverse_ renderAction as)) firstSize <> renderLBS cont   where-    renderAction :: Monad m => Action -> WriterT (D.DList Word8) (StateT Int m) ()+    renderAction :: Monad m => Action -> WriterT (DList Word8) (StateT Int m) ()     renderAction (SBS Hex bs)   = tell $ foldMap hexWord8 $ S.unpack bs-    renderAction (SBS _ bs)     = tell $ D.fromList $ S.unpack bs+    renderAction (SBS _ bs)     = tell $ toDList $ S.unpack bs     renderAction (LBS Hex lbs)  = tell $ foldMap hexWord8 $ L.unpack lbs     renderAction (LBS _ lbs)    = tell $ renderLBS lbs-    renderAction (ShBS sbs)     = tell $ D.fromList $ Sh.unpack sbs-    renderAction (W8 w)         = tell $ return w-    renderAction (W8S ws)       = tell $ D.fromList ws-    renderAction (String cs)    = tell $ foldMap (D.fromList . charUtf8_list) cs-    renderAction Flush          = tell $ D.empty-    renderAction (EnsureFree _) = tell $ D.empty-    renderAction (FDec f)       = tell $ D.fromList $ encodeASCII $ show f-    renderAction (DDec d)       = tell $ D.fromList $ encodeASCII $ show d+    renderAction (ShBS sbs)     = tell $ toDList $ Sh.unpack sbs+    renderAction (W8 w)         = tell $ toDList [w]+    renderAction (W8S ws)       = tell $ toDList ws+    renderAction (String cs)    = tell $ foldMap (toDList . charUtf8_list) cs+    renderAction Flush          = tell $ mempty+    renderAction (EnsureFree _) = tell $ mempty+    renderAction (FDec f)       = tell $ toDList $ encodeASCII $ show f+    renderAction (DDec d)       = tell $ toDList $ encodeASCII $ show d     renderAction (ModState i)   = do         s <- lift get-        tell (D.fromList $ encodeASCII $ show s)+        tell (toDList $ encodeASCII $ show s)         lift $ put (s - i) -    renderLBS = D.fromList . L.unpack-    hexWord8  = D.fromList . wordHexFixed_list+    renderLBS = toDList . L.unpack+    hexWord8  = toDList . wordHexFixed_list  buildAction :: Action -> StateT Int Put () buildAction (SBS Hex bs)            = lift $ putBuilder $ byteStringHex bs@@ -600,6 +640,342 @@   ]   where     enlarge (n, e) = n ^ (abs (e `mod` (50 :: Integer)))++testsFloating :: [TestTree]+testsFloating =+  [ testMatches "f2sBasic" floatDec show+        [ ( 0.0    , "0.0" )+        , ( (-0.0) , "-0.0" )+        , ( 1.0    , "1.0" )+        , ( (-1.0) , "-1.0" )+        , ( (0/0)  , "NaN" )+        , ( (1/0)  , "Infinity" )+        , ( (-1/0) , "-Infinity" )+        ]+  , testMatches "f2sSubnormal" floatDec show+        [ ( 1.1754944e-38 , "1.1754944e-38" )+        ]+  , testMatches "f2sMinAndMax" floatDec show+        [ ( coerceWord32ToFloat 0x7f7fffff , "3.4028235e38" )+        , ( coerceWord32ToFloat 0x00000001 , "1.0e-45" )+        ]+  , testMatches "f2sBoundaryRound" floatDec show+        [ ( 3.355445e7   , "3.3554448e7" )+        , ( 8.999999e9   , "8.999999e9" )+        , ( 3.4366717e10 , "3.4366718e10" )+        ]+  , testMatches "f2sExactValueRound" floatDec show+        [ ( 3.0540412e5 , "305404.13" )+        , ( 8.0990312e3 , "8099.0313" )+        ]+  , testMatches "f2sTrailingZeros" floatDec show+        -- Pattern for the first test: 00111001100000000000000000000000+        [ ( 2.4414062e-4 , "2.4414063e-4" )+        , ( 2.4414062e-3 , "2.4414063e-3" )+        , ( 4.3945312e-3 , "4.3945313e-3" )+        , ( 6.3476562e-3 , "6.3476563e-3" )+        ]+  , testMatches "f2sRegression" floatDec show+        [ ( 4.7223665e21   , "4.7223665e21" )+        , ( 8388608.0      , "8388608.0" )+        , ( 1.6777216e7    , "1.6777216e7" )+        , ( 3.3554436e7    , "3.3554436e7" )+        , ( 6.7131496e7    , "6.7131496e7" )+        , ( 1.9310392e-38  , "1.9310392e-38" )+        , ( (-2.47e-43)    , "-2.47e-43" )+        , ( 1.993244e-38   , "1.993244e-38" )+        , ( 4103.9003      , "4103.9004" )+        , ( 5.3399997e9    , "5.3399997e9" )+        , ( 6.0898e-39     , "6.0898e-39" )+        , ( 0.0010310042   , "1.0310042e-3" )+        , ( 2.8823261e17   , "2.882326e17" )+        , ( 7.0385309e-26  , "7.038531e-26" )+        , ( 9.2234038e17   , "9.223404e17" )+        , ( 6.7108872e7    , "6.710887e7" )+        , ( 1.0e-44        , "1.0e-44" )+        , ( 2.816025e14    , "2.816025e14" )+        , ( 9.223372e18    , "9.223372e18" )+        , ( 1.5846085e29   , "1.5846086e29" )+        , ( 1.1811161e19   , "1.1811161e19" )+        , ( 5.368709e18    , "5.368709e18" )+        , ( 4.6143165e18   , "4.6143166e18" )+        , ( 0.007812537    , "7.812537e-3" )+        , ( 1.4e-45        , "1.0e-45" )+        , ( 1.18697724e20  , "1.18697725e20" )+        , ( 1.00014165e-36 , "1.00014165e-36" )+        , ( 200.0          , "200.0" )+        , ( 3.3554432e7    , "3.3554432e7" )+        , ( 2.0019531      , "2.0019531" )+        , ( 2.001953       , "2.001953" )+        ]+  , testExpected "f2sScientific" (formatFloat scientific)+        [ ( 0.0            , "0.0e0"         )+        , ( 8388608.0      , "8.388608e6"    )+        , ( 1.6777216e7    , "1.6777216e7"   )+        , ( 3.3554436e7    , "3.3554436e7"   )+        , ( 6.7131496e7    , "6.7131496e7"   )+        , ( 1.9310392e-38  , "1.9310392e-38" )+        , ( (-2.47e-43)    , "-2.47e-43"     )+        , ( 1.993244e-38   , "1.993244e-38"  )+        , ( 4103.9003      , "4.1039004e3"   )+        , ( 0.0010310042   , "1.0310042e-3"  )+        , ( 0.007812537    , "7.812537e-3"   )+        , ( 200.0          , "2.0e2"         )+        , ( 2.0019531      , "2.0019531e0"   )+        , ( 2.001953       , "2.001953e0"    )+        ]+  , testMatches "f2sLooksLikePowerOf5" floatDec show+        [ ( coerceWord32ToFloat 0x5D1502F9 , "6.7108864e17" )+        , ( coerceWord32ToFloat 0x5D9502F9 , "1.3421773e18" )+        , ( coerceWord32ToFloat 0x5e1502F9 , "2.6843546e18" )+        ]+  , testMatches "f2sOutputLength" floatDec show+        [ ( 1.0            , "1.0" )+        , ( 1.2            , "1.2" )+        , ( 1.23           , "1.23" )+        , ( 1.234          , "1.234" )+        , ( 1.2345         , "1.2345" )+        , ( 1.23456        , "1.23456" )+        , ( 1.234567       , "1.234567" )+        , ( 1.2345678      , "1.2345678" )+        , ( 1.23456735e-36 , "1.23456735e-36" )+        ]+  , testMatches "d2sBasic" doubleDec show+        [ ( 0.0    , "0.0" )+        , ( (-0.0) , "-0.0" )+        , ( 1.0    , "1.0" )+        , ( (-1.0) , "-1.0" )+        , ( (0/0)  , "NaN" )+        , ( (1/0)  , "Infinity" )+        , ( (-1/0) , "-Infinity" )+        ]+  , testMatches "d2sSubnormal" doubleDec show+        [ ( 2.2250738585072014e-308 , "2.2250738585072014e-308" )+        ]+  , testMatches "d2sMinAndMax" doubleDec show+        [ ( (coerceWord64ToDouble 0x7fefffffffffffff) , "1.7976931348623157e308" )+        , ( (coerceWord64ToDouble 0x0000000000000001) , "5.0e-324" )+        ]+  , testMatches "d2sTrailingZeros" doubleDec show+        [ ( 2.98023223876953125e-8 , "2.9802322387695313e-8" )+        ]+  , testMatches "d2sRegression" doubleDec show+        [ ( (-2.109808898695963e16) , "-2.1098088986959632e16" )+        , ( 4.940656e-318           , "4.940656e-318" )+        , ( 1.18575755e-316         , "1.18575755e-316" )+        , ( 2.989102097996e-312     , "2.989102097996e-312" )+        , ( 9.0608011534336e15      , "9.0608011534336e15" )+        , ( 4.708356024711512e18    , "4.708356024711512e18" )+        , ( 9.409340012568248e18    , "9.409340012568248e18" )+        , ( 1.2345678               , "1.2345678" )+        , ( 1.9430376160308388e16   , "1.9430376160308388e16" )+        , ( (-6.9741824662760956e19), "-6.9741824662760956e19" )+        , ( 4.3816050601147837e18   , "4.3816050601147837e18" )+        ]+  , testExpected "d2sScientific" (formatDouble scientific)+        [ ( 0.0         , "0.0e0"         )+        , ( 1.2345678   , "1.2345678e0"   )+        , ( 4.294967294 , "4.294967294e0" )+        , ( 4.294967295 , "4.294967295e0" )+        ]+  , testProperty "d2sStandard" $ conjoin+        [ singleMatches (formatDouble (standard 2)) (flip (showFFloat (Just 2)) []) ( 12.345 , "12.34"    )+        , singleMatches (formatDouble (standard 2)) (flip (showFFloat (Just 2)) []) ( 0.0050 , "0.00"     )+        , singleMatches (formatDouble (standard 2)) (flip (showFFloat (Just 2)) []) ( 0.0051 , "0.01"     )+        , singleMatches (formatDouble (standard 5)) (flip (showFFloat (Just 5)) []) ( 12.345 , "12.34500" )+        ]+  , testMatches "d2sLooksLikePowerOf5" doubleDec show+        [ ( (coerceWord64ToDouble 0x4830F0CF064DD592) , "5.764607523034235e39" )+        , ( (coerceWord64ToDouble 0x4840F0CF064DD592) , "1.152921504606847e40" )+        , ( (coerceWord64ToDouble 0x4850F0CF064DD592) , "2.305843009213694e40" )+        , ( (coerceWord64ToDouble 0x4400000000000004) , "3.689348814741914e19" )++        -- here v- is a power of 5 but since we don't accept bounds there is no+        -- interesting trailing behavior+        , ( (coerceWord64ToDouble 0x440000000000301d) , "3.6893488147520004e19" )+        ]+  , testMatches "d2sOutputLength" doubleDec show+        [ ( 1                  , "1.0" )+        , ( 1.2                , "1.2" )+        , ( 1.23               , "1.23" )+        , ( 1.234              , "1.234" )+        , ( 1.2345             , "1.2345" )+        , ( 1.23456            , "1.23456" )+        , ( 1.234567           , "1.234567" )+        , ( 1.2345678          , "1.2345678" )+        , ( 1.23456789         , "1.23456789" )+        , ( 1.234567895        , "1.234567895" )+        , ( 1.2345678901       , "1.2345678901" )+        , ( 1.23456789012      , "1.23456789012" )+        , ( 1.234567890123     , "1.234567890123" )+        , ( 1.2345678901234    , "1.2345678901234" )+        , ( 1.23456789012345   , "1.23456789012345" )+        , ( 1.234567890123456  , "1.234567890123456" )+        , ( 1.2345678901234567 , "1.2345678901234567" )++        -- Test 32-bit chunking+        , ( 4.294967294 , "4.294967294" )+        , ( 4.294967295 , "4.294967295" )+        , ( 4.294967296 , "4.294967296" )+        , ( 4.294967297 , "4.294967297" )+        , ( 4.294967298 , "4.294967298" )+        ]+  , testMatches "d2sMinMaxShift" doubleDec show+        [ ( (ieeeParts2Double False 4 0) , "1.7800590868057611e-307" )+        -- 32-bit opt-size=0:  49 <= dist <= 49+        -- 32-bit opt-size=1:  28 <= dist <= 49+        -- 64-bit opt-size=0:  50 <= dist <= 50+        -- 64-bit opt-size=1:  28 <= dist <= 50+        , ( (ieeeParts2Double False 6 maxMantissa) , "2.8480945388892175e-306" )+        -- 32-bit opt-size=0:  52 <= dist <= 53+        -- 32-bit opt-size=1:   2 <= dist <= 53+        -- 64-bit opt-size=0:  53 <= dist <= 53+        -- 64-bit opt-size=1:   2 <= dist <= 53+        , ( (ieeeParts2Double False 41 0) , "2.446494580089078e-296" )+        -- 32-bit opt-size=0:  52 <= dist <= 52+        -- 32-bit opt-size=1:   2 <= dist <= 52+        -- 64-bit opt-size=0:  53 <= dist <= 53+        -- 64-bit opt-size=1:   2 <= dist <= 53+        , ( (ieeeParts2Double False 40 maxMantissa) , "4.8929891601781557e-296" )+        -- 32-bit opt-size=0:  57 <= dist <= 58+        -- 32-bit opt-size=1:  57 <= dist <= 58+        -- 64-bit opt-size=0:  58 <= dist <= 58+        -- 64-bit opt-size=1:  58 <= dist <= 58+        , ( (ieeeParts2Double False 1077 0) , "1.8014398509481984e16" )+        -- 32-bit opt-size=0:  57 <= dist <= 57+        -- 32-bit opt-size=1:  57 <= dist <= 57+        -- 64-bit opt-size=0:  58 <= dist <= 58+        -- 64-bit opt-size=1:  58 <= dist <= 58+        , ( (ieeeParts2Double False 1076 maxMantissa) , "3.6028797018963964e16" )+        -- 32-bit opt-size=0:  51 <= dist <= 52+        -- 32-bit opt-size=1:  51 <= dist <= 59+        -- 64-bit opt-size=0:  52 <= dist <= 52+        -- 64-bit opt-size=1:  52 <= dist <= 59+        , ( (ieeeParts2Double False 307 0) , "2.900835519859558e-216" )+        -- 32-bit opt-size=0:  51 <= dist <= 51+        -- 32-bit opt-size=1:  51 <= dist <= 59+        -- 64-bit opt-size=0:  52 <= dist <= 52+        -- 64-bit opt-size=1:  52 <= dist <= 59+        , ( (ieeeParts2Double False 306 maxMantissa) , "5.801671039719115e-216" )+        -- 32-bit opt-size=0:  49 <= dist <= 49+        -- 32-bit opt-size=1:  44 <= dist <= 49+        -- 64-bit opt-size=0:  50 <= dist <= 50+        -- 64-bit opt-size=1:  44 <= dist <= 50+        , ( (ieeeParts2Double False 934 0x000FA7161A4D6e0C) , "3.196104012172126e-27" )+        ]+  , testMatches "d2sSmallIntegers" doubleDec show+        [ ( 9007199254740991.0 , "9.007199254740991e15" )+        , ( 9007199254740992.0 , "9.007199254740992e15" )++        , ( 1.0e+0                , "1.0" )+        , ( 1.2e+1                , "12.0" )+        , ( 1.23e+2               , "123.0" )+        , ( 1.234e+3              , "1234.0" )+        , ( 1.2345e+4             , "12345.0" )+        , ( 1.23456e+5            , "123456.0" )+        , ( 1.234567e+6           , "1234567.0" )+        , ( 1.2345678e+7          , "1.2345678e7" )+        , ( 1.23456789e+8         , "1.23456789e8" )+        , ( 1.23456789e+9         , "1.23456789e9" )+        , ( 1.234567895e+9        , "1.234567895e9" )+        , ( 1.2345678901e+10      , "1.2345678901e10" )+        , ( 1.23456789012e+11     , "1.23456789012e11" )+        , ( 1.234567890123e+12    , "1.234567890123e12" )+        , ( 1.2345678901234e+13   , "1.2345678901234e13" )+        , ( 1.23456789012345e+14  , "1.23456789012345e14" )+        , ( 1.234567890123456e+15 , "1.234567890123456e15" )++        -- 10^i+        , ( 1.0e+0  , "1.0" )+        , ( 1.0e+1  , "10.0" )+        , ( 1.0e+2  , "100.0" )+        , ( 1.0e+3  , "1000.0" )+        , ( 1.0e+4  , "10000.0" )+        , ( 1.0e+5  , "100000.0" )+        , ( 1.0e+6  , "1000000.0" )+        , ( 1.0e+7  , "1.0e7" )+        , ( 1.0e+8  , "1.0e8" )+        , ( 1.0e+9  , "1.0e9" )+        , ( 1.0e+10 , "1.0e10" )+        , ( 1.0e+11 , "1.0e11" )+        , ( 1.0e+12 , "1.0e12" )+        , ( 1.0e+13 , "1.0e13" )+        , ( 1.0e+14 , "1.0e14" )+        , ( 1.0e+15 , "1.0e15" )++        -- 10^15 + 10^i+        , ( (1.0e+15 + 1.0e+0)  , "1.000000000000001e15" )+        , ( (1.0e+15 + 1.0e+1)  , "1.00000000000001e15" )+        , ( (1.0e+15 + 1.0e+2)  , "1.0000000000001e15" )+        , ( (1.0e+15 + 1.0e+3)  , "1.000000000001e15" )+        , ( (1.0e+15 + 1.0e+4)  , "1.00000000001e15" )+        , ( (1.0e+15 + 1.0e+5)  , "1.0000000001e15" )+        , ( (1.0e+15 + 1.0e+6)  , "1.000000001e15" )+        , ( (1.0e+15 + 1.0e+7)  , "1.00000001e15" )+        , ( (1.0e+15 + 1.0e+8)  , "1.0000001e15" )+        , ( (1.0e+15 + 1.0e+9)  , "1.000001e15" )+        , ( (1.0e+15 + 1.0e+10) , "1.00001e15" )+        , ( (1.0e+15 + 1.0e+11) , "1.0001e15" )+        , ( (1.0e+15 + 1.0e+12) , "1.001e15" )+        , ( (1.0e+15 + 1.0e+13) , "1.01e15" )+        , ( (1.0e+15 + 1.0e+14) , "1.1e15" )++        -- Largest power of 2 <= 10^(i+1)+        , ( 8.0                , "8.0" )+        , ( 64.0               , "64.0" )+        , ( 512.0              , "512.0" )+        , ( 8192.0             , "8192.0" )+        , ( 65536.0            , "65536.0" )+        , ( 524288.0           , "524288.0" )+        , ( 8388608.0          , "8388608.0" )+        , ( 67108864.0         , "6.7108864e7" )+        , ( 536870912.0        , "5.36870912e8" )+        , ( 8589934592.0       , "8.589934592e9" )+        , ( 68719476736.0      , "6.8719476736e10" )+        , ( 549755813888.0     , "5.49755813888e11" )+        , ( 8796093022208.0    , "8.796093022208e12" )+        , ( 70368744177664.0   , "7.0368744177664e13" )+        , ( 562949953421312.0  , "5.62949953421312e14" )+        , ( 9007199254740992.0 , "9.007199254740992e15" )++        -- 1000 * (Largest power of 2 <= 10^(i+1))+        , ( 8.0e+3             , "8000.0" )+        , ( 64.0e+3            , "64000.0" )+        , ( 512.0e+3           , "512000.0" )+        , ( 8192.0e+3          , "8192000.0" )+        , ( 65536.0e+3         , "6.5536e7" )+        , ( 524288.0e+3        , "5.24288e8" )+        , ( 8388608.0e+3       , "8.388608e9" )+        , ( 67108864.0e+3      , "6.7108864e10" )+        , ( 536870912.0e+3     , "5.36870912e11" )+        , ( 8589934592.0e+3    , "8.589934592e12" )+        , ( 68719476736.0e+3   , "6.8719476736e13" )+        , ( 549755813888.0e+3  , "5.49755813888e14" )+        , ( 8796093022208.0e+3 , "8.796093022208e15" )+        ]+  , testMatches "f2sPowersOf10" floatDec show $+        fmap asShowRef [read ("1.0e" ++ show x) :: Float | x <- [-46..39 :: Int]]+  , testMatches "d2sPowersOf10" doubleDec show $+        fmap asShowRef [read ("1.0e" ++ show x) :: Double | x <- [-324..309 :: Int]]+  ]+  where+    testExpected :: TestName -> (a -> Builder) -> [(a, String)] -> TestTree+    testExpected name dec lst = testProperty name . conjoin $+      fmap (\(x, ref) -> L.unpack (toLazyByteString (dec x)) === encodeASCII ref) lst++    singleMatches :: (a -> Builder) -> (a -> String) -> (a, String) -> Property+    singleMatches dec refdec (x, ref) = L.unpack (toLazyByteString (dec x)) === encodeASCII (refdec x) .&&. refdec x === ref++    testMatches :: TestName -> (a -> Builder) -> (a -> String) -> [(a, String)] -> TestTree+    testMatches name dec refdec lst = testProperty name . conjoin $ fmap (singleMatches dec refdec) lst++    maxMantissa = (1 `shiftL` 53) - 1 :: Word64++    ieeeParts2Double :: Bool -> Int -> Word64 -> Double+    ieeeParts2Double sign expo mantissa =+        coerceWord64ToDouble $ (fromIntegral (fromEnum sign) `shiftL` 63) .|. (fromIntegral expo `shiftL` 52) .|. mantissa++    asShowRef x = (x, show x)  testsChar8 :: [TestTree] testsChar8 =
− tests/builder/TestSuite.hs
@@ -1,17 +0,0 @@-module Main where--import qualified Data.ByteString.Builder.Tests-import qualified Data.ByteString.Builder.Prim.Tests-import           Test.Tasty (defaultMain, TestTree, testGroup)--main :: IO ()-main = defaultMain $ testGroup "All" tests--tests :: [TestTree]-tests =-  [ testGroup "Data.ByteString.Builder"-       Data.ByteString.Builder.Tests.tests--  , testGroup "Data.ByteString.Builder.BasicEncoding"-       Data.ByteString.Builder.Prim.Tests.tests-  ]