on master help sign in
Implement dropEnd
commit65b6ea51eacf2307e4a38e35b656c635e1e85648 authorBryan O'Sullivan <bos@serpentine.com> dateThu 6 Mar 2014, 20:07 (13 years ago) parent94e83cf
3 files changed+36−1
Data/Text.hs+19−1 Data/Text/Unsafe.hs+11 tests/Tests/Properties.hs+6
Data/Text.hs+19−1
@@ -123,6 +123,7 @@ module Data.Text
123123 -- ** Breaking strings
124124 , take
125125 , drop
126+ , dropEnd
126127 , takeWhile
127128 , dropWhile
128129 , dropWhileEnd
@@ -214,7 +215,7 @@ import Data.Text.Internal.Private (span_)
214215import Data.Text.Internal (Text(..), empty, firstf, safe, text, textP)
215216import qualified Prelude as P
216217import Data.Text.Unsafe (Iter(..), iter, iter_, lengthWord16, reverseIter,
217− unsafeHead, unsafeTail)
218+ reverseIter_, unsafeHead, unsafeTail)
218219import Data.Text.Internal.Unsafe.Char (unsafeChr)
219220import qualified Data.Text.Internal.Functions as F
220221import qualified Data.Text.Internal.Encoding.Utf16 as U16
@@ -1038,6 +1039,23 @@ drop n t@(Text arr off len)
10381039 unstream (S.drop n (stream t)) = drop n t
10391040 #-}
10401041
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+
10411059-- | /O(n)/ 'takeWhile', applied to a predicate @p@ and a 'Text',
10421060-- returns the longest prefix (possibly empty) of elements that
10431061-- satisfy @p@. Subject to fusion.
Data/Text/Unsafe.hs+11
@@ -18,6 +18,7 @@ module Data.Text.Unsafe
1818 , iter
1919 , iter_
2020 , reverseIter
21+ , reverseIter_
2122 , unsafeHead
2223 , unsafeTail
2324 , lengthWord16
@@ -94,6 +95,16 @@ reverseIter (Text arr off _len) i
9495 k = j - 1
9596{-# INLINE reverseIter #-}
9697
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+
97108-- | /O(1)/ Return the length of a 'Text' in units of 'Word16'. This
98109-- is useful for sizing a target array appropriately before using
99110-- 'unsafeCopyToPtr'.
tests/Tests/Properties.hs+6
@@ -469,7 +469,11 @@ s_drop_s m = L.drop n `eqP` (unpackS . S.unstream . S.drop n)
469469sf_drop p n = (L.drop n . L.filter p) `eqP`
470470 (unpackS . S.drop n . S.filter p)
471471t_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)
472474tl_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)
473477s_take_drop m = (L.take n . L.drop n) `eqP` (unpackS . S.take n . S.drop n)
474478 where n = small m
475479s_take_drop_s m = (L.take n . L.drop n) `eqP`
@@ -1061,7 +1065,9 @@ tests =
10611065 testProperty "s_drop_s" s_drop_s,
10621066 testProperty "sf_drop" sf_drop,
10631067 testProperty "t_drop" t_drop,
1068+ testProperty "t_dropEnd" t_dropEnd,
10641069 testProperty "tl_drop" tl_drop,
1070+ -- testProperty "tl_dropEnd" tl_dropEnd,
10651071 testProperty "s_take_drop" s_take_drop,
10661072 testProperty "s_take_drop_s" s_take_drop_s,
10671073 testProperty "s_takeWhile" s_takeWhile,