Bryan O'Sullivan avatar Bryan O'Sullivan committed 491340d

Implement break and span

Comments (0)

Files changed (2)

     , takeWhile
     , dropWhile
     , splitAt
-    -- , span
-    -- , break
+    , span
+    , break
     -- , group
     -- , groupBy
     , inits
                 Show, showsPrec,
                 Read, readsPrec,
                 (&&), (||), (+), (-), (<), (>), (<=), (>=), (.),
-                return, otherwise)
+                not, return, otherwise)
 import Data.Char (isSpace)
 import Control.Monad.ST (ST)
 import qualified Data.Text.Array as A
   #-}
 
 -- | /O(n)/ 'splitAt' @n t@ returns a pair whose first element is a
--- prefix of @t@ of length @n@ and second element is the remainder of
+-- prefix of @t@ of length @n@, and whose second is the remainder of
 -- the string. It is equivalent to @('take' n t, 'drop' n t)@.
 splitAt :: Int -> Text -> (Text, Text)
 splitAt n t@(Text arr off len)
   where k = loop off 0
         end = off + len
         loop !i !count
-            | i >= end || count >= n   = i - off
-            | otherwise                = loop (i+d) (count+1)
-            where d = iter_ arr i
+            | i >= end || count >= n = i - off
+            | otherwise              = loop (i+d) (count+1)
+            where d                  = iter_ arr i
 {-# INLINE splitAt #-}
 
+-- | /O(n)/ 'span', applied to a predicate @p@ and text @t@, returns a
+-- pair whose first element is the longest prefix (possibly empty) of
+-- @t@ of elements that satisfy @p@, and whose second is the remainder
+-- of the list.
+span :: (Char -> Bool) -> Text -> (Text, Text)
+span p t@(Text arr off len)
+    | k == 0    = (empty, t)
+    | k == len  = (t, empty)
+    | otherwise = (Text arr off k, Text arr (off+k) (len-k))
+  where k = loop off 0
+        loop !i !l | l >= len || not (p c) = l
+                   | otherwise             = loop (i+d) (l+d)
+            where (c,d)                    = iter arr i
+{-# INLINE span #-}
+
+-- | /O(n)/ 'break' is like 'span', but the prefix returned is over
+-- elements that fail the predicate @p@.
+break :: (Char -> Bool) -> Text -> (Text, Text)
+break p = span (not . p)
+{-# INLINE break #-}
+
 -- | /O(n)/ Return all initial segments of the given 'Text', shortest
 -- first.
 inits :: Text -> [Text]

tests/Properties.hs

 prop_dropWhile p     = L.dropWhile p `eqP` (unpack . T.dropWhile p)
 prop_dropWhileS p    = L.dropWhile p `eqP` (unpack . unstream . S.dropWhile p . stream)
 prop_splitAt n       = L.splitAt n   `eqP` ((unpack *** unpack) . T.splitAt n)
+prop_span p          = L.span p      `eqP` ((unpack *** unpack) . T.span p)
+prop_break p         = L.break p     `eqP` ((unpack *** unpack) . T.break p)
 prop_inits           = L.inits       `eqP` (map unpack . T.inits)
 prop_tails           = L.tails       `eqP` (map unpack . T.tails)
 
   ("prop_dropWhile", mytest prop_dropWhile),
   ("prop_dropWhileS", mytest prop_dropWhileS),
   ("prop_splitAt", mytest prop_splitAt),
+  ("prop_span", mytest prop_span),
+  ("prop_break", mytest prop_break),
   ("prop_inits", mytest prop_inits),
   ("prop_tails", mytest prop_tails),
 
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.