on master help sign in
Implement lazy length, and test it

--HG-- extra : convert_revision : f56356a3336b696fe26b0d1b4a970ca997b9483e

commit1876b8c33d3e4af9a0c22a38fd5436734e436973 authorBryan O'Sullivan <bos@serpentine.com> dateTue 3 Mar 2009, 00:33 (18 years ago) parentc88ba28
3 files changed+34−2
Data/Text/Fusion.hs+13 Data/Text/Lazy.hs+15−2 tests/Properties.hs+6
Data/Text/Fusion.hs+13
@@ -39,6 +39,7 @@ module Data.Text.Fusion
3939 , init
4040 , null
4141 , length
42+ , length64
4243
4344 -- * Transformations
4445 , map
@@ -110,6 +111,7 @@ import qualified Data.List as L
110111import GHC.Exts (Int(..), (+#))
111112import Data.Bits ((.&.), shiftR)
112113import Data.Char (ord)
114+import Data.Int (Int64)
113115import Data.Text.Internal (Text(..))
114116import Data.Text.UnsafeChar (unsafeChr, unsafeWrite)
115117import qualified Data.Text.Array as A
@@ -313,6 +315,17 @@ length (Stream next s0 _len) = loop_length 0# s0
313315 Yield _ s' -> loop_length (z# +# 1#) s'
314316{-# INLINE[0] length #-}
315317
318+-- | /O(n)/ Returns the number of characters in a text.
319+length64 :: Stream Char -> Int64
320+length64 (Stream next s0 _len) = loop_length 0 s0
321+ where
322+ loop_length z s = case next s of
323+ Done -> z
324+ Skip s' -> loop_length z s'
325+ Yield _ s' -> let !z' = z + 1
326+ in loop_length z' s'
327+{-# INLINE[0] length64 #-}
328+
316329-- ----------------------------------------------------------------------------
317330-- * Stream transformations
318331
Data/Text/Lazy.hs+15−2
@@ -49,7 +49,7 @@ module Data.Text.Lazy
4949 , tail
5050 , init
5151 , null
52− -- , length
52+ , length
5353
5454 -- * Transformations
5555 -- , map
@@ -150,8 +150,9 @@ import Prelude (Char, Bool(..), Functor(..), Int, Maybe(..), String,
150150 Eq(..), Ord(..), (++),
151151 Read(..), Show(..),
152152 (&&), (||), (+), (-), (.), ($),
153− not, return, otherwise)
153+ fromIntegral, not, return, otherwise)
154154import qualified Prelude as P
155+import Data.Int (Int64)
155156import Data.String (IsString(..))
156157import qualified Data.Text as T
157158import qualified Data.Text.Fusion as S
@@ -295,6 +296,18 @@ null _ = False
295296 S.null (stream t) = null t
296297 #-}
297298
299+length :: Text -> Int64
300+length = foldlChunks go 0
301+ where go l t = l + fromIntegral (T.length t)
302+{-# INLINE [1] length #-}
303+
304+{-# RULES
305+"LAZY TEXT length -> fused" [~1] forall t.
306+ length t = S.length64 (stream t)
307+"LAZY TEXT length -> unfused" [1] forall t.
308+ S.length64 (stream t) = length t
309+ #-}
310+
298311-- | /O(1)/ Returns the last character of a 'Text', which must be
299312-- non-empty. Subject to array fusion.
300313last :: Text -> Char
tests/Properties.hs+6
@@ -136,7 +136,10 @@ prop_TL_init = init `eqEP` (unpackT . TL.init)
136136prop_S_null = null `eqP` S.null
137137prop_T_null = null `eqP` T.null
138138prop_TL_null = null `eqP` TL.null
139+prop_S_length = length `eqP` S.length
140+prop_S_length64 = length `eqP` (fromIntegral . S.length64)
139141prop_T_length = length `eqP` T.length
142+prop_TL_length = length `eqP` (fromIntegral . TL.length)
140143prop_T_map f = map f `eqP` (unpackT . T.map f)
141144prop_T_intercalate c = L.intercalate c `eq` (unpackT . T.intercalate (T.pack c) . map T.pack)
142145prop_T_intersperse c = L.intersperse c `eqP` (unpackT . T.intersperse c)
@@ -317,7 +320,10 @@ tests = [
317320 ("prop_S_null", mytest prop_S_null),
318321 ("prop_T_null", mytest prop_T_null),
319322 ("prop_TL_null", mytest prop_TL_null),
323+ ("prop_S_length", mytest prop_S_length),
324+ ("prop_S_length64", mytest prop_S_length64),
320325 ("prop_T_length", mytest prop_T_length),
326+ ("prop_TL_length", mytest prop_TL_length),
321327
322328 ("prop_T_map", mytest prop_T_map),
323329 ("prop_T_intercalate", mytest prop_T_intercalate),