Add `unsnoc` to Data.Text and Data.Text.Lazy
authorBrian Chen <brian.chxn@gmail.com>
Tue, 7 Mar 2017 21:11:18 +0000 (16:11 -0500)
committerBrian Chen <brian.chxn@gmail.com>
Tue, 7 Mar 2017 21:11:18 +0000 (16:11 -0500)
Closes #171.

Data/Text.hs
Data/Text/Lazy.hs
tests/Tests/Properties.hs

index 6e2eb3b..de064e8 100644 (file)
@@ -60,6 +60,7 @@ module Data.Text
     , snoc
     , append
     , uncons
+    , unsnoc
     , head
     , last
     , tail
@@ -545,6 +546,17 @@ init (Text arr off len) | len <= 0                   = emptyError "init"
     unstream (S.init (stream t)) = init t
  #-}
 
+-- | /O(1)/ Returns all but the last character and the last character of a
+-- 'Text', or 'Nothing' if empty.
+unsnoc :: Text -> Maybe (Text, Char)
+unsnoc (Text arr off len)
+    | len <= 0                 = Nothing
+    | n < 0xDC00 || n > 0xDFFF = Just (text arr off (len-1), unsafeChr n)
+    | otherwise                = Just (text arr off (len-2), U16.chr2 n0 n)
+    where n  = A.unsafeIndex arr (off+len-1)
+          n0 = A.unsafeIndex arr (off+len-2)
+{-# INLINE [1] unsnoc #-}
+
 -- | /O(1)/ Tests whether a 'Text' is empty or not.  Subject to
 -- fusion.
 null :: Text -> Bool
index 7094bcc..27b55bd 100644 (file)
@@ -68,6 +68,7 @@ module Data.Text.Lazy
     , snoc
     , append
     , uncons
+    , unsnoc
     , head
     , last
     , tail
@@ -561,6 +562,15 @@ init Empty = emptyError "init"
     unstream (S.init (stream t)) = init t
  #-}
 
+-- | /O(n\/c)/ Returns the 'init' and 'last' of a 'Text', or 'Nothing' if
+-- empty.
+--
+-- * It is no faster than using 'init' and 'last'.
+unsnoc :: Text -> Maybe (Text, Char)
+unsnoc Empty          = Nothing
+unsnoc ts@(Chunk _ _) = Just (init ts, last ts)
+{-# INLINE unsnoc #-}
+
 -- | /O(1)/ Tests whether a 'Text' is empty or not.  Subject to
 -- fusion.
 null :: Text -> Bool
index af5420e..5466dae 100644 (file)
@@ -9,7 +9,7 @@ module Tests.Properties
     ) where
 
 import Control.Applicative ((<$>), (<*>))
-import Control.Arrow ((***), second)
+import Control.Arrow ((***), first, second)
 import Data.Bits ((.&.))
 import Data.Char (chr, isDigit, isHexDigit, isLower, isSpace, isLetter, isUpper, ord)
 import Data.Int (Int8, Int16, Int32, Int64)
@@ -230,6 +230,13 @@ sf_uncons p       = (uncons . L.filter p) `eqP`
                     (fmap (second unpackS) . S.uncons . S.filter p)
 t_uncons          = uncons   `eqP` (fmap (second unpackS) . T.uncons)
 tl_uncons         = uncons   `eqP` (fmap (second unpackS) . TL.uncons)
+
+unsnoc xs@(_:_) = Just (init xs, last xs)
+unsnoc []       = Nothing
+
+t_unsnoc          = unsnoc   `eqP` (fmap (first unpackS) . T.unsnoc)
+tl_unsnoc         = unsnoc   `eqP` (fmap (first unpackS) . TL.unsnoc)
+
 s_head            = head   `eqP` S.head
 sf_head p         = (head . L.filter p) `eqP` (S.head . S.filter p)
 t_head            = head   `eqP` T.head
@@ -976,6 +983,8 @@ tests =
       testProperty "sf_uncons" sf_uncons,
       testProperty "t_uncons" t_uncons,
       testProperty "tl_uncons" tl_uncons,
+      testProperty "t_unsnoc" t_unsnoc,
+      testProperty "tl_unsnoc" tl_unsnoc,
       testProperty "s_head" s_head,
       testProperty "sf_head" sf_head,
       testProperty "t_head" t_head,