Commits

Bryan O'Sullivan committed bdf921f

Add lazy encoding/decoding support. Improve docs.

Comments (0)

Files changed (3)

Data/ByteString/Base16.hs

 digits = "0123456789abcdef"
 {-# NOINLINE digits #-}
 
+-- | Encode a string into base16 form.  The result will always be a
+-- multiple of 2 bytes in length.
+--
+-- Example:
+--
+-- > encode "foo"  == "666f6f"
 encode :: ByteString -> ByteString
 encode (PS sfp soff slen)
-    | slen > maxBound `div` 2 = error "Data.ByteString.Base16.encode: input too large"
+    | slen > maxBound `div` 2 =
+        error "Data.ByteString.Base16.encode: input too long"
     | otherwise = unsafeCreate (slen*2) $ \dptr ->
                     withForeignPtr sfp $ \sptr ->
                       enc (sptr `plusPtr` soff) dptr
       poke (d `plusPtr` 1) . unsafeIndex digits $ x .&. 0xf
       go (s `plusPtr` 1) (d `plusPtr` 2)
 
+-- | Decode a string from base16 form. The first element of the
+-- returned tuple contains the decoded data. The second element starts
+-- at the first invalid base16 sequence in the original string.
+--
+-- Examples:
+--
+-- > decode "666f6f"  == ("foo", "")
+-- > decode "66quux"  == ("f", "quux")
+-- > decode "666quux" == ("f", "6quux")
 decode :: ByteString -> (ByteString, ByteString)
 decode (PS sfp soff slen) =
   unsafePerformIO . createAndTrim' (slen `div` 2) $ \dptr ->

Data/ByteString/Base16/Lazy.hs

+{-# LANGUAGE OverloadedStrings #-}
+
+-- |
+-- Module      : Data.ByteString.Base16.Lazy
+-- Copyright   : (c) 2011 MailRank, Inc.
+--
+-- License     : BSD
+-- Maintainer  : bos@mailrank.com
+-- Stability   : experimental
+-- Portability : GHC
+--
+-- Fast and efficient encoding and decoding of base16-encoded strings.
+
+module Data.ByteString.Base16.Lazy
+    (
+      encode
+    , decode
+    ) where
+
+import Data.Word (Word8)
+import qualified Data.ByteString.Base16 as B16
+import qualified Data.ByteString as B
+import qualified Data.ByteString.Unsafe as B
+import Data.ByteString.Lazy.Internal
+
+-- | Encode a string into base16 form.  The result will always be a
+-- multiple of 2 bytes in length.
+--
+-- Example:
+--
+-- > encode "foo"  == "666f6f"
+encode :: ByteString -> ByteString
+encode (Chunk c cs) = Chunk (B16.encode c) (encode cs)
+encode Empty        = Empty
+
+-- | Decode a string from base16 form. The first element of the
+-- returned tuple contains the decoded data. The second element starts
+-- at the first invalid base16 sequence in the original string.
+--
+-- This function operates as lazily as possible over the input chunks.
+-- The only instance in which it is non-lazy is if an odd-length chunk
+-- ends with a byte that is valid base16.
+--
+-- Examples:
+--
+-- > decode "666f6f"  == ("foo", "")
+-- > decode "66quux"  == ("f", "quux")
+-- > decode "666quux" == ("f", "6quux")
+decode :: ByteString -> (ByteString, ByteString)
+decode = foldrChunks go (Empty, Empty)
+  where go c ~(y,z)
+           | len == 0 = (chunk h y, z)
+           | len == 1 && isHex (B.unsafeHead t) =
+               case z of
+                 Chunk a as | isHex (B.unsafeHead a)
+                   -> let (q,_) = B16.decode (t `B.snoc` B.unsafeHead a)
+                      in (chunk h (chunk q y), chunk (B.unsafeTail a) as)
+                 _ -> (chunk h y, chunk t z)
+           | otherwise = (chunk h y, chunk t z)
+            where (h,t) = B16.decode c
+                  len = B.length t
+
+isHex :: Word8 -> Bool
+isHex w = (w >= 48 && w <= 57) || (w >= 97 && w <= 102) || (w >= 65 && w <= 70)

base16-bytestring.cabal

 name:                base16-bytestring
-version:             0.1.0.0
+version:             0.1.1.0
 synopsis:            Fast base16 (hex) encoding and deconding for ByteStrings
 description:         Fast base16 (hex) encoding and deconding for ByteStrings
 homepage:            http://github.com/mailrank/base16-bytestring
 library
   exposed-modules:
     Data.ByteString.Base16
+    Data.ByteString.Base16.Lazy
   
   build-depends:
     base == 4.*,
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.