base64-bytestring 1.0.0.0 → 1.0.0.1
raw patch · 3 files changed
+92/−69 lines, 3 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
Files
- Data/ByteString/Base64/Internal.hs +60/−61
- base64-bytestring.cabal +3/−3
- benchmarks/BM.hs +29/−5
Data/ByteString/Base64/Internal.hs view
@@ -74,16 +74,16 @@ twoMore = sp `plusPtr` 2 == sEnd equals = 0x3d :: Word8 {-# INLINE equals #-}- a <- peekSP 0 ((`shiftR` 2) . (.&. 0xfc))- b <- peekSP 0 ((`shiftL` 4) . (.&. 0x03))+ !a <- peekSP 0 ((`shiftR` 2) . (.&. 0xfc))+ !b <- peekSP 0 ((`shiftL` 4) . (.&. 0x03)) !b' <- if twoMore then peekSP 1 ((.|. b) . (`shiftR` 4) . (.&. 0xf0)) else return b poke8 dp =<< aidx a poke8 (dp `plusPtr` 1) =<< aidx b'- c <- if twoMore- then aidx =<< peekSP 1 ((`shiftL` 2) . (.&. 0x0f))- else return equals+ !c <- if twoMore+ then aidx =<< peekSP 1 ((`shiftL` 2) . (.&. 0x0f))+ else return equals poke8 (dp `plusPtr` 2) c poke8 (dp `plusPtr` 3) equals withForeignPtr dfp $ \dptr ->@@ -155,12 +155,12 @@ | dlen <= 0 = Right B.empty | otherwise = unsafePerformIO $ do dfp <- mallocByteString dlen- withForeignPtr decodeFP $ \decptr -> do+ withForeignPtr decodeFP $ \ !decptr -> do let finish dbytes = return . Right $! if dbytes > 0 then PS dfp 0 dbytes else B.empty bail = return . Left- withForeignPtr sfp $ \sptr -> do+ withForeignPtr sfp $ \ !sptr -> do let sEnd = sptr `plusPtr` (slen + soff) look p = do ix <- fromIntegral `fmap` peek8 p@@ -197,9 +197,6 @@ where (di,drem) = slen `divMod` 4 dlen = di * 3 -data D = D { dNext :: {-# UNPACK #-} !(Ptr Word8)- , dValue :: {-# UNPACK #-} !Word32 }- -- | Decode a base64-encoded string. This function is lenient in -- following the specification from RFC 4648, -- <http://www.apps.ietf.org/rfc/rfc4648.html>, and will not generate@@ -211,45 +208,49 @@ | dlen <= 0 = B.empty | otherwise = unsafePerformIO $ do dfp <- mallocByteString dlen- dbytes <- withForeignPtr decodeFP $ \decptr ->- withForeignPtr sfp $ \sptr -> do- let sEnd = sptr `plusPtr` (slen + soff)+ withForeignPtr decodeFP $ \ !decptr ->+ withForeignPtr sfp $ \ !sptr -> do+ let finish dbytes+ | dbytes > 0 = return (PS dfp 0 dbytes)+ | otherwise = return B.empty+ sEnd = sptr `plusPtr` (slen + soff) fill !dp !sp !n- | sp >= sEnd = return n- | otherwise = {-# SCC "decodeLenientWithTable/fill" #-} do- let look skipPad = go+ | sp >= sEnd = finish n+ | otherwise = {-# SCC "decodeLenientWithTable/fill" #-}+ let look :: Bool -> Ptr Word8+ -> (Ptr Word8 -> Word32 -> IO ByteString)+ -> IO ByteString+ {-# INLINE look #-}+ look skipPad p0 f = go p0 where- go p | p >= sEnd = return $! D (sEnd `plusPtr` (-1)) done- | otherwise = {-# SCC "decodeLenient/look" #-} do+ go p | p >= sEnd = f (sEnd `plusPtr` (-1)) done+ | otherwise = {-# SCC "decodeLenient/look" #-} do ix <- fromIntegral `fmap` peek8 p v <- peek8 (decptr `plusPtr` ix) if v == x || (v == done && skipPad) then go (p `plusPtr` 1)- else return $! D (p `plusPtr` 1) (fromIntegral v)- !a <- look True sp- !b <- look True (dNext a)- !c <- look False (dNext b)- !d <- look False (dNext c)- let w = (dValue a `shiftL` 18) .|. (dValue b `shiftL` 12) .|.- (dValue c `shiftL` 6) .|. dValue d- if dValue a == done || dValue b == done- then return n- else do- poke8 dp $ fromIntegral (w `shiftR` 16)- if dValue c == done- then return $! n + 1- else do- poke8 (dp `plusPtr` 1) $ fromIntegral (w `shiftR` 8)- if dValue d == done- then return $! n + 2- else do- poke8 (dp `plusPtr` 2) $ fromIntegral w- fill (dp `plusPtr` 3) (dNext d) (n+3)+ else f (p `plusPtr` 1) (fromIntegral v)+ in look True sp $ \ !aNext !aValue ->+ look True aNext $ \ !bNext !bValue ->+ if aValue == done || bValue == done+ then finish n+ else+ look False bNext $ \ !cNext !cValue ->+ look False cNext $ \ !dNext !dValue -> do+ let w = (aValue `shiftL` 18) .|. (bValue `shiftL` 12) .|.+ (cValue `shiftL` 6) .|. dValue+ poke8 dp $ fromIntegral (w `shiftR` 16)+ if cValue == done+ then finish (n + 1)+ else do+ poke8 (dp `plusPtr` 1) $ fromIntegral (w `shiftR` 8)+ if dValue == done+ then finish (n + 2)+ else do+ poke8 (dp `plusPtr` 2) $ fromIntegral w+ fill (dp `plusPtr` 3) dNext (n+3) withForeignPtr dfp $ \dptr -> fill dptr (sptr `plusPtr` soff) 0- return $! if dbytes > 0- then PS dfp 0 dbytes- else B.empty where dlen = ((slen + 3) `div` 4) * 3 x :: Integral a => a@@ -263,23 +264,21 @@ -- This takes a list of ByteStrings, and returns a list in which each -- (apart from possibly the last) has length that is a multiple of n reChunkIn :: Int -> [ByteString] -> [ByteString]-reChunkIn _ [] = []-reChunkIn _ [y] = [y]-reChunkIn n (y : ys) = case B.length y `divMod` n of- (_, 0) ->- y : reChunkIn n ys- (d, _) ->- case B.splitAt (d * n) y of- (prefix, suffix) -> prefix : fixup suffix ys- where fixup acc [] = [acc]- fixup acc (z : zs) = case B.splitAt (n - B.length acc) z of- (prefix, suffix) ->- let acc' = acc `B.append` prefix- in if B.length acc' == n- then let zs' = if B.null suffix- then zs- else suffix : zs- in acc' : reChunkIn n zs'- else -- suffix must be null- fixup acc' zs-+reChunkIn !n = go+ where+ go [] = []+ go (y : ys) = case B.length y `divMod` n of+ (_, 0) -> y : go ys+ (d, _) -> case B.splitAt (d * n) y of+ (prefix, suffix) -> prefix : fixup suffix ys+ fixup acc [] = [acc]+ fixup acc (z : zs) = case B.splitAt (n - B.length acc) z of+ (prefix, suffix) ->+ let acc' = acc `B.append` prefix+ in if B.length acc' == n+ then let zs' = if B.null suffix+ then zs+ else suffix : zs+ in acc' : go zs'+ else -- suffix must be null+ fixup acc' zs
base64-bytestring.cabal view
@@ -1,7 +1,7 @@ name: base64-bytestring-version: 1.0.0.0-synopsis: Fast base64 encoding and deconding for ByteStrings-description: Fast base64 encoding and deconding for ByteStrings+version: 1.0.0.1+synopsis: Fast base64 encoding and decoding for ByteStrings+description: Fast base64 encoding and decoding for ByteStrings homepage: https://github.com/bos/base64-bytestring bug-reports: https://github.com/bos/base64-bytestring/issues license: BSD3
benchmarks/BM.hs view
@@ -1,11 +1,15 @@ {-# LANGUAGE OverloadedStrings #-} +import Control.DeepSeq (NFData(rnf)) import Criterion.Main-import qualified Data.ByteString.Char8 as B import qualified Data.ByteString.Base64 as B+import qualified Data.ByteString.Base64.Lazy as L import qualified Data.ByteString.Base64.URL as U+import qualified Data.ByteString.Char8 as B+import qualified Data.ByteString.Lazy as L+import qualified Data.ByteString.Lazy.Internal as L -sized name orig =+strict name orig = bgroup name [ bgroup "normal" [ bench "decode" $ whnf B.decode enc@@ -20,10 +24,30 @@ ] where enc = U.encode orig +instance NFData L.ByteString where+ rnf L.Empty = ()+ rnf (L.Chunk _ ps) = rnf ps++lazy name orig =+ bgroup name [+ bench "decode" $ nf L.decode enc+ , bench "encode" $ nf L.encode orig+ ]+ where enc = L.encode orig+ main :: IO () main = defaultMain [- sized "small" input- , sized "medium" (B.concat (replicate 100 input))- , sized "large" (B.concat (replicate 10000 input))+ bgroup "lazy" [+ lazy "small" (L.fromChunks [input])+ , lazy "medium" (L.concat . replicate 16 . L.fromChunks . (:[]) .+ B.concat $ replicate 8 input)+ , lazy "large" (L.concat . replicate 1280 . L.fromChunks . (:[]) .+ B.concat $ replicate 8 input)+ ]+ , bgroup "strict" [+ strict "small" input+ , strict "medium" (B.concat (replicate 128 input))+ , strict "large" (B.concat (replicate 10240 input))+ ] ] where input = "abcdABCD0123[];'"