@@ -0,0 +1,90 @@
1+{-# LANGUAGE BangPatterns, ExistentialQuantification #-}
3+-- Module : Data.Text.Fusion.Internal
4+-- Copyright : (c) Tom Harper 2008-2009,
5+-- (c) Bryan O'Sullivan 2009,
6+-- (c) Duncan Coutts 2009
9+-- Maintainer : rtharper@aftereternity.co.uk, bos@serpentine.com,
11+-- Stability : experimental
14+-- Core stream fusion functionality for text.
16+module Data.Text.Fusion.Internal
29+data PairS a b = !a :!: !b
31+-- | Allow a function over a stream to switch between two states.
38+-- The length hint in a Stream has two roles. If its value is zero,
39+-- we trust it, and treat the stream as empty. Otherwise, we treat it
40+-- as a hint: it should usually be accurate, so we use it when
41+-- unstreaming to decide what size array to allocate. However, the
42+-- unstreaming functions must be able to cope with the hint being too
43+-- small or too large.
45+-- The size hint tries to track the UTF-16 code points in a stream,
46+-- but often counts the number of characters instead. It can easily
47+-- undercount if, for instance, a transformed stream contains astral
48+-- plane characters (those above 0x10000).
52+ (s -> Step s a) -- stepper function
54+ {-# UNPACK #-}!Int -- length hint
56+-- | The empty stream.
58+empty = Stream next () 0
60+{-# INLINE [0] empty #-}
62+-- | /O(n)/ Determines if two streams are equal.
63+eq :: Ord a => Stream a -> Stream a -> Bool
65+eq (Stream next1 s1 _) (Stream next2 s2 _) = cmp (next1 s1) (next2 s2)
70+ cmp (Skip s1') (Skip s2') = cmp (next1 s1') (next2 s2')
71+ cmp (Skip s1') x2 = cmp (next1 s1') x2
72+ cmp x1 (Skip s2') = cmp x1 (next2 s2')
73+ cmp (Yield x1 s1') (Yield x2 s2') = x1 == x2 &&
74+ cmp (next1 s1') (next2 s2')
76+streamList :: [a] -> Stream a
77+{-# INLINE streamList #-}
79+streamList s = Stream next s unknownLength
81+ next (x:xs) = Yield x xs
84+unstreamList :: Stream a -> [a]
85+{-# INLINE unstreamList #-}
86+unstreamList (Stream next s0 _len) = unfold s0
87+ where unfold !s = case next s of
90+ Yield x s' -> x : unfold s'