on master help sign in
Add `unsnoc` to Data.Text and Data.Text.Lazy
40a3168Brian Chen
Data/Text.hs+12
@@ -60,6 +60,7 @@ module Data.Text
60 , snoc
60 , snoc
61 , append
61 , append
62 , uncons
62 , uncons
63+ , unsnoc
63 , head
64 , head
64 , last
65 , last
65 , tail
66 , tail
@@ -545,6 +546,17 @@ init (Text arr off len) | len <= 0 = emptyError "init"
545 unstream (S.init (stream t)) = init t
546 unstream (S.init (stream t)) = init t
546 #-}
547 #-}
547
548
549+-- | /O(1)/ Returns all but the last character and the last character of a
550+-- 'Text', or 'Nothing' if empty.
551+unsnoc :: Text -> Maybe (Text, Char)
552+unsnoc (Text arr off len)
553+ | len <= 0 = Nothing
554+ | n < 0xDC00 || n > 0xDFFF = Just (text arr off (len-1), unsafeChr n)
555+ | otherwise = Just (text arr off (len-2), U16.chr2 n0 n)
556+ where n = A.unsafeIndex arr (off+len-1)
557+ n0 = A.unsafeIndex arr (off+len-2)
558+{-# INLINE [1] unsnoc #-}
559+
548-- | /O(1)/ Tests whether a 'Text' is empty or not. Subject to
560-- | /O(1)/ Tests whether a 'Text' is empty or not. Subject to
549-- fusion.
561-- fusion.
550null :: Text -> Bool
562null :: Text -> Bool
Data/Text/Lazy.hs+10
@@ -68,6 +68,7 @@ module Data.Text.Lazy
68 , snoc
68 , snoc
69 , append
69 , append
70 , uncons
70 , uncons
71+ , unsnoc
71 , head
72 , head
72 , last
73 , last
73 , tail
74 , tail
@@ -561,6 +562,15 @@ init Empty = emptyError "init"
561 unstream (S.init (stream t)) = init t
562 unstream (S.init (stream t)) = init t
562 #-}
563 #-}
563
564
565+-- | /O(n\/c)/ Returns the 'init' and 'last' of a 'Text', or 'Nothing' if
566+-- empty.
567+--
568+-- * It is no faster than using 'init' and 'last'.
569+unsnoc :: Text -> Maybe (Text, Char)
570+unsnoc Empty = Nothing
571+unsnoc ts@(Chunk _ _) = Just (init ts, last ts)
572+{-# INLINE unsnoc #-}
573+
564-- | /O(1)/ Tests whether a 'Text' is empty or not. Subject to
574-- | /O(1)/ Tests whether a 'Text' is empty or not. Subject to
565-- fusion.
575-- fusion.
566null :: Text -> Bool
576null :: Text -> Bool
tests/Tests/Properties.hs+10−1
@@ -9,7 +9,7 @@ module Tests.Properties
9 ) where
9 ) where
10
10
11import Control.Applicative ((<$>), (<*>))
11import Control.Applicative ((<$>), (<*>))
12−import Control.Arrow ((***), second)
12+import Control.Arrow ((***), first, second)
13import Data.Bits ((.&.))
13import Data.Bits ((.&.))
14import Data.Char (chr, isDigit, isHexDigit, isLower, isSpace, isLetter, isUpper, ord)
14import Data.Char (chr, isDigit, isHexDigit, isLower, isSpace, isLetter, isUpper, ord)
15import Data.Int (Int8, Int16, Int32, Int64)
15import Data.Int (Int8, Int16, Int32, Int64)
@@ -230,6 +230,13 @@ sf_uncons p = (uncons . L.filter p) `eqP`
230 (fmap (second unpackS) . S.uncons . S.filter p)
230 (fmap (second unpackS) . S.uncons . S.filter p)
231t_uncons = uncons `eqP` (fmap (second unpackS) . T.uncons)
231t_uncons = uncons `eqP` (fmap (second unpackS) . T.uncons)
232tl_uncons = uncons `eqP` (fmap (second unpackS) . TL.uncons)
232tl_uncons = uncons `eqP` (fmap (second unpackS) . TL.uncons)
233+
234+unsnoc xs@(_:_) = Just (init xs, last xs)
235+unsnoc [] = Nothing
236+
237+t_unsnoc = unsnoc `eqP` (fmap (first unpackS) . T.unsnoc)
238+tl_unsnoc = unsnoc `eqP` (fmap (first unpackS) . TL.unsnoc)
239+
233s_head = head `eqP` S.head
240s_head = head `eqP` S.head
234sf_head p = (head . L.filter p) `eqP` (S.head . S.filter p)
241sf_head p = (head . L.filter p) `eqP` (S.head . S.filter p)
235t_head = head `eqP` T.head
242t_head = head `eqP` T.head
@@ -976,6 +983,8 @@ tests =
976 testProperty "sf_uncons" sf_uncons,
983 testProperty "sf_uncons" sf_uncons,
977 testProperty "t_uncons" t_uncons,
984 testProperty "t_uncons" t_uncons,
978 testProperty "tl_uncons" tl_uncons,
985 testProperty "tl_uncons" tl_uncons,
986+ testProperty "t_unsnoc" t_unsnoc,
987+ testProperty "tl_unsnoc" tl_unsnoc,
979 testProperty "s_head" s_head,
988 testProperty "s_head" s_head,
980 testProperty "sf_head" sf_head,
989 testProperty "sf_head" sf_head,
981 testProperty "t_head" t_head,
990 testProperty "t_head" t_head,