Commits

Mikhail Vorozhtsov  committed 1986a50

Unified 'ensure' for ByteString and Text.

  • Participants
  • Parent commits 5bb0db2

Comments (0)

Files changed (4)

File Data/Attoparsec/ByteString/Internal.hs

 
 type Parser = T.Parser B.ByteString
 type Result = IResult B.ByteString
-type Input = T.Input B.ByteString
-type Added = T.Added B.ByteString
 type Failure r = T.Failure B.ByteString r
 type Success a r = T.Success B.ByteString a r
 
-ensure' :: Int -> Input -> Added -> More -> Failure r -> Success B.ByteString r
-        -> IResult B.ByteString r
-ensure' !n0 i0 a0 m0 kf0 ks0 =
-    T.runParser (demandInput >> go n0) i0 a0 m0 kf0 ks0
-  where
-    go !n = T.Parser $ \i a m kf ks ->
-        if B.length (unI i) >= n
-        then ks i a m (unI i)
-        else T.runParser (demandInput >> go n) i a m kf ks
-
--- | If at least @n@ bytes of input are available, return the current
--- input, otherwise fail.
-ensure :: Int -> Parser B.ByteString
-ensure !n = T.Parser $ \i0 a0 m0 kf ks ->
-    if B.length (unI i0) >= n
-    then ks i0 a0 m0 (unI i0)
-    -- The uncommon case is kept out-of-line to reduce code size:
-    else ensure' n i0 a0 m0 kf ks
--- Non-recursive so the bounds check can be inlined:
-{-# INLINE ensure #-}
-
 -- | The parser @satisfy p@ succeeds for any byte for which the
 -- predicate @p@ returns 'True'. Returns the byte that is actually
 -- parsed.

File Data/Attoparsec/Internal.hs

-{-# LANGUAGE CPP #-}
+{-# LANGUAGE CPP, BangPatterns #-}
 -- |
 -- Module      :  Data.Attoparsec.Internal
 -- Copyright   :  Bryan O'Sullivan 2012
       compareResults
     , get
     , put
+    , ensure
     , prompt
     , demandInput
     , wantInput
 put c = Parser $ \_i0 a0 m0 _kf ks -> ks (I c) a0 m0 ()
 {-# INLINE put #-}
 
+ensure' :: Chunk t
+        => Int -> Input t -> Added t -> More -> Failure t r -> Success t t r
+        -> IResult t r
+ensure' !n0 i0 a0 m0 kf0 ks0 =
+    runParser (demandInput >> go n0) i0 a0 m0 kf0 ks0
+  where
+    go !n = Parser $ \i a m kf ks ->
+        if chunkLengthAtLeast (unI i) n
+        then ks i a m (unI i)
+        else runParser (demandInput >> go n) i a m kf ks
+#if __GLASGOW_HASKELL__ >= 700
+{-# SPECIALIZE ensure' :: Int -> Input ByteString -> Added ByteString -> More
+                       -> Failure ByteString r
+                       -> Success ByteString ByteString r
+                       -> IResult ByteString r #-}
+{-# SPECIALIZE ensure' :: Int -> Input Text -> Added Text -> More
+                       -> Failure Text r -> Success Text Text r
+                       -> IResult Text r #-}
+#endif
+
+-- | If at least @n@ elements of input are available, return the
+-- current input, otherwise fail.
+ensure :: Chunk t => Int -> Parser t t
+ensure !n = Parser $ \i0 a0 m0 kf ks ->
+    if chunkLengthAtLeast (unI i0) n
+    then ks i0 a0 m0 (unI i0)
+    -- The uncommon case is kept out-of-line to reduce code size:
+    else ensure' n i0 a0 m0 kf ks
+-- Non-recursive so the bounds check can be inlined:
+{-# INLINE ensure #-}
+
 -- | Ask for input.  If we receive any, pass it to a success
 -- continuation, otherwise to a failure continuation.
 prompt :: Chunk t

File Data/Attoparsec/Internal/Types.hs

 import qualified Data.ByteString as BS
 import Data.Text (Text)
 import qualified Data.Text as T
+import qualified Data.Text.Unsafe as T
 import Data.Monoid (Monoid(..))
 import Prelude hiding (getChar, take, takeWhile)
 
   type ChunkElem c
   -- | Test if the chunk is empty.
   nullChunk :: c -> Bool
+  -- | Check if the chunk has the length of at least @n@ elements.
+  chunkLengthAtLeast :: c -> Int -> Bool
 
 instance Chunk ByteString where
   type ChunkElem ByteString = Word8
   nullChunk = BS.null
   {-# INLINE nullChunk #-}
+  chunkLengthAtLeast bs n = BS.length bs >= n
+  {-# INLINE chunkLengthAtLeast #-}
 
 instance Chunk Text where
   type ChunkElem Text = Char
   nullChunk = T.null
   {-# INLINE nullChunk #-}
+  chunkLengthAtLeast t n = T.lengthWord16 t `quot` 2 >= n || T.length t >= n
+  {-# INLINE chunkLengthAtLeast #-}

File Data/Attoparsec/Text/Internal.hs

 import qualified Data.Attoparsec.Internal.Types as T
 import qualified Data.Attoparsec.Text.FastSet as Set
 import qualified Data.Text as T
-import qualified Data.Text.Internal as T
 import qualified Data.Text.Lazy as L
 
 type Parser = T.Parser Text
 instance (a ~ Text) => IsString (Parser a) where
     fromString = string . T.pack
 
-lengthAtLeast :: T.Text -> Int -> Bool
-lengthAtLeast t@(T.Text _ _ len) n = (len `quot` 2) >= n || T.length t >= n
-{-# INLINE lengthAtLeast #-}
-
--- | If at least @n@ characters of input are available, return the
--- current input, otherwise fail.
-ensure :: Int -> Parser Text
-ensure !n = T.Parser $ \i0 a0 m0 kf ks ->
-    if lengthAtLeast (unI i0) n
-    then ks i0 a0 m0 (unI i0)
-    else runParser (demandInput >> go n) i0 a0 m0 kf ks
-  where
-    go n' = T.Parser $ \i0 a0 m0 kf ks ->
-        if lengthAtLeast (unI i0) n'
-        then ks i0 a0 m0 (unI i0)
-        else runParser (demandInput >> go n') i0 a0 m0 kf ks
-{-# INLINE ensure #-}
-
 unsafeHead :: Text -> Char
 unsafeHead = T.head