on master help sign in
Implement dropEnd
65b6ea5Bryan O'Sullivan
Data/Text.hs+19−1
@@ -123,6 +123,7 @@ module Data.Text
123 -- ** Breaking strings
123 -- ** Breaking strings
124 , take
124 , take
125 , drop
125 , drop
126+ , dropEnd
126 , takeWhile
127 , takeWhile
127 , dropWhile
128 , dropWhile
128 , dropWhileEnd
129 , dropWhileEnd
@@ -214,7 +215,7 @@ import Data.Text.Internal.Private (span_)
214import Data.Text.Internal (Text(..), empty, firstf, safe, text, textP)
215import Data.Text.Internal (Text(..), empty, firstf, safe, text, textP)
215import qualified Prelude as P
216import qualified Prelude as P
216import Data.Text.Unsafe (Iter(..), iter, iter_, lengthWord16, reverseIter,
217import Data.Text.Unsafe (Iter(..), iter, iter_, lengthWord16, reverseIter,
217− unsafeHead, unsafeTail)
218+ reverseIter_, unsafeHead, unsafeTail)
218import Data.Text.Internal.Unsafe.Char (unsafeChr)
219import Data.Text.Internal.Unsafe.Char (unsafeChr)
219import qualified Data.Text.Internal.Functions as F
220import qualified Data.Text.Internal.Functions as F
220import qualified Data.Text.Internal.Encoding.Utf16 as U16
221import qualified Data.Text.Internal.Encoding.Utf16 as U16
@@ -1038,6 +1039,23 @@ drop n t@(Text arr off len)
1038 unstream (S.drop n (stream t)) = drop n t
1039 unstream (S.drop n (stream t)) = drop n t
1039 #-}
1040 #-}
1040
1041
1042+-- | /O(n)/ 'dropEnd' @n@ @t@ returns the prefix remaining after
1043+-- dropping @n@ characters from the end of @t@.
1044+--
1045+-- Examples:
1046+--
1047+-- > dropEnd 3 "foobar" == "foo"
1048+dropEnd :: Int -> Text -> Text
1049+dropEnd n t@(Text arr off len)
1050+ | n <= 0 = t
1051+ | n >= len = empty
1052+ | otherwise = loop (len-1) n
1053+ where loop i !m
1054+ | i <= 0 = empty
1055+ | m <= 1 = Text arr off i
1056+ | otherwise = loop (i+d) (m-1)
1057+ where d = reverseIter_ t i
1058+
1041-- | /O(n)/ 'takeWhile', applied to a predicate @p@ and a 'Text',
1059-- | /O(n)/ 'takeWhile', applied to a predicate @p@ and a 'Text',
1042-- returns the longest prefix (possibly empty) of elements that
1060-- returns the longest prefix (possibly empty) of elements that
1043-- satisfy @p@. Subject to fusion.
1061-- satisfy @p@. Subject to fusion.
Data/Text/Unsafe.hs+11
@@ -18,6 +18,7 @@ module Data.Text.Unsafe
18 , iter
18 , iter
19 , iter_
19 , iter_
20 , reverseIter
20 , reverseIter
21+ , reverseIter_
21 , unsafeHead
22 , unsafeHead
22 , unsafeTail
23 , unsafeTail
23 , lengthWord16
24 , lengthWord16
@@ -94,6 +95,16 @@ reverseIter (Text arr off _len) i
94 k = j - 1
95 k = j - 1
95{-# INLINE reverseIter #-}
96{-# INLINE reverseIter #-}
96
97
98+-- | /O(1)/ Iterate one step backwards through a UTF-16 array,
99+-- returning the delta to add (i.e. a negative number) to give the
100+-- next offset to iterate at.
101+reverseIter_ :: Text -> Int -> Int
102+reverseIter_ (Text arr off _len) i
103+ | m < 0xDC00 || m > 0xDFFF = -1
104+ | otherwise = -2
105+ where m = A.unsafeIndex arr (off+i)
106+{-# INLINE reverseIter_ #-}
107+
97-- | /O(1)/ Return the length of a 'Text' in units of 'Word16'. This
108-- | /O(1)/ Return the length of a 'Text' in units of 'Word16'. This
98-- is useful for sizing a target array appropriately before using
109-- is useful for sizing a target array appropriately before using
99-- 'unsafeCopyToPtr'.
110-- 'unsafeCopyToPtr'.
tests/Tests/Properties.hs+6
@@ -469,7 +469,11 @@ s_drop_s m = L.drop n `eqP` (unpackS . S.unstream . S.drop n)
469sf_drop p n = (L.drop n . L.filter p) `eqP`
469sf_drop p n = (L.drop n . L.filter p) `eqP`
470 (unpackS . S.drop n . S.filter p)
470 (unpackS . S.drop n . S.filter p)
471t_drop n = L.drop n `eqP` (unpackS . T.drop n)
471t_drop n = L.drop n `eqP` (unpackS . T.drop n)
472+t_dropEnd n = (L.reverse . L.drop n . L.reverse) `eqP`
473+ (unpackS . T.dropEnd n)
472tl_drop n = L.drop n `eqP` (unpackS . TL.drop (fromIntegral n))
474tl_drop n = L.drop n `eqP` (unpackS . TL.drop (fromIntegral n))
475+--tl_dropEnd n = (L.reverse . L.drop n . L.reverse) `eqP`
476+-- (unpackS . TL.dropEnd n)
473s_take_drop m = (L.take n . L.drop n) `eqP` (unpackS . S.take n . S.drop n)
477s_take_drop m = (L.take n . L.drop n) `eqP` (unpackS . S.take n . S.drop n)
474 where n = small m
478 where n = small m
475s_take_drop_s m = (L.take n . L.drop n) `eqP`
479s_take_drop_s m = (L.take n . L.drop n) `eqP`
@@ -1061,7 +1065,9 @@ tests =
1061 testProperty "s_drop_s" s_drop_s,
1065 testProperty "s_drop_s" s_drop_s,
1062 testProperty "sf_drop" sf_drop,
1066 testProperty "sf_drop" sf_drop,
1063 testProperty "t_drop" t_drop,
1067 testProperty "t_drop" t_drop,
1068+ testProperty "t_dropEnd" t_dropEnd,
1064 testProperty "tl_drop" tl_drop,
1069 testProperty "tl_drop" tl_drop,
1070+ -- testProperty "tl_dropEnd" tl_dropEnd,
1065 testProperty "s_take_drop" s_take_drop,
1071 testProperty "s_take_drop" s_take_drop,
1066 testProperty "s_take_drop_s" s_take_drop_s,
1072 testProperty "s_take_drop_s" s_take_drop_s,
1067 testProperty "s_takeWhile" s_takeWhile,
1073 testProperty "s_takeWhile" s_takeWhile,