diff --git a/Data/Text.hs b/Data/Text.hs
--- a/Data/Text.hs
+++ b/Data/Text.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE BangPatterns #-}
+{-# LANGUAGE BangPatterns, Rank2Types #-}
 {-# OPTIONS_GHC -fno-warn-orphans #-}
 
 -- |
@@ -115,6 +115,7 @@
     , splitAt
     , spanBy
     , break
+    , breakEnd
     , breakBy
     , group
     , groupBy
@@ -164,10 +165,12 @@
 import Prelude (Char, Bool(..), Functor(..), Int, Maybe(..), String,
                 Eq(..), Ord(..), (++),
                 Read(..), Show(..),
-                (&&), (||), (+), (-), (.), ($),
-                fromIntegral, div, not, return, otherwise)
+                (&&), (||), (+), (-), (.), ($), (>>), (*),
+                div, not, return, otherwise)
+import Control.DeepSeq (NFData)
 import Control.Exception (assert)
 import Data.Char (isSpace)
+import Control.Monad (foldM)
 import Control.Monad.ST (ST)
 import qualified Data.Text.Array as A
 import qualified Data.List as L
@@ -212,6 +215,8 @@
 instance IsString Text where
     fromString = pack
 
+instance NFData Text
+
 -- -----------------------------------------------------------------------------
 -- * Conversion to/from 'Text'
 
@@ -254,15 +259,10 @@
     where
       len = len1+len2
       x = do
-        arr <- A.unsafeNew len :: ST s (A.MArray s Word16)
-        copy arr1 off1 (len1+off1) arr 0
-        copy arr2 off2 (len2+off2) arr len1
+        arr <- A.unsafeNew len
+        copy arr 0 arr1 off1 len1
+        copy arr len1 arr2 off2 (len1+len2)
         return arr
-            where
-              copy arr i top arr' j
-                  | i >= top  = return ()
-                  | otherwise = do A.unsafeWrite arr' j (arr `A.unsafeIndex` i)
-                                   copy arr (i+1) top arr' (j+1)
 {-# INLINE append #-}
 
 {-# RULES
@@ -272,6 +272,14 @@
     unstream (S.append (stream t1) (stream t2)) = append t1 t2
  #-}
 
+copy :: forall s. A.MArray s Word16 -> Int -> A.Array Word16 -> Int -> Int
+     -> ST s ()
+copy dest i0 src j0 top = go i0 j0
+  where
+    go i j | i >= top  = return ()
+           | otherwise = do A.unsafeWrite dest i (src `A.unsafeIndex` j)
+                            go (i+1) (j+1)
+
 -- | /O(1)/ Returns the first character of a 'Text', which must be
 -- non-empty.  Subject to fusion.
 head :: Text -> Char
@@ -386,7 +394,7 @@
 -- 'Text's and concatenates the list after interspersing the first
 -- argument between each element of the list.
 intercalate :: Text -> [Text] -> Text
-intercalate t ts = unstream (S.intercalate (stream t) (L.map stream ts))
+intercalate t = concat . (L.intersperse t)
 {-# INLINE intercalate #-}
 
 -- | /O(n)/ The 'intersperse' function takes a character and places it
@@ -400,7 +408,7 @@
 reverse t = S.reverse (stream t)
 {-# INLINE reverse #-}
 
--- | /O(m*n)/ Replace every occurrence of one substring with another.
+-- | /O(m+n)/ Replace every occurrence of one substring with another.
 replace :: Text                 -- ^ Text to search for
         -> Text                 -- ^ Replacement text
         -> Text                 -- ^ Input text
@@ -555,18 +563,21 @@
 -- -----------------------------------------------------------------------------
 -- ** Special folds
 
--- | /O(n)/ Concatenate a list of 'Text's. Subject to fusion.
+-- | /O(n)/ Concatenate a list of 'Text's.
 concat :: [Text] -> Text
-concat ts = unstream (S.concat (L.map stream ts))
+concat ts = Text (A.run go) 0 len
+  where
+    len = L.sum (L.map (\(Text _ _ l) -> l) ts)
+    go = do
+      arr <- A.unsafeNew len
+      let step i (Text a o l) = let j = i + l in copy arr i a o j >> return j
+      foldM step 0 ts >> return arr
 {-# INLINE concat #-}
 
 -- | /O(n)/ Map a function over a 'Text' that results in a 'Text', and
--- concatenate the results.  Subject to fusion.
---
--- Note: if in 'concatMap' @f@ @t@, @f@ is defined in terms of fusible
--- functions, it will also be fusible.
+-- concatenate the results.
 concatMap :: (Char -> Text) -> Text -> Text
-concatMap f t = unstream (S.concatMap (stream . f) (stream t))
+concatMap f = concat . foldr ((:) . f) []
 {-# INLINE concatMap #-}
 
 -- | /O(n)/ 'any' @p@ @t@ determines whether any character in the
@@ -656,11 +667,21 @@
 -- ** Generating and unfolding 'Text's
 
 -- | /O(n*m)/ 'replicate' @n@ @t@ is a 'Text' consisting of the input
--- @t@ repeated @n@ times. Subject to fusion.
+-- @t@ repeated @n@ times.
 replicate :: Int -> Text -> Text
-replicate n t
-    | isSingleton t = replicateChar n (unsafeHead t)
-    | otherwise     = unstream (S.replicateI (fromIntegral n) (S.stream t))
+replicate n t@(Text a o l)
+    | n <= 0 || l <= 0 = empty
+    | n == 1           = t
+    | isSingleton t    = replicateChar n (unsafeHead t)
+    | otherwise        = Text (A.run x) 0 len
+  where
+    len = l * n
+    x = do
+      arr <- A.unsafeNew len
+      let loop !d !i | i >= n    = return arr
+                     | otherwise = let m = d + l
+                                   in copy arr d a o m >> loop m (i+1)
+      loop 0 0
 {-# INLINE [1] replicate #-}
 
 {-# RULES
@@ -1020,6 +1041,18 @@
                     (x:_) -> (textP arr off x, textP arr (off+x) (len-x))
 {-# INLINE break #-}
 
+-- | /O(n+m)/ Similar to 'break', but searches from the end of the string.
+--
+-- The first element of the returned tuple is the prefix of @haystack@
+-- up to and including the last match of @needle@.  The second is the
+-- remainder of @haystack@, following the match.
+--
+-- > breakEnd "::" "a::b::c" ==> ("a::b::", "c")
+breakEnd :: Text -> Text -> (Text, Text)
+breakEnd pat src = let (a,b) = break (reverse pat) (reverse src)
+                   in  (reverse b, reverse a)
+{-# INLINE breakEnd #-}
+
 -- | /O(n+m)/ Find all non-overlapping instances of @needle@ in
 -- @haystack@.  The first element of the returned pair is the prefix
 -- of @haystack@ prior to any matches of @needle@.  The second is a
@@ -1069,7 +1102,7 @@
 -- For example, suppose you have a string that you want to split on
 -- the substring @\"::\"@, such as @\"foo::bar::quux\"@. Instead of
 -- searching for the index of @\"::\"@ and taking the substrings
--- before and after that index, you would instead use @find "::"@.
+-- before and after that index, you would instead use @find \"::\"@.
 
 -- | /O(n)/ 'Text' index (subscript) operator, starting from 0.
 index :: Text -> Int -> Char
@@ -1151,6 +1184,7 @@
     where (h,t) = spanBy (/= '\n') ps
 {-# INLINE lines #-}
 
+{-
 -- | /O(n)/ Portably breaks a 'Text' up into a list of 'Text's at line
 -- boundaries.
 --
@@ -1158,7 +1192,6 @@
 -- return immediately followed by a line feed, or a carriage return.
 -- This accounts for both Unix and Windows line ending conventions,
 -- and for the old convention used on Mac OS 9 and earlier.
-{-
 lines' :: Text -> [Text]
 lines' ps | null ps   = []
           | otherwise = h : case uncons t of
diff --git a/Data/Text/Array.hs b/Data/Text/Array.hs
--- a/Data/Text/Array.hs
+++ b/Data/Text/Array.hs
@@ -56,10 +56,10 @@
 #if defined(__GLASGOW_HASKELL__)
 #include "MachDeps.h"
 
-import GHC.Base (ByteArray#, MutableByteArray#, Int(..), indexIntArray#,
-                 indexWord16Array#, newByteArray#, readIntArray#,
-                 readWord16Array#, unsafeCoerce#, writeIntArray#,
-                 writeWord16Array#, (+#), (*#))
+import GHC.Base (ByteArray#, MutableByteArray#, Int(..),
+                 indexWord16Array#, newByteArray#,
+                 readWord16Array#, unsafeCoerce#,
+                 writeWord16Array#, (*#))
 import GHC.Prim (Int#)
 import GHC.ST (ST(..), runST)
 import GHC.Word (Word16(..))
@@ -78,7 +78,6 @@
 
 import Control.Exception (assert)
 import Data.Typeable (Typeable1(..), Typeable2(..), TyCon, mkTyCon, mkTyConApp)
-import Data.Word (Word16)
 import Prelude hiding (length, read)
 
 #include "Typeable.h"
@@ -167,7 +166,7 @@
 #if defined(__GLASGOW_HASKELL__)
 
 wORD16_SCALE :: Int# -> Int#
-wORD16_SCALE n# = scale# *# n# where I# scale# = SIZEOF_WORD16
+wORD16_SCALE n# = scale# *# n# where !(I# scale#) = SIZEOF_WORD16
 
 -- | Create an uninitialized mutable array.
 unsafeNew :: forall s e. Elt e => Int -> ST s (MArray s e)
diff --git a/Data/Text/Encoding/Fusion.hs b/Data/Text/Encoding/Fusion.hs
--- a/Data/Text/Encoding/Fusion.hs
+++ b/Data/Text/Encoding/Fusion.hs
@@ -32,7 +32,6 @@
     ) where
 
 import Control.Exception (assert)
-import Data.ByteString as B
 import Data.ByteString.Internal (ByteString(..), mallocByteString, memcpy)
 import Data.Text.Fusion (Step(..), Stream(..))
 import Data.Text.Fusion.Size
@@ -68,7 +67,6 @@
 streamUtf8 onErr bs = Stream next 0 (maxSize l)
     where
       l = B.length bs
-      {-# INLINE next #-}
       next i
           | i >= l = Done
           | U8.validate1 x1 = Yield (unsafeChr8 x1) (i+1)
diff --git a/Data/Text/Encoding/Utf16.hs b/Data/Text/Encoding/Utf16.hs
--- a/Data/Text/Encoding/Utf16.hs
+++ b/Data/Text/Encoding/Utf16.hs
@@ -26,10 +26,10 @@
 chr2 :: Word16 -> Word16 -> Char
 chr2 (W16# a#) (W16# b#) = C# (chr# (upper# +# lower# +# 0x10000#))
     where
-      x# = word2Int# a#
-      y# = word2Int# b#
-      upper# = uncheckedIShiftL# (x# -# 0xD800#) 10#
-      lower# = y# -# 0xDC00#
+      !x# = word2Int# a#
+      !y# = word2Int# b#
+      !upper# = uncheckedIShiftL# (x# -# 0xD800#) 10#
+      !lower# = y# -# 0xDC00#
 {-# INLINE chr2 #-}
 
 validate1    :: Word16 -> Bool
diff --git a/Data/Text/Encoding/Utf8.hs b/Data/Text/Encoding/Utf8.hs
--- a/Data/Text/Encoding/Utf8.hs
+++ b/Data/Text/Encoding/Utf8.hs
@@ -73,35 +73,35 @@
 chr2       :: Word8 -> Word8 -> Char
 chr2 (W8# x1#) (W8# x2#) = C# (chr# (z1# +# z2#))
     where
-      y1# = word2Int# x1#
-      y2# = word2Int# x2#
-      z1# = uncheckedIShiftL# (y1# -# 0xC0#) 6#
-      z2# = y2# -# 0x80#
+      !y1# = word2Int# x1#
+      !y2# = word2Int# x2#
+      !z1# = uncheckedIShiftL# (y1# -# 0xC0#) 6#
+      !z2# = y2# -# 0x80#
 {-# INLINE chr2 #-}
 
 chr3          :: Word8 -> Word8 -> Word8 -> Char
 chr3 (W8# x1#) (W8# x2#) (W8# x3#) = C# (chr# (z1# +# z2# +# z3#))
     where
-      y1# = word2Int# x1#
-      y2# = word2Int# x2#
-      y3# = word2Int# x3#
-      z1# = uncheckedIShiftL# (y1# -# 0xE0#) 12#
-      z2# = uncheckedIShiftL# (y2# -# 0x80#) 6#
-      z3# = y3# -# 0x80#
+      !y1# = word2Int# x1#
+      !y2# = word2Int# x2#
+      !y3# = word2Int# x3#
+      !z1# = uncheckedIShiftL# (y1# -# 0xE0#) 12#
+      !z2# = uncheckedIShiftL# (y2# -# 0x80#) 6#
+      !z3# = y3# -# 0x80#
 {-# INLINE chr3 #-}
 
 chr4             :: Word8 -> Word8 -> Word8 -> Word8 -> Char
 chr4 (W8# x1#) (W8# x2#) (W8# x3#) (W8# x4#) =
     C# (chr# (z1# +# z2# +# z3# +# z4#))
     where
-      y1# = word2Int# x1#
-      y2# = word2Int# x2#
-      y3# = word2Int# x3#
-      y4# = word2Int# x4#
-      z1# = uncheckedIShiftL# (y1# -# 0xF0#) 18#
-      z2# = uncheckedIShiftL# (y2# -# 0x80#) 12#
-      z3# = uncheckedIShiftL# (y3# -# 0x80#) 6#
-      z4# = y4# -# 0x80#
+      !y1# = word2Int# x1#
+      !y2# = word2Int# x2#
+      !y3# = word2Int# x3#
+      !y4# = word2Int# x4#
+      !z1# = uncheckedIShiftL# (y1# -# 0xF0#) 18#
+      !z2# = uncheckedIShiftL# (y2# -# 0x80#) 12#
+      !z3# = uncheckedIShiftL# (y3# -# 0x80#) 6#
+      !z4# = y4# -# 0x80#
 {-# INLINE chr4 #-}
 
 validate1    :: Word8 -> Bool
diff --git a/Data/Text/Fusion/CaseMapping.hs b/Data/Text/Fusion/CaseMapping.hs
--- a/Data/Text/Fusion/CaseMapping.hs
+++ b/Data/Text/Fusion/CaseMapping.hs
@@ -5,452 +5,452 @@
 import Data.Char
 import Data.Text.Fusion.Internal
 
-upperMapping :: forall s. Char -> s -> Step (PairS (PairS s Char) Char) Char
+upperMapping :: forall s. Char -> s -> Step (CC s) Char
 {-# INLINE upperMapping #-}
 -- LATIN SMALL LETTER SHARP S
-upperMapping '\x00df' s = Yield '\x0053' (s :*: '\x0053' :*: '\x0000')
+upperMapping '\x00df' s = Yield '\x0053' (CC s '\x0053' '\x0000')
 -- LATIN SMALL LIGATURE FF
-upperMapping '\xfb00' s = Yield '\x0046' (s :*: '\x0046' :*: '\x0000')
+upperMapping '\xfb00' s = Yield '\x0046' (CC s '\x0046' '\x0000')
 -- LATIN SMALL LIGATURE FI
-upperMapping '\xfb01' s = Yield '\x0046' (s :*: '\x0049' :*: '\x0000')
+upperMapping '\xfb01' s = Yield '\x0046' (CC s '\x0049' '\x0000')
 -- LATIN SMALL LIGATURE FL
-upperMapping '\xfb02' s = Yield '\x0046' (s :*: '\x004c' :*: '\x0000')
+upperMapping '\xfb02' s = Yield '\x0046' (CC s '\x004c' '\x0000')
 -- LATIN SMALL LIGATURE FFI
-upperMapping '\xfb03' s = Yield '\x0046' (s :*: '\x0046' :*: '\x0049')
+upperMapping '\xfb03' s = Yield '\x0046' (CC s '\x0046' '\x0049')
 -- LATIN SMALL LIGATURE FFL
-upperMapping '\xfb04' s = Yield '\x0046' (s :*: '\x0046' :*: '\x004c')
+upperMapping '\xfb04' s = Yield '\x0046' (CC s '\x0046' '\x004c')
 -- LATIN SMALL LIGATURE LONG S T
-upperMapping '\xfb05' s = Yield '\x0053' (s :*: '\x0054' :*: '\x0000')
+upperMapping '\xfb05' s = Yield '\x0053' (CC s '\x0054' '\x0000')
 -- LATIN SMALL LIGATURE ST
-upperMapping '\xfb06' s = Yield '\x0053' (s :*: '\x0054' :*: '\x0000')
+upperMapping '\xfb06' s = Yield '\x0053' (CC s '\x0054' '\x0000')
 -- ARMENIAN SMALL LIGATURE ECH YIWN
-upperMapping '\x0587' s = Yield '\x0535' (s :*: '\x0552' :*: '\x0000')
+upperMapping '\x0587' s = Yield '\x0535' (CC s '\x0552' '\x0000')
 -- ARMENIAN SMALL LIGATURE MEN NOW
-upperMapping '\xfb13' s = Yield '\x0544' (s :*: '\x0546' :*: '\x0000')
+upperMapping '\xfb13' s = Yield '\x0544' (CC s '\x0546' '\x0000')
 -- ARMENIAN SMALL LIGATURE MEN ECH
-upperMapping '\xfb14' s = Yield '\x0544' (s :*: '\x0535' :*: '\x0000')
+upperMapping '\xfb14' s = Yield '\x0544' (CC s '\x0535' '\x0000')
 -- ARMENIAN SMALL LIGATURE MEN INI
-upperMapping '\xfb15' s = Yield '\x0544' (s :*: '\x053b' :*: '\x0000')
+upperMapping '\xfb15' s = Yield '\x0544' (CC s '\x053b' '\x0000')
 -- ARMENIAN SMALL LIGATURE VEW NOW
-upperMapping '\xfb16' s = Yield '\x054e' (s :*: '\x0546' :*: '\x0000')
+upperMapping '\xfb16' s = Yield '\x054e' (CC s '\x0546' '\x0000')
 -- ARMENIAN SMALL LIGATURE MEN XEH
-upperMapping '\xfb17' s = Yield '\x0544' (s :*: '\x053d' :*: '\x0000')
+upperMapping '\xfb17' s = Yield '\x0544' (CC s '\x053d' '\x0000')
 -- LATIN SMALL LETTER N PRECEDED BY APOSTROPHE
-upperMapping '\x0149' s = Yield '\x02bc' (s :*: '\x004e' :*: '\x0000')
+upperMapping '\x0149' s = Yield '\x02bc' (CC s '\x004e' '\x0000')
 -- GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS
-upperMapping '\x0390' s = Yield '\x0399' (s :*: '\x0308' :*: '\x0301')
+upperMapping '\x0390' s = Yield '\x0399' (CC s '\x0308' '\x0301')
 -- GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS
-upperMapping '\x03b0' s = Yield '\x03a5' (s :*: '\x0308' :*: '\x0301')
+upperMapping '\x03b0' s = Yield '\x03a5' (CC s '\x0308' '\x0301')
 -- LATIN SMALL LETTER J WITH CARON
-upperMapping '\x01f0' s = Yield '\x004a' (s :*: '\x030c' :*: '\x0000')
+upperMapping '\x01f0' s = Yield '\x004a' (CC s '\x030c' '\x0000')
 -- LATIN SMALL LETTER H WITH LINE BELOW
-upperMapping '\x1e96' s = Yield '\x0048' (s :*: '\x0331' :*: '\x0000')
+upperMapping '\x1e96' s = Yield '\x0048' (CC s '\x0331' '\x0000')
 -- LATIN SMALL LETTER T WITH DIAERESIS
-upperMapping '\x1e97' s = Yield '\x0054' (s :*: '\x0308' :*: '\x0000')
+upperMapping '\x1e97' s = Yield '\x0054' (CC s '\x0308' '\x0000')
 -- LATIN SMALL LETTER W WITH RING ABOVE
-upperMapping '\x1e98' s = Yield '\x0057' (s :*: '\x030a' :*: '\x0000')
+upperMapping '\x1e98' s = Yield '\x0057' (CC s '\x030a' '\x0000')
 -- LATIN SMALL LETTER Y WITH RING ABOVE
-upperMapping '\x1e99' s = Yield '\x0059' (s :*: '\x030a' :*: '\x0000')
+upperMapping '\x1e99' s = Yield '\x0059' (CC s '\x030a' '\x0000')
 -- LATIN SMALL LETTER A WITH RIGHT HALF RING
-upperMapping '\x1e9a' s = Yield '\x0041' (s :*: '\x02be' :*: '\x0000')
+upperMapping '\x1e9a' s = Yield '\x0041' (CC s '\x02be' '\x0000')
 -- GREEK SMALL LETTER UPSILON WITH PSILI
-upperMapping '\x1f50' s = Yield '\x03a5' (s :*: '\x0313' :*: '\x0000')
+upperMapping '\x1f50' s = Yield '\x03a5' (CC s '\x0313' '\x0000')
 -- GREEK SMALL LETTER UPSILON WITH PSILI AND VARIA
-upperMapping '\x1f52' s = Yield '\x03a5' (s :*: '\x0313' :*: '\x0300')
+upperMapping '\x1f52' s = Yield '\x03a5' (CC s '\x0313' '\x0300')
 -- GREEK SMALL LETTER UPSILON WITH PSILI AND OXIA
-upperMapping '\x1f54' s = Yield '\x03a5' (s :*: '\x0313' :*: '\x0301')
+upperMapping '\x1f54' s = Yield '\x03a5' (CC s '\x0313' '\x0301')
 -- GREEK SMALL LETTER UPSILON WITH PSILI AND PERISPOMENI
-upperMapping '\x1f56' s = Yield '\x03a5' (s :*: '\x0313' :*: '\x0342')
+upperMapping '\x1f56' s = Yield '\x03a5' (CC s '\x0313' '\x0342')
 -- GREEK SMALL LETTER ALPHA WITH PERISPOMENI
-upperMapping '\x1fb6' s = Yield '\x0391' (s :*: '\x0342' :*: '\x0000')
+upperMapping '\x1fb6' s = Yield '\x0391' (CC s '\x0342' '\x0000')
 -- GREEK SMALL LETTER ETA WITH PERISPOMENI
-upperMapping '\x1fc6' s = Yield '\x0397' (s :*: '\x0342' :*: '\x0000')
+upperMapping '\x1fc6' s = Yield '\x0397' (CC s '\x0342' '\x0000')
 -- GREEK SMALL LETTER IOTA WITH DIALYTIKA AND VARIA
-upperMapping '\x1fd2' s = Yield '\x0399' (s :*: '\x0308' :*: '\x0300')
+upperMapping '\x1fd2' s = Yield '\x0399' (CC s '\x0308' '\x0300')
 -- GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA
-upperMapping '\x1fd3' s = Yield '\x0399' (s :*: '\x0308' :*: '\x0301')
+upperMapping '\x1fd3' s = Yield '\x0399' (CC s '\x0308' '\x0301')
 -- GREEK SMALL LETTER IOTA WITH PERISPOMENI
-upperMapping '\x1fd6' s = Yield '\x0399' (s :*: '\x0342' :*: '\x0000')
+upperMapping '\x1fd6' s = Yield '\x0399' (CC s '\x0342' '\x0000')
 -- GREEK SMALL LETTER IOTA WITH DIALYTIKA AND PERISPOMENI
-upperMapping '\x1fd7' s = Yield '\x0399' (s :*: '\x0308' :*: '\x0342')
+upperMapping '\x1fd7' s = Yield '\x0399' (CC s '\x0308' '\x0342')
 -- GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND VARIA
-upperMapping '\x1fe2' s = Yield '\x03a5' (s :*: '\x0308' :*: '\x0300')
+upperMapping '\x1fe2' s = Yield '\x03a5' (CC s '\x0308' '\x0300')
 -- GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND OXIA
-upperMapping '\x1fe3' s = Yield '\x03a5' (s :*: '\x0308' :*: '\x0301')
+upperMapping '\x1fe3' s = Yield '\x03a5' (CC s '\x0308' '\x0301')
 -- GREEK SMALL LETTER RHO WITH PSILI
-upperMapping '\x1fe4' s = Yield '\x03a1' (s :*: '\x0313' :*: '\x0000')
+upperMapping '\x1fe4' s = Yield '\x03a1' (CC s '\x0313' '\x0000')
 -- GREEK SMALL LETTER UPSILON WITH PERISPOMENI
-upperMapping '\x1fe6' s = Yield '\x03a5' (s :*: '\x0342' :*: '\x0000')
+upperMapping '\x1fe6' s = Yield '\x03a5' (CC s '\x0342' '\x0000')
 -- GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND PERISPOMENI
-upperMapping '\x1fe7' s = Yield '\x03a5' (s :*: '\x0308' :*: '\x0342')
+upperMapping '\x1fe7' s = Yield '\x03a5' (CC s '\x0308' '\x0342')
 -- GREEK SMALL LETTER OMEGA WITH PERISPOMENI
-upperMapping '\x1ff6' s = Yield '\x03a9' (s :*: '\x0342' :*: '\x0000')
+upperMapping '\x1ff6' s = Yield '\x03a9' (CC s '\x0342' '\x0000')
 -- GREEK SMALL LETTER ALPHA WITH PSILI AND YPOGEGRAMMENI
-upperMapping '\x1f80' s = Yield '\x1f08' (s :*: '\x0399' :*: '\x0000')
+upperMapping '\x1f80' s = Yield '\x1f08' (CC s '\x0399' '\x0000')
 -- GREEK SMALL LETTER ALPHA WITH DASIA AND YPOGEGRAMMENI
-upperMapping '\x1f81' s = Yield '\x1f09' (s :*: '\x0399' :*: '\x0000')
+upperMapping '\x1f81' s = Yield '\x1f09' (CC s '\x0399' '\x0000')
 -- GREEK SMALL LETTER ALPHA WITH PSILI AND VARIA AND YPOGEGRAMMENI
-upperMapping '\x1f82' s = Yield '\x1f0a' (s :*: '\x0399' :*: '\x0000')
+upperMapping '\x1f82' s = Yield '\x1f0a' (CC s '\x0399' '\x0000')
 -- GREEK SMALL LETTER ALPHA WITH DASIA AND VARIA AND YPOGEGRAMMENI
-upperMapping '\x1f83' s = Yield '\x1f0b' (s :*: '\x0399' :*: '\x0000')
+upperMapping '\x1f83' s = Yield '\x1f0b' (CC s '\x0399' '\x0000')
 -- GREEK SMALL LETTER ALPHA WITH PSILI AND OXIA AND YPOGEGRAMMENI
-upperMapping '\x1f84' s = Yield '\x1f0c' (s :*: '\x0399' :*: '\x0000')
+upperMapping '\x1f84' s = Yield '\x1f0c' (CC s '\x0399' '\x0000')
 -- GREEK SMALL LETTER ALPHA WITH DASIA AND OXIA AND YPOGEGRAMMENI
-upperMapping '\x1f85' s = Yield '\x1f0d' (s :*: '\x0399' :*: '\x0000')
+upperMapping '\x1f85' s = Yield '\x1f0d' (CC s '\x0399' '\x0000')
 -- GREEK SMALL LETTER ALPHA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI
-upperMapping '\x1f86' s = Yield '\x1f0e' (s :*: '\x0399' :*: '\x0000')
+upperMapping '\x1f86' s = Yield '\x1f0e' (CC s '\x0399' '\x0000')
 -- GREEK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI
-upperMapping '\x1f87' s = Yield '\x1f0f' (s :*: '\x0399' :*: '\x0000')
+upperMapping '\x1f87' s = Yield '\x1f0f' (CC s '\x0399' '\x0000')
 -- GREEK CAPITAL LETTER ALPHA WITH PSILI AND PROSGEGRAMMENI
-upperMapping '\x1f88' s = Yield '\x1f08' (s :*: '\x0399' :*: '\x0000')
+upperMapping '\x1f88' s = Yield '\x1f08' (CC s '\x0399' '\x0000')
 -- GREEK CAPITAL LETTER ALPHA WITH DASIA AND PROSGEGRAMMENI
-upperMapping '\x1f89' s = Yield '\x1f09' (s :*: '\x0399' :*: '\x0000')
+upperMapping '\x1f89' s = Yield '\x1f09' (CC s '\x0399' '\x0000')
 -- GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA AND PROSGEGRAMMENI
-upperMapping '\x1f8a' s = Yield '\x1f0a' (s :*: '\x0399' :*: '\x0000')
+upperMapping '\x1f8a' s = Yield '\x1f0a' (CC s '\x0399' '\x0000')
 -- GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA AND PROSGEGRAMMENI
-upperMapping '\x1f8b' s = Yield '\x1f0b' (s :*: '\x0399' :*: '\x0000')
+upperMapping '\x1f8b' s = Yield '\x1f0b' (CC s '\x0399' '\x0000')
 -- GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA AND PROSGEGRAMMENI
-upperMapping '\x1f8c' s = Yield '\x1f0c' (s :*: '\x0399' :*: '\x0000')
+upperMapping '\x1f8c' s = Yield '\x1f0c' (CC s '\x0399' '\x0000')
 -- GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA AND PROSGEGRAMMENI
-upperMapping '\x1f8d' s = Yield '\x1f0d' (s :*: '\x0399' :*: '\x0000')
+upperMapping '\x1f8d' s = Yield '\x1f0d' (CC s '\x0399' '\x0000')
 -- GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI
-upperMapping '\x1f8e' s = Yield '\x1f0e' (s :*: '\x0399' :*: '\x0000')
+upperMapping '\x1f8e' s = Yield '\x1f0e' (CC s '\x0399' '\x0000')
 -- GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI
-upperMapping '\x1f8f' s = Yield '\x1f0f' (s :*: '\x0399' :*: '\x0000')
+upperMapping '\x1f8f' s = Yield '\x1f0f' (CC s '\x0399' '\x0000')
 -- GREEK SMALL LETTER ETA WITH PSILI AND YPOGEGRAMMENI
-upperMapping '\x1f90' s = Yield '\x1f28' (s :*: '\x0399' :*: '\x0000')
+upperMapping '\x1f90' s = Yield '\x1f28' (CC s '\x0399' '\x0000')
 -- GREEK SMALL LETTER ETA WITH DASIA AND YPOGEGRAMMENI
-upperMapping '\x1f91' s = Yield '\x1f29' (s :*: '\x0399' :*: '\x0000')
+upperMapping '\x1f91' s = Yield '\x1f29' (CC s '\x0399' '\x0000')
 -- GREEK SMALL LETTER ETA WITH PSILI AND VARIA AND YPOGEGRAMMENI
-upperMapping '\x1f92' s = Yield '\x1f2a' (s :*: '\x0399' :*: '\x0000')
+upperMapping '\x1f92' s = Yield '\x1f2a' (CC s '\x0399' '\x0000')
 -- GREEK SMALL LETTER ETA WITH DASIA AND VARIA AND YPOGEGRAMMENI
-upperMapping '\x1f93' s = Yield '\x1f2b' (s :*: '\x0399' :*: '\x0000')
+upperMapping '\x1f93' s = Yield '\x1f2b' (CC s '\x0399' '\x0000')
 -- GREEK SMALL LETTER ETA WITH PSILI AND OXIA AND YPOGEGRAMMENI
-upperMapping '\x1f94' s = Yield '\x1f2c' (s :*: '\x0399' :*: '\x0000')
+upperMapping '\x1f94' s = Yield '\x1f2c' (CC s '\x0399' '\x0000')
 -- GREEK SMALL LETTER ETA WITH DASIA AND OXIA AND YPOGEGRAMMENI
-upperMapping '\x1f95' s = Yield '\x1f2d' (s :*: '\x0399' :*: '\x0000')
+upperMapping '\x1f95' s = Yield '\x1f2d' (CC s '\x0399' '\x0000')
 -- GREEK SMALL LETTER ETA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI
-upperMapping '\x1f96' s = Yield '\x1f2e' (s :*: '\x0399' :*: '\x0000')
+upperMapping '\x1f96' s = Yield '\x1f2e' (CC s '\x0399' '\x0000')
 -- GREEK SMALL LETTER ETA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI
-upperMapping '\x1f97' s = Yield '\x1f2f' (s :*: '\x0399' :*: '\x0000')
+upperMapping '\x1f97' s = Yield '\x1f2f' (CC s '\x0399' '\x0000')
 -- GREEK CAPITAL LETTER ETA WITH PSILI AND PROSGEGRAMMENI
-upperMapping '\x1f98' s = Yield '\x1f28' (s :*: '\x0399' :*: '\x0000')
+upperMapping '\x1f98' s = Yield '\x1f28' (CC s '\x0399' '\x0000')
 -- GREEK CAPITAL LETTER ETA WITH DASIA AND PROSGEGRAMMENI
-upperMapping '\x1f99' s = Yield '\x1f29' (s :*: '\x0399' :*: '\x0000')
+upperMapping '\x1f99' s = Yield '\x1f29' (CC s '\x0399' '\x0000')
 -- GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA AND PROSGEGRAMMENI
-upperMapping '\x1f9a' s = Yield '\x1f2a' (s :*: '\x0399' :*: '\x0000')
+upperMapping '\x1f9a' s = Yield '\x1f2a' (CC s '\x0399' '\x0000')
 -- GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA AND PROSGEGRAMMENI
-upperMapping '\x1f9b' s = Yield '\x1f2b' (s :*: '\x0399' :*: '\x0000')
+upperMapping '\x1f9b' s = Yield '\x1f2b' (CC s '\x0399' '\x0000')
 -- GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA AND PROSGEGRAMMENI
-upperMapping '\x1f9c' s = Yield '\x1f2c' (s :*: '\x0399' :*: '\x0000')
+upperMapping '\x1f9c' s = Yield '\x1f2c' (CC s '\x0399' '\x0000')
 -- GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA AND PROSGEGRAMMENI
-upperMapping '\x1f9d' s = Yield '\x1f2d' (s :*: '\x0399' :*: '\x0000')
+upperMapping '\x1f9d' s = Yield '\x1f2d' (CC s '\x0399' '\x0000')
 -- GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI
-upperMapping '\x1f9e' s = Yield '\x1f2e' (s :*: '\x0399' :*: '\x0000')
+upperMapping '\x1f9e' s = Yield '\x1f2e' (CC s '\x0399' '\x0000')
 -- GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI
-upperMapping '\x1f9f' s = Yield '\x1f2f' (s :*: '\x0399' :*: '\x0000')
+upperMapping '\x1f9f' s = Yield '\x1f2f' (CC s '\x0399' '\x0000')
 -- GREEK SMALL LETTER OMEGA WITH PSILI AND YPOGEGRAMMENI
-upperMapping '\x1fa0' s = Yield '\x1f68' (s :*: '\x0399' :*: '\x0000')
+upperMapping '\x1fa0' s = Yield '\x1f68' (CC s '\x0399' '\x0000')
 -- GREEK SMALL LETTER OMEGA WITH DASIA AND YPOGEGRAMMENI
-upperMapping '\x1fa1' s = Yield '\x1f69' (s :*: '\x0399' :*: '\x0000')
+upperMapping '\x1fa1' s = Yield '\x1f69' (CC s '\x0399' '\x0000')
 -- GREEK SMALL LETTER OMEGA WITH PSILI AND VARIA AND YPOGEGRAMMENI
-upperMapping '\x1fa2' s = Yield '\x1f6a' (s :*: '\x0399' :*: '\x0000')
+upperMapping '\x1fa2' s = Yield '\x1f6a' (CC s '\x0399' '\x0000')
 -- GREEK SMALL LETTER OMEGA WITH DASIA AND VARIA AND YPOGEGRAMMENI
-upperMapping '\x1fa3' s = Yield '\x1f6b' (s :*: '\x0399' :*: '\x0000')
+upperMapping '\x1fa3' s = Yield '\x1f6b' (CC s '\x0399' '\x0000')
 -- GREEK SMALL LETTER OMEGA WITH PSILI AND OXIA AND YPOGEGRAMMENI
-upperMapping '\x1fa4' s = Yield '\x1f6c' (s :*: '\x0399' :*: '\x0000')
+upperMapping '\x1fa4' s = Yield '\x1f6c' (CC s '\x0399' '\x0000')
 -- GREEK SMALL LETTER OMEGA WITH DASIA AND OXIA AND YPOGEGRAMMENI
-upperMapping '\x1fa5' s = Yield '\x1f6d' (s :*: '\x0399' :*: '\x0000')
+upperMapping '\x1fa5' s = Yield '\x1f6d' (CC s '\x0399' '\x0000')
 -- GREEK SMALL LETTER OMEGA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI
-upperMapping '\x1fa6' s = Yield '\x1f6e' (s :*: '\x0399' :*: '\x0000')
+upperMapping '\x1fa6' s = Yield '\x1f6e' (CC s '\x0399' '\x0000')
 -- GREEK SMALL LETTER OMEGA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI
-upperMapping '\x1fa7' s = Yield '\x1f6f' (s :*: '\x0399' :*: '\x0000')
+upperMapping '\x1fa7' s = Yield '\x1f6f' (CC s '\x0399' '\x0000')
 -- GREEK CAPITAL LETTER OMEGA WITH PSILI AND PROSGEGRAMMENI
-upperMapping '\x1fa8' s = Yield '\x1f68' (s :*: '\x0399' :*: '\x0000')
+upperMapping '\x1fa8' s = Yield '\x1f68' (CC s '\x0399' '\x0000')
 -- GREEK CAPITAL LETTER OMEGA WITH DASIA AND PROSGEGRAMMENI
-upperMapping '\x1fa9' s = Yield '\x1f69' (s :*: '\x0399' :*: '\x0000')
+upperMapping '\x1fa9' s = Yield '\x1f69' (CC s '\x0399' '\x0000')
 -- GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA AND PROSGEGRAMMENI
-upperMapping '\x1faa' s = Yield '\x1f6a' (s :*: '\x0399' :*: '\x0000')
+upperMapping '\x1faa' s = Yield '\x1f6a' (CC s '\x0399' '\x0000')
 -- GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA AND PROSGEGRAMMENI
-upperMapping '\x1fab' s = Yield '\x1f6b' (s :*: '\x0399' :*: '\x0000')
+upperMapping '\x1fab' s = Yield '\x1f6b' (CC s '\x0399' '\x0000')
 -- GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA AND PROSGEGRAMMENI
-upperMapping '\x1fac' s = Yield '\x1f6c' (s :*: '\x0399' :*: '\x0000')
+upperMapping '\x1fac' s = Yield '\x1f6c' (CC s '\x0399' '\x0000')
 -- GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA AND PROSGEGRAMMENI
-upperMapping '\x1fad' s = Yield '\x1f6d' (s :*: '\x0399' :*: '\x0000')
+upperMapping '\x1fad' s = Yield '\x1f6d' (CC s '\x0399' '\x0000')
 -- GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI
-upperMapping '\x1fae' s = Yield '\x1f6e' (s :*: '\x0399' :*: '\x0000')
+upperMapping '\x1fae' s = Yield '\x1f6e' (CC s '\x0399' '\x0000')
 -- GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI
-upperMapping '\x1faf' s = Yield '\x1f6f' (s :*: '\x0399' :*: '\x0000')
+upperMapping '\x1faf' s = Yield '\x1f6f' (CC s '\x0399' '\x0000')
 -- GREEK SMALL LETTER ALPHA WITH YPOGEGRAMMENI
-upperMapping '\x1fb3' s = Yield '\x0391' (s :*: '\x0399' :*: '\x0000')
+upperMapping '\x1fb3' s = Yield '\x0391' (CC s '\x0399' '\x0000')
 -- GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI
-upperMapping '\x1fbc' s = Yield '\x0391' (s :*: '\x0399' :*: '\x0000')
+upperMapping '\x1fbc' s = Yield '\x0391' (CC s '\x0399' '\x0000')
 -- GREEK SMALL LETTER ETA WITH YPOGEGRAMMENI
-upperMapping '\x1fc3' s = Yield '\x0397' (s :*: '\x0399' :*: '\x0000')
+upperMapping '\x1fc3' s = Yield '\x0397' (CC s '\x0399' '\x0000')
 -- GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI
-upperMapping '\x1fcc' s = Yield '\x0397' (s :*: '\x0399' :*: '\x0000')
+upperMapping '\x1fcc' s = Yield '\x0397' (CC s '\x0399' '\x0000')
 -- GREEK SMALL LETTER OMEGA WITH YPOGEGRAMMENI
-upperMapping '\x1ff3' s = Yield '\x03a9' (s :*: '\x0399' :*: '\x0000')
+upperMapping '\x1ff3' s = Yield '\x03a9' (CC s '\x0399' '\x0000')
 -- GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI
-upperMapping '\x1ffc' s = Yield '\x03a9' (s :*: '\x0399' :*: '\x0000')
+upperMapping '\x1ffc' s = Yield '\x03a9' (CC s '\x0399' '\x0000')
 -- GREEK SMALL LETTER ALPHA WITH VARIA AND YPOGEGRAMMENI
-upperMapping '\x1fb2' s = Yield '\x1fba' (s :*: '\x0399' :*: '\x0000')
+upperMapping '\x1fb2' s = Yield '\x1fba' (CC s '\x0399' '\x0000')
 -- GREEK SMALL LETTER ALPHA WITH OXIA AND YPOGEGRAMMENI
-upperMapping '\x1fb4' s = Yield '\x0386' (s :*: '\x0399' :*: '\x0000')
+upperMapping '\x1fb4' s = Yield '\x0386' (CC s '\x0399' '\x0000')
 -- GREEK SMALL LETTER ETA WITH VARIA AND YPOGEGRAMMENI
-upperMapping '\x1fc2' s = Yield '\x1fca' (s :*: '\x0399' :*: '\x0000')
+upperMapping '\x1fc2' s = Yield '\x1fca' (CC s '\x0399' '\x0000')
 -- GREEK SMALL LETTER ETA WITH OXIA AND YPOGEGRAMMENI
-upperMapping '\x1fc4' s = Yield '\x0389' (s :*: '\x0399' :*: '\x0000')
+upperMapping '\x1fc4' s = Yield '\x0389' (CC s '\x0399' '\x0000')
 -- GREEK SMALL LETTER OMEGA WITH VARIA AND YPOGEGRAMMENI
-upperMapping '\x1ff2' s = Yield '\x1ffa' (s :*: '\x0399' :*: '\x0000')
+upperMapping '\x1ff2' s = Yield '\x1ffa' (CC s '\x0399' '\x0000')
 -- GREEK SMALL LETTER OMEGA WITH OXIA AND YPOGEGRAMMENI
-upperMapping '\x1ff4' s = Yield '\x038f' (s :*: '\x0399' :*: '\x0000')
+upperMapping '\x1ff4' s = Yield '\x038f' (CC s '\x0399' '\x0000')
 -- GREEK SMALL LETTER ALPHA WITH PERISPOMENI AND YPOGEGRAMMENI
-upperMapping '\x1fb7' s = Yield '\x0391' (s :*: '\x0342' :*: '\x0399')
+upperMapping '\x1fb7' s = Yield '\x0391' (CC s '\x0342' '\x0399')
 -- GREEK SMALL LETTER ETA WITH PERISPOMENI AND YPOGEGRAMMENI
-upperMapping '\x1fc7' s = Yield '\x0397' (s :*: '\x0342' :*: '\x0399')
+upperMapping '\x1fc7' s = Yield '\x0397' (CC s '\x0342' '\x0399')
 -- GREEK SMALL LETTER OMEGA WITH PERISPOMENI AND YPOGEGRAMMENI
-upperMapping '\x1ff7' s = Yield '\x03a9' (s :*: '\x0342' :*: '\x0399')
-upperMapping c s = Yield (toUpper c) (s :*: '\0' :*: '\0')
-lowerMapping :: forall s. Char -> s -> Step (PairS (PairS s Char) Char) Char
+upperMapping '\x1ff7' s = Yield '\x03a9' (CC s '\x0342' '\x0399')
+upperMapping c s = Yield (toUpper c) (CC s '\0' '\0')
+lowerMapping :: forall s. Char -> s -> Step (CC s) Char
 {-# INLINE lowerMapping #-}
 -- LATIN CAPITAL LETTER I WITH DOT ABOVE
-lowerMapping '\x0130' s = Yield '\x0069' (s :*: '\x0307' :*: '\x0000')
-lowerMapping c s = Yield (toLower c) (s :*: '\0' :*: '\0')
-foldMapping :: forall s. Char -> s -> Step (PairS (PairS s Char) Char) Char
+lowerMapping '\x0130' s = Yield '\x0069' (CC s '\x0307' '\x0000')
+lowerMapping c s = Yield (toLower c) (CC s '\0' '\0')
+foldMapping :: forall s. Char -> s -> Step (CC s) Char
 {-# INLINE foldMapping #-}
 -- MICRO SIGN
-foldMapping '\x00b5' s = Yield '\x03bc' (s :*: '\x0000' :*: '\x0000')
+foldMapping '\x00b5' s = Yield '\x03bc' (CC s '\x0000' '\x0000')
 -- LATIN SMALL LETTER SHARP S
-foldMapping '\x00df' s = Yield '\x0073' (s :*: '\x0073' :*: '\x0000')
+foldMapping '\x00df' s = Yield '\x0073' (CC s '\x0073' '\x0000')
 -- LATIN CAPITAL LETTER I WITH DOT ABOVE
-foldMapping '\x0130' s = Yield '\x0069' (s :*: '\x0307' :*: '\x0000')
+foldMapping '\x0130' s = Yield '\x0069' (CC s '\x0307' '\x0000')
 -- LATIN SMALL LETTER N PRECEDED BY APOSTROPHE
-foldMapping '\x0149' s = Yield '\x02bc' (s :*: '\x006e' :*: '\x0000')
+foldMapping '\x0149' s = Yield '\x02bc' (CC s '\x006e' '\x0000')
 -- LATIN SMALL LETTER LONG S
-foldMapping '\x017f' s = Yield '\x0073' (s :*: '\x0000' :*: '\x0000')
+foldMapping '\x017f' s = Yield '\x0073' (CC s '\x0000' '\x0000')
 -- LATIN SMALL LETTER J WITH CARON
-foldMapping '\x01f0' s = Yield '\x006a' (s :*: '\x030c' :*: '\x0000')
+foldMapping '\x01f0' s = Yield '\x006a' (CC s '\x030c' '\x0000')
 -- COMBINING GREEK YPOGEGRAMMENI
-foldMapping '\x0345' s = Yield '\x03b9' (s :*: '\x0000' :*: '\x0000')
+foldMapping '\x0345' s = Yield '\x03b9' (CC s '\x0000' '\x0000')
 -- GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS
-foldMapping '\x0390' s = Yield '\x03b9' (s :*: '\x0308' :*: '\x0301')
+foldMapping '\x0390' s = Yield '\x03b9' (CC s '\x0308' '\x0301')
 -- GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS
-foldMapping '\x03b0' s = Yield '\x03c5' (s :*: '\x0308' :*: '\x0301')
+foldMapping '\x03b0' s = Yield '\x03c5' (CC s '\x0308' '\x0301')
 -- GREEK SMALL LETTER FINAL SIGMA
-foldMapping '\x03c2' s = Yield '\x03c3' (s :*: '\x0000' :*: '\x0000')
+foldMapping '\x03c2' s = Yield '\x03c3' (CC s '\x0000' '\x0000')
 -- GREEK BETA SYMBOL
-foldMapping '\x03d0' s = Yield '\x03b2' (s :*: '\x0000' :*: '\x0000')
+foldMapping '\x03d0' s = Yield '\x03b2' (CC s '\x0000' '\x0000')
 -- GREEK THETA SYMBOL
-foldMapping '\x03d1' s = Yield '\x03b8' (s :*: '\x0000' :*: '\x0000')
+foldMapping '\x03d1' s = Yield '\x03b8' (CC s '\x0000' '\x0000')
 -- GREEK PHI SYMBOL
-foldMapping '\x03d5' s = Yield '\x03c6' (s :*: '\x0000' :*: '\x0000')
+foldMapping '\x03d5' s = Yield '\x03c6' (CC s '\x0000' '\x0000')
 -- GREEK PI SYMBOL
-foldMapping '\x03d6' s = Yield '\x03c0' (s :*: '\x0000' :*: '\x0000')
+foldMapping '\x03d6' s = Yield '\x03c0' (CC s '\x0000' '\x0000')
 -- GREEK KAPPA SYMBOL
-foldMapping '\x03f0' s = Yield '\x03ba' (s :*: '\x0000' :*: '\x0000')
+foldMapping '\x03f0' s = Yield '\x03ba' (CC s '\x0000' '\x0000')
 -- GREEK RHO SYMBOL
-foldMapping '\x03f1' s = Yield '\x03c1' (s :*: '\x0000' :*: '\x0000')
+foldMapping '\x03f1' s = Yield '\x03c1' (CC s '\x0000' '\x0000')
 -- GREEK LUNATE EPSILON SYMBOL
-foldMapping '\x03f5' s = Yield '\x03b5' (s :*: '\x0000' :*: '\x0000')
+foldMapping '\x03f5' s = Yield '\x03b5' (CC s '\x0000' '\x0000')
 -- ARMENIAN SMALL LIGATURE ECH YIWN
-foldMapping '\x0587' s = Yield '\x0565' (s :*: '\x0582' :*: '\x0000')
+foldMapping '\x0587' s = Yield '\x0565' (CC s '\x0582' '\x0000')
 -- LATIN SMALL LETTER H WITH LINE BELOW
-foldMapping '\x1e96' s = Yield '\x0068' (s :*: '\x0331' :*: '\x0000')
+foldMapping '\x1e96' s = Yield '\x0068' (CC s '\x0331' '\x0000')
 -- LATIN SMALL LETTER T WITH DIAERESIS
-foldMapping '\x1e97' s = Yield '\x0074' (s :*: '\x0308' :*: '\x0000')
+foldMapping '\x1e97' s = Yield '\x0074' (CC s '\x0308' '\x0000')
 -- LATIN SMALL LETTER W WITH RING ABOVE
-foldMapping '\x1e98' s = Yield '\x0077' (s :*: '\x030a' :*: '\x0000')
+foldMapping '\x1e98' s = Yield '\x0077' (CC s '\x030a' '\x0000')
 -- LATIN SMALL LETTER Y WITH RING ABOVE
-foldMapping '\x1e99' s = Yield '\x0079' (s :*: '\x030a' :*: '\x0000')
+foldMapping '\x1e99' s = Yield '\x0079' (CC s '\x030a' '\x0000')
 -- LATIN SMALL LETTER A WITH RIGHT HALF RING
-foldMapping '\x1e9a' s = Yield '\x0061' (s :*: '\x02be' :*: '\x0000')
+foldMapping '\x1e9a' s = Yield '\x0061' (CC s '\x02be' '\x0000')
 -- LATIN SMALL LETTER LONG S WITH DOT ABOVE
-foldMapping '\x1e9b' s = Yield '\x1e61' (s :*: '\x0000' :*: '\x0000')
+foldMapping '\x1e9b' s = Yield '\x1e61' (CC s '\x0000' '\x0000')
 -- LATIN CAPITAL LETTER SHARP S
-foldMapping '\x1e9e' s = Yield '\x0073' (s :*: '\x0073' :*: '\x0000')
+foldMapping '\x1e9e' s = Yield '\x0073' (CC s '\x0073' '\x0000')
 -- GREEK SMALL LETTER UPSILON WITH PSILI
-foldMapping '\x1f50' s = Yield '\x03c5' (s :*: '\x0313' :*: '\x0000')
+foldMapping '\x1f50' s = Yield '\x03c5' (CC s '\x0313' '\x0000')
 -- GREEK SMALL LETTER UPSILON WITH PSILI AND VARIA
-foldMapping '\x1f52' s = Yield '\x03c5' (s :*: '\x0313' :*: '\x0300')
+foldMapping '\x1f52' s = Yield '\x03c5' (CC s '\x0313' '\x0300')
 -- GREEK SMALL LETTER UPSILON WITH PSILI AND OXIA
-foldMapping '\x1f54' s = Yield '\x03c5' (s :*: '\x0313' :*: '\x0301')
+foldMapping '\x1f54' s = Yield '\x03c5' (CC s '\x0313' '\x0301')
 -- GREEK SMALL LETTER UPSILON WITH PSILI AND PERISPOMENI
-foldMapping '\x1f56' s = Yield '\x03c5' (s :*: '\x0313' :*: '\x0342')
+foldMapping '\x1f56' s = Yield '\x03c5' (CC s '\x0313' '\x0342')
 -- GREEK SMALL LETTER ALPHA WITH PSILI AND YPOGEGRAMMENI
-foldMapping '\x1f80' s = Yield '\x1f00' (s :*: '\x03b9' :*: '\x0000')
+foldMapping '\x1f80' s = Yield '\x1f00' (CC s '\x03b9' '\x0000')
 -- GREEK SMALL LETTER ALPHA WITH DASIA AND YPOGEGRAMMENI
-foldMapping '\x1f81' s = Yield '\x1f01' (s :*: '\x03b9' :*: '\x0000')
+foldMapping '\x1f81' s = Yield '\x1f01' (CC s '\x03b9' '\x0000')
 -- GREEK SMALL LETTER ALPHA WITH PSILI AND VARIA AND YPOGEGRAMMENI
-foldMapping '\x1f82' s = Yield '\x1f02' (s :*: '\x03b9' :*: '\x0000')
+foldMapping '\x1f82' s = Yield '\x1f02' (CC s '\x03b9' '\x0000')
 -- GREEK SMALL LETTER ALPHA WITH DASIA AND VARIA AND YPOGEGRAMMENI
-foldMapping '\x1f83' s = Yield '\x1f03' (s :*: '\x03b9' :*: '\x0000')
+foldMapping '\x1f83' s = Yield '\x1f03' (CC s '\x03b9' '\x0000')
 -- GREEK SMALL LETTER ALPHA WITH PSILI AND OXIA AND YPOGEGRAMMENI
-foldMapping '\x1f84' s = Yield '\x1f04' (s :*: '\x03b9' :*: '\x0000')
+foldMapping '\x1f84' s = Yield '\x1f04' (CC s '\x03b9' '\x0000')
 -- GREEK SMALL LETTER ALPHA WITH DASIA AND OXIA AND YPOGEGRAMMENI
-foldMapping '\x1f85' s = Yield '\x1f05' (s :*: '\x03b9' :*: '\x0000')
+foldMapping '\x1f85' s = Yield '\x1f05' (CC s '\x03b9' '\x0000')
 -- GREEK SMALL LETTER ALPHA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI
-foldMapping '\x1f86' s = Yield '\x1f06' (s :*: '\x03b9' :*: '\x0000')
+foldMapping '\x1f86' s = Yield '\x1f06' (CC s '\x03b9' '\x0000')
 -- GREEK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI
-foldMapping '\x1f87' s = Yield '\x1f07' (s :*: '\x03b9' :*: '\x0000')
+foldMapping '\x1f87' s = Yield '\x1f07' (CC s '\x03b9' '\x0000')
 -- GREEK CAPITAL LETTER ALPHA WITH PSILI AND PROSGEGRAMMENI
-foldMapping '\x1f88' s = Yield '\x1f00' (s :*: '\x03b9' :*: '\x0000')
+foldMapping '\x1f88' s = Yield '\x1f00' (CC s '\x03b9' '\x0000')
 -- GREEK CAPITAL LETTER ALPHA WITH DASIA AND PROSGEGRAMMENI
-foldMapping '\x1f89' s = Yield '\x1f01' (s :*: '\x03b9' :*: '\x0000')
+foldMapping '\x1f89' s = Yield '\x1f01' (CC s '\x03b9' '\x0000')
 -- GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA AND PROSGEGRAMMENI
-foldMapping '\x1f8a' s = Yield '\x1f02' (s :*: '\x03b9' :*: '\x0000')
+foldMapping '\x1f8a' s = Yield '\x1f02' (CC s '\x03b9' '\x0000')
 -- GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA AND PROSGEGRAMMENI
-foldMapping '\x1f8b' s = Yield '\x1f03' (s :*: '\x03b9' :*: '\x0000')
+foldMapping '\x1f8b' s = Yield '\x1f03' (CC s '\x03b9' '\x0000')
 -- GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA AND PROSGEGRAMMENI
-foldMapping '\x1f8c' s = Yield '\x1f04' (s :*: '\x03b9' :*: '\x0000')
+foldMapping '\x1f8c' s = Yield '\x1f04' (CC s '\x03b9' '\x0000')
 -- GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA AND PROSGEGRAMMENI
-foldMapping '\x1f8d' s = Yield '\x1f05' (s :*: '\x03b9' :*: '\x0000')
+foldMapping '\x1f8d' s = Yield '\x1f05' (CC s '\x03b9' '\x0000')
 -- GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI
-foldMapping '\x1f8e' s = Yield '\x1f06' (s :*: '\x03b9' :*: '\x0000')
+foldMapping '\x1f8e' s = Yield '\x1f06' (CC s '\x03b9' '\x0000')
 -- GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI
-foldMapping '\x1f8f' s = Yield '\x1f07' (s :*: '\x03b9' :*: '\x0000')
+foldMapping '\x1f8f' s = Yield '\x1f07' (CC s '\x03b9' '\x0000')
 -- GREEK SMALL LETTER ETA WITH PSILI AND YPOGEGRAMMENI
-foldMapping '\x1f90' s = Yield '\x1f20' (s :*: '\x03b9' :*: '\x0000')
+foldMapping '\x1f90' s = Yield '\x1f20' (CC s '\x03b9' '\x0000')
 -- GREEK SMALL LETTER ETA WITH DASIA AND YPOGEGRAMMENI
-foldMapping '\x1f91' s = Yield '\x1f21' (s :*: '\x03b9' :*: '\x0000')
+foldMapping '\x1f91' s = Yield '\x1f21' (CC s '\x03b9' '\x0000')
 -- GREEK SMALL LETTER ETA WITH PSILI AND VARIA AND YPOGEGRAMMENI
-foldMapping '\x1f92' s = Yield '\x1f22' (s :*: '\x03b9' :*: '\x0000')
+foldMapping '\x1f92' s = Yield '\x1f22' (CC s '\x03b9' '\x0000')
 -- GREEK SMALL LETTER ETA WITH DASIA AND VARIA AND YPOGEGRAMMENI
-foldMapping '\x1f93' s = Yield '\x1f23' (s :*: '\x03b9' :*: '\x0000')
+foldMapping '\x1f93' s = Yield '\x1f23' (CC s '\x03b9' '\x0000')
 -- GREEK SMALL LETTER ETA WITH PSILI AND OXIA AND YPOGEGRAMMENI
-foldMapping '\x1f94' s = Yield '\x1f24' (s :*: '\x03b9' :*: '\x0000')
+foldMapping '\x1f94' s = Yield '\x1f24' (CC s '\x03b9' '\x0000')
 -- GREEK SMALL LETTER ETA WITH DASIA AND OXIA AND YPOGEGRAMMENI
-foldMapping '\x1f95' s = Yield '\x1f25' (s :*: '\x03b9' :*: '\x0000')
+foldMapping '\x1f95' s = Yield '\x1f25' (CC s '\x03b9' '\x0000')
 -- GREEK SMALL LETTER ETA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI
-foldMapping '\x1f96' s = Yield '\x1f26' (s :*: '\x03b9' :*: '\x0000')
+foldMapping '\x1f96' s = Yield '\x1f26' (CC s '\x03b9' '\x0000')
 -- GREEK SMALL LETTER ETA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI
-foldMapping '\x1f97' s = Yield '\x1f27' (s :*: '\x03b9' :*: '\x0000')
+foldMapping '\x1f97' s = Yield '\x1f27' (CC s '\x03b9' '\x0000')
 -- GREEK CAPITAL LETTER ETA WITH PSILI AND PROSGEGRAMMENI
-foldMapping '\x1f98' s = Yield '\x1f20' (s :*: '\x03b9' :*: '\x0000')
+foldMapping '\x1f98' s = Yield '\x1f20' (CC s '\x03b9' '\x0000')
 -- GREEK CAPITAL LETTER ETA WITH DASIA AND PROSGEGRAMMENI
-foldMapping '\x1f99' s = Yield '\x1f21' (s :*: '\x03b9' :*: '\x0000')
+foldMapping '\x1f99' s = Yield '\x1f21' (CC s '\x03b9' '\x0000')
 -- GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA AND PROSGEGRAMMENI
-foldMapping '\x1f9a' s = Yield '\x1f22' (s :*: '\x03b9' :*: '\x0000')
+foldMapping '\x1f9a' s = Yield '\x1f22' (CC s '\x03b9' '\x0000')
 -- GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA AND PROSGEGRAMMENI
-foldMapping '\x1f9b' s = Yield '\x1f23' (s :*: '\x03b9' :*: '\x0000')
+foldMapping '\x1f9b' s = Yield '\x1f23' (CC s '\x03b9' '\x0000')
 -- GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA AND PROSGEGRAMMENI
-foldMapping '\x1f9c' s = Yield '\x1f24' (s :*: '\x03b9' :*: '\x0000')
+foldMapping '\x1f9c' s = Yield '\x1f24' (CC s '\x03b9' '\x0000')
 -- GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA AND PROSGEGRAMMENI
-foldMapping '\x1f9d' s = Yield '\x1f25' (s :*: '\x03b9' :*: '\x0000')
+foldMapping '\x1f9d' s = Yield '\x1f25' (CC s '\x03b9' '\x0000')
 -- GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI
-foldMapping '\x1f9e' s = Yield '\x1f26' (s :*: '\x03b9' :*: '\x0000')
+foldMapping '\x1f9e' s = Yield '\x1f26' (CC s '\x03b9' '\x0000')
 -- GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI
-foldMapping '\x1f9f' s = Yield '\x1f27' (s :*: '\x03b9' :*: '\x0000')
+foldMapping '\x1f9f' s = Yield '\x1f27' (CC s '\x03b9' '\x0000')
 -- GREEK SMALL LETTER OMEGA WITH PSILI AND YPOGEGRAMMENI
-foldMapping '\x1fa0' s = Yield '\x1f60' (s :*: '\x03b9' :*: '\x0000')
+foldMapping '\x1fa0' s = Yield '\x1f60' (CC s '\x03b9' '\x0000')
 -- GREEK SMALL LETTER OMEGA WITH DASIA AND YPOGEGRAMMENI
-foldMapping '\x1fa1' s = Yield '\x1f61' (s :*: '\x03b9' :*: '\x0000')
+foldMapping '\x1fa1' s = Yield '\x1f61' (CC s '\x03b9' '\x0000')
 -- GREEK SMALL LETTER OMEGA WITH PSILI AND VARIA AND YPOGEGRAMMENI
-foldMapping '\x1fa2' s = Yield '\x1f62' (s :*: '\x03b9' :*: '\x0000')
+foldMapping '\x1fa2' s = Yield '\x1f62' (CC s '\x03b9' '\x0000')
 -- GREEK SMALL LETTER OMEGA WITH DASIA AND VARIA AND YPOGEGRAMMENI
-foldMapping '\x1fa3' s = Yield '\x1f63' (s :*: '\x03b9' :*: '\x0000')
+foldMapping '\x1fa3' s = Yield '\x1f63' (CC s '\x03b9' '\x0000')
 -- GREEK SMALL LETTER OMEGA WITH PSILI AND OXIA AND YPOGEGRAMMENI
-foldMapping '\x1fa4' s = Yield '\x1f64' (s :*: '\x03b9' :*: '\x0000')
+foldMapping '\x1fa4' s = Yield '\x1f64' (CC s '\x03b9' '\x0000')
 -- GREEK SMALL LETTER OMEGA WITH DASIA AND OXIA AND YPOGEGRAMMENI
-foldMapping '\x1fa5' s = Yield '\x1f65' (s :*: '\x03b9' :*: '\x0000')
+foldMapping '\x1fa5' s = Yield '\x1f65' (CC s '\x03b9' '\x0000')
 -- GREEK SMALL LETTER OMEGA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI
-foldMapping '\x1fa6' s = Yield '\x1f66' (s :*: '\x03b9' :*: '\x0000')
+foldMapping '\x1fa6' s = Yield '\x1f66' (CC s '\x03b9' '\x0000')
 -- GREEK SMALL LETTER OMEGA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI
-foldMapping '\x1fa7' s = Yield '\x1f67' (s :*: '\x03b9' :*: '\x0000')
+foldMapping '\x1fa7' s = Yield '\x1f67' (CC s '\x03b9' '\x0000')
 -- GREEK CAPITAL LETTER OMEGA WITH PSILI AND PROSGEGRAMMENI
-foldMapping '\x1fa8' s = Yield '\x1f60' (s :*: '\x03b9' :*: '\x0000')
+foldMapping '\x1fa8' s = Yield '\x1f60' (CC s '\x03b9' '\x0000')
 -- GREEK CAPITAL LETTER OMEGA WITH DASIA AND PROSGEGRAMMENI
-foldMapping '\x1fa9' s = Yield '\x1f61' (s :*: '\x03b9' :*: '\x0000')
+foldMapping '\x1fa9' s = Yield '\x1f61' (CC s '\x03b9' '\x0000')
 -- GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA AND PROSGEGRAMMENI
-foldMapping '\x1faa' s = Yield '\x1f62' (s :*: '\x03b9' :*: '\x0000')
+foldMapping '\x1faa' s = Yield '\x1f62' (CC s '\x03b9' '\x0000')
 -- GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA AND PROSGEGRAMMENI
-foldMapping '\x1fab' s = Yield '\x1f63' (s :*: '\x03b9' :*: '\x0000')
+foldMapping '\x1fab' s = Yield '\x1f63' (CC s '\x03b9' '\x0000')
 -- GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA AND PROSGEGRAMMENI
-foldMapping '\x1fac' s = Yield '\x1f64' (s :*: '\x03b9' :*: '\x0000')
+foldMapping '\x1fac' s = Yield '\x1f64' (CC s '\x03b9' '\x0000')
 -- GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA AND PROSGEGRAMMENI
-foldMapping '\x1fad' s = Yield '\x1f65' (s :*: '\x03b9' :*: '\x0000')
+foldMapping '\x1fad' s = Yield '\x1f65' (CC s '\x03b9' '\x0000')
 -- GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI
-foldMapping '\x1fae' s = Yield '\x1f66' (s :*: '\x03b9' :*: '\x0000')
+foldMapping '\x1fae' s = Yield '\x1f66' (CC s '\x03b9' '\x0000')
 -- GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI
-foldMapping '\x1faf' s = Yield '\x1f67' (s :*: '\x03b9' :*: '\x0000')
+foldMapping '\x1faf' s = Yield '\x1f67' (CC s '\x03b9' '\x0000')
 -- GREEK SMALL LETTER ALPHA WITH VARIA AND YPOGEGRAMMENI
-foldMapping '\x1fb2' s = Yield '\x1f70' (s :*: '\x03b9' :*: '\x0000')
+foldMapping '\x1fb2' s = Yield '\x1f70' (CC s '\x03b9' '\x0000')
 -- GREEK SMALL LETTER ALPHA WITH YPOGEGRAMMENI
-foldMapping '\x1fb3' s = Yield '\x03b1' (s :*: '\x03b9' :*: '\x0000')
+foldMapping '\x1fb3' s = Yield '\x03b1' (CC s '\x03b9' '\x0000')
 -- GREEK SMALL LETTER ALPHA WITH OXIA AND YPOGEGRAMMENI
-foldMapping '\x1fb4' s = Yield '\x03ac' (s :*: '\x03b9' :*: '\x0000')
+foldMapping '\x1fb4' s = Yield '\x03ac' (CC s '\x03b9' '\x0000')
 -- GREEK SMALL LETTER ALPHA WITH PERISPOMENI
-foldMapping '\x1fb6' s = Yield '\x03b1' (s :*: '\x0342' :*: '\x0000')
+foldMapping '\x1fb6' s = Yield '\x03b1' (CC s '\x0342' '\x0000')
 -- GREEK SMALL LETTER ALPHA WITH PERISPOMENI AND YPOGEGRAMMENI
-foldMapping '\x1fb7' s = Yield '\x03b1' (s :*: '\x0342' :*: '\x03b9')
+foldMapping '\x1fb7' s = Yield '\x03b1' (CC s '\x0342' '\x03b9')
 -- GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI
-foldMapping '\x1fbc' s = Yield '\x03b1' (s :*: '\x03b9' :*: '\x0000')
+foldMapping '\x1fbc' s = Yield '\x03b1' (CC s '\x03b9' '\x0000')
 -- GREEK PROSGEGRAMMENI
-foldMapping '\x1fbe' s = Yield '\x03b9' (s :*: '\x0000' :*: '\x0000')
+foldMapping '\x1fbe' s = Yield '\x03b9' (CC s '\x0000' '\x0000')
 -- GREEK SMALL LETTER ETA WITH VARIA AND YPOGEGRAMMENI
-foldMapping '\x1fc2' s = Yield '\x1f74' (s :*: '\x03b9' :*: '\x0000')
+foldMapping '\x1fc2' s = Yield '\x1f74' (CC s '\x03b9' '\x0000')
 -- GREEK SMALL LETTER ETA WITH YPOGEGRAMMENI
-foldMapping '\x1fc3' s = Yield '\x03b7' (s :*: '\x03b9' :*: '\x0000')
+foldMapping '\x1fc3' s = Yield '\x03b7' (CC s '\x03b9' '\x0000')
 -- GREEK SMALL LETTER ETA WITH OXIA AND YPOGEGRAMMENI
-foldMapping '\x1fc4' s = Yield '\x03ae' (s :*: '\x03b9' :*: '\x0000')
+foldMapping '\x1fc4' s = Yield '\x03ae' (CC s '\x03b9' '\x0000')
 -- GREEK SMALL LETTER ETA WITH PERISPOMENI
-foldMapping '\x1fc6' s = Yield '\x03b7' (s :*: '\x0342' :*: '\x0000')
+foldMapping '\x1fc6' s = Yield '\x03b7' (CC s '\x0342' '\x0000')
 -- GREEK SMALL LETTER ETA WITH PERISPOMENI AND YPOGEGRAMMENI
-foldMapping '\x1fc7' s = Yield '\x03b7' (s :*: '\x0342' :*: '\x03b9')
+foldMapping '\x1fc7' s = Yield '\x03b7' (CC s '\x0342' '\x03b9')
 -- GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI
-foldMapping '\x1fcc' s = Yield '\x03b7' (s :*: '\x03b9' :*: '\x0000')
+foldMapping '\x1fcc' s = Yield '\x03b7' (CC s '\x03b9' '\x0000')
 -- GREEK SMALL LETTER IOTA WITH DIALYTIKA AND VARIA
-foldMapping '\x1fd2' s = Yield '\x03b9' (s :*: '\x0308' :*: '\x0300')
+foldMapping '\x1fd2' s = Yield '\x03b9' (CC s '\x0308' '\x0300')
 -- GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA
-foldMapping '\x1fd3' s = Yield '\x03b9' (s :*: '\x0308' :*: '\x0301')
+foldMapping '\x1fd3' s = Yield '\x03b9' (CC s '\x0308' '\x0301')
 -- GREEK SMALL LETTER IOTA WITH PERISPOMENI
-foldMapping '\x1fd6' s = Yield '\x03b9' (s :*: '\x0342' :*: '\x0000')
+foldMapping '\x1fd6' s = Yield '\x03b9' (CC s '\x0342' '\x0000')
 -- GREEK SMALL LETTER IOTA WITH DIALYTIKA AND PERISPOMENI
-foldMapping '\x1fd7' s = Yield '\x03b9' (s :*: '\x0308' :*: '\x0342')
+foldMapping '\x1fd7' s = Yield '\x03b9' (CC s '\x0308' '\x0342')
 -- GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND VARIA
-foldMapping '\x1fe2' s = Yield '\x03c5' (s :*: '\x0308' :*: '\x0300')
+foldMapping '\x1fe2' s = Yield '\x03c5' (CC s '\x0308' '\x0300')
 -- GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND OXIA
-foldMapping '\x1fe3' s = Yield '\x03c5' (s :*: '\x0308' :*: '\x0301')
+foldMapping '\x1fe3' s = Yield '\x03c5' (CC s '\x0308' '\x0301')
 -- GREEK SMALL LETTER RHO WITH PSILI
-foldMapping '\x1fe4' s = Yield '\x03c1' (s :*: '\x0313' :*: '\x0000')
+foldMapping '\x1fe4' s = Yield '\x03c1' (CC s '\x0313' '\x0000')
 -- GREEK SMALL LETTER UPSILON WITH PERISPOMENI
-foldMapping '\x1fe6' s = Yield '\x03c5' (s :*: '\x0342' :*: '\x0000')
+foldMapping '\x1fe6' s = Yield '\x03c5' (CC s '\x0342' '\x0000')
 -- GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND PERISPOMENI
-foldMapping '\x1fe7' s = Yield '\x03c5' (s :*: '\x0308' :*: '\x0342')
+foldMapping '\x1fe7' s = Yield '\x03c5' (CC s '\x0308' '\x0342')
 -- GREEK SMALL LETTER OMEGA WITH VARIA AND YPOGEGRAMMENI
-foldMapping '\x1ff2' s = Yield '\x1f7c' (s :*: '\x03b9' :*: '\x0000')
+foldMapping '\x1ff2' s = Yield '\x1f7c' (CC s '\x03b9' '\x0000')
 -- GREEK SMALL LETTER OMEGA WITH YPOGEGRAMMENI
-foldMapping '\x1ff3' s = Yield '\x03c9' (s :*: '\x03b9' :*: '\x0000')
+foldMapping '\x1ff3' s = Yield '\x03c9' (CC s '\x03b9' '\x0000')
 -- GREEK SMALL LETTER OMEGA WITH OXIA AND YPOGEGRAMMENI
-foldMapping '\x1ff4' s = Yield '\x03ce' (s :*: '\x03b9' :*: '\x0000')
+foldMapping '\x1ff4' s = Yield '\x03ce' (CC s '\x03b9' '\x0000')
 -- GREEK SMALL LETTER OMEGA WITH PERISPOMENI
-foldMapping '\x1ff6' s = Yield '\x03c9' (s :*: '\x0342' :*: '\x0000')
+foldMapping '\x1ff6' s = Yield '\x03c9' (CC s '\x0342' '\x0000')
 -- GREEK SMALL LETTER OMEGA WITH PERISPOMENI AND YPOGEGRAMMENI
-foldMapping '\x1ff7' s = Yield '\x03c9' (s :*: '\x0342' :*: '\x03b9')
+foldMapping '\x1ff7' s = Yield '\x03c9' (CC s '\x0342' '\x03b9')
 -- GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI
-foldMapping '\x1ffc' s = Yield '\x03c9' (s :*: '\x03b9' :*: '\x0000')
+foldMapping '\x1ffc' s = Yield '\x03c9' (CC s '\x03b9' '\x0000')
 -- LATIN SMALL LIGATURE FF
-foldMapping '\xfb00' s = Yield '\x0066' (s :*: '\x0066' :*: '\x0000')
+foldMapping '\xfb00' s = Yield '\x0066' (CC s '\x0066' '\x0000')
 -- LATIN SMALL LIGATURE FI
-foldMapping '\xfb01' s = Yield '\x0066' (s :*: '\x0069' :*: '\x0000')
+foldMapping '\xfb01' s = Yield '\x0066' (CC s '\x0069' '\x0000')
 -- LATIN SMALL LIGATURE FL
-foldMapping '\xfb02' s = Yield '\x0066' (s :*: '\x006c' :*: '\x0000')
+foldMapping '\xfb02' s = Yield '\x0066' (CC s '\x006c' '\x0000')
 -- LATIN SMALL LIGATURE FFI
-foldMapping '\xfb03' s = Yield '\x0066' (s :*: '\x0066' :*: '\x0069')
+foldMapping '\xfb03' s = Yield '\x0066' (CC s '\x0066' '\x0069')
 -- LATIN SMALL LIGATURE FFL
-foldMapping '\xfb04' s = Yield '\x0066' (s :*: '\x0066' :*: '\x006c')
+foldMapping '\xfb04' s = Yield '\x0066' (CC s '\x0066' '\x006c')
 -- LATIN SMALL LIGATURE LONG S T
-foldMapping '\xfb05' s = Yield '\x0073' (s :*: '\x0074' :*: '\x0000')
+foldMapping '\xfb05' s = Yield '\x0073' (CC s '\x0074' '\x0000')
 -- LATIN SMALL LIGATURE ST
-foldMapping '\xfb06' s = Yield '\x0073' (s :*: '\x0074' :*: '\x0000')
+foldMapping '\xfb06' s = Yield '\x0073' (CC s '\x0074' '\x0000')
 -- ARMENIAN SMALL LIGATURE MEN NOW
-foldMapping '\xfb13' s = Yield '\x0574' (s :*: '\x0576' :*: '\x0000')
+foldMapping '\xfb13' s = Yield '\x0574' (CC s '\x0576' '\x0000')
 -- ARMENIAN SMALL LIGATURE MEN ECH
-foldMapping '\xfb14' s = Yield '\x0574' (s :*: '\x0565' :*: '\x0000')
+foldMapping '\xfb14' s = Yield '\x0574' (CC s '\x0565' '\x0000')
 -- ARMENIAN SMALL LIGATURE MEN INI
-foldMapping '\xfb15' s = Yield '\x0574' (s :*: '\x056b' :*: '\x0000')
+foldMapping '\xfb15' s = Yield '\x0574' (CC s '\x056b' '\x0000')
 -- ARMENIAN SMALL LIGATURE VEW NOW
-foldMapping '\xfb16' s = Yield '\x057e' (s :*: '\x0576' :*: '\x0000')
+foldMapping '\xfb16' s = Yield '\x057e' (CC s '\x0576' '\x0000')
 -- ARMENIAN SMALL LIGATURE MEN XEH
-foldMapping '\xfb17' s = Yield '\x0574' (s :*: '\x056d' :*: '\x0000')
-foldMapping c s = Yield (toLower c) (s :*: '\0' :*: '\0')
+foldMapping '\xfb17' s = Yield '\x0574' (CC s '\x056d' '\x0000')
+foldMapping c s = Yield (toLower c) (CC s '\0' '\0')
diff --git a/Data/Text/Fusion/Common.hs b/Data/Text/Fusion/Common.hs
--- a/Data/Text/Fusion/Common.hs
+++ b/Data/Text/Fusion/Common.hs
@@ -98,7 +98,7 @@
     , zipWith
     ) where
 
-import Prelude (Bool(..), Char, Either(..), Eq(..), Int, Integral, Maybe(..),
+import Prelude (Bool(..), Char, Eq(..), Int, Integral, Maybe(..),
                 Ord(..), String, (.), ($), (+), (-), (*), (++), (&&),
                 fromIntegral, otherwise)
 import qualified Data.List as L
@@ -121,35 +121,36 @@
           next (x:xs)   = Yield x xs
 
 unstreamList :: Stream a -> [a]
-{-# INLINE [0] unstreamList #-}
 unstreamList (Stream next s0 _len) = unfold s0
     where unfold !s = case next s of
                         Done       -> []
                         Skip s'    -> unfold s'
                         Yield x s' -> x : unfold s'
+{-# INLINE [0] unstreamList #-}
 
 {-# RULES "STREAM streamList/unstreamList fusion" forall s. streamList (unstreamList s) = s #-}
 
 -- ----------------------------------------------------------------------------
 -- * Basic stream functions
 
+data C s = C0 !s
+         | C1 !s
+
 -- | /O(n)/ Adds a character to the front of a Stream Char.
 cons :: Char -> Stream Char -> Stream Char
-cons w (Stream next0 s0 len) = Stream next (S2 :*: s0) (len+1)
+cons w (Stream next0 s0 len) = Stream next (C1 s0) (len+1)
     where
-      {-# INLINE next #-}
-      next (S2 :*: s) = Yield w (S1 :*: s)
-      next (S1 :*: s) = case next0 s of
+      next (C1 s) = Yield w (C0 s)
+      next (C0 s) = case next0 s of
                           Done -> Done
-                          Skip s' -> Skip (S1 :*: s')
-                          Yield x s' -> Yield x (S1 :*: s')
+                          Skip s' -> Skip (C0 s')
+                          Yield x s' -> Yield x (C0 s')
 {-# INLINE [0] cons #-}
 
 -- | /O(n)/ Adds a character to the end of a stream.
 snoc :: Stream Char -> Char -> Stream Char
 snoc (Stream next0 xs0 len) w = Stream next (J xs0) (len+1)
   where
-    {-# INLINE next #-}
     next (J xs) = case next0 xs of
       Done        -> Yield w N
       Skip xs'    -> Skip    (J xs')
@@ -157,20 +158,22 @@
     next N = Done
 {-# INLINE [0] snoc #-}
 
+data E l r = L {-# UNPACK #-} !l
+           | R {-# UNPACK #-} !r
+
 -- | /O(n)/ Appends one Stream to the other.
 append :: Stream Char -> Stream Char -> Stream Char
 append (Stream next0 s01 len1) (Stream next1 s02 len2) =
-    Stream next (Left s01) (len1 + len2)
+    Stream next (L s01) (len1 + len2)
     where
-      {-# INLINE next #-}
-      next (Left s1) = case next0 s1 of
-                         Done        -> Skip    (Right s02)
-                         Skip s1'    -> Skip    (Left s1')
-                         Yield x s1' -> Yield x (Left s1')
-      next (Right s2) = case next1 s2 of
+      next (L s1) = case next0 s1 of
+                         Done        -> Skip    (R s02)
+                         Skip s1'    -> Skip    (L s1')
+                         Yield x s1' -> Yield x (L s1')
+      next (R s2) = case next1 s2 of
                           Done        -> Done
-                          Skip s2'    -> Skip    (Right s2')
-                          Yield x s2' -> Yield x (Right s2')
+                          Skip s2'    -> Skip    (R s2')
+                          Yield x s2' -> Yield x (R s2')
 {-# INLINE [0] append #-}
 
 -- | /O(1)/ Returns the first character of a Text, which must be non-empty.
@@ -180,8 +183,8 @@
     where
       loop_head !s = case next s of
                       Yield x _ -> x
-                      Skip s' -> loop_head s'
-                      Done -> streamError "head" "Empty stream"
+                      Skip s'   -> loop_head s'
+                      Done      -> streamError "head" "Empty stream"
 {-# INLINE [0] head #-}
 
 -- | /O(1)/ Returns the first character and remainder of a 'Stream
@@ -213,34 +216,34 @@
 -- | /O(1)/ Returns all characters after the head of a Stream Char, which must
 -- be non-empty.
 tail :: Stream Char -> Stream Char
-tail (Stream next0 s0 len) = Stream next (False :*: s0) (len-1)
+tail (Stream next0 s0 len) = Stream next (C0 s0) (len-1)
     where
-      {-# INLINE next #-}
-      next (False :*: s) = case next0 s of
-                          Done       -> emptyError "tail"
-                          Skip s'    -> Skip (False :*: s')
-                          Yield _ s' -> Skip (True :*: s')
-      next (True :*: s) = case next0 s of
-                          Done       -> Done
-                          Skip s'    -> Skip    (True :*: s')
-                          Yield x s' -> Yield x (True :*: s')
+      next (C0 s) = case next0 s of
+                      Done       -> emptyError "tail"
+                      Skip s'    -> Skip (C0 s')
+                      Yield _ s' -> Skip (C1 s')
+      next (C1 s) = case next0 s of
+                      Done       -> Done
+                      Skip s'    -> Skip    (C1 s')
+                      Yield x s' -> Yield x (C1 s')
 {-# INLINE [0] tail #-}
 
+data Init s = Init0 !s
+            | Init1 {-# UNPACK #-} !Char !s
 
 -- | /O(1)/ Returns all but the last character of a Stream Char, which
 -- must be non-empty.
 init :: Stream Char -> Stream Char
-init (Stream next0 s0 len) = Stream next (N :*: s0) (len-1)
+init (Stream next0 s0 len) = Stream next (Init0 s0) (len-1)
     where
-      {-# INLINE next #-}
-      next (N :*: s) = case next0 s of
+      next (Init0 s) = case next0 s of
                          Done       -> emptyError "init"
-                         Skip s'    -> Skip (N :*: s')
-                         Yield x s' -> Skip (J x  :*: s')
-      next (J x :*: s)  = case next0 s of
+                         Skip s'    -> Skip (Init0 s')
+                         Yield x s' -> Skip (Init1 x s')
+      next (Init1 x s)  = case next0 s of
                             Done        -> Done
-                            Skip s'     -> Skip    (J x  :*: s')
-                            Yield x' s' -> Yield x (J x' :*: s')
+                            Skip s'     -> Skip    (Init1 x s')
+                            Yield x' s' -> Yield x (Init1 x' s')
 {-# INLINE [0] init #-}
 
 -- | /O(1)/ Tests whether a Stream Char is empty or not.
@@ -283,7 +286,6 @@
 map :: (Char -> Char) -> Stream Char -> Stream Char
 map f (Stream next0 s0 len) = Stream next s0 len
     where
-      {-# INLINE next #-}
       next !s = case next0 s of
                   Done       -> Done
                   Skip s'    -> Skip s'
@@ -295,22 +297,24 @@
      map f (map g s) = map (\x -> f (g x)) s
  #-}
 
+data I s = I1 !s
+         | I2 !s {-# UNPACK #-} !Char
+         | I3 !s
+
 -- | /O(n)/ Take a character and place it between each of the
 -- characters of a 'Stream Char'.
 intersperse :: Char -> Stream Char -> Stream Char
-intersperse c (Stream next0 s0 len) = Stream next (s0 :*: N :*: S1) len
+intersperse c (Stream next0 s0 len) = Stream next (I1 s0) len
     where
-      {-# INLINE next #-}
-      next (s :*: N :*: S1) = case next0 s of
+      next (I1 s) = case next0 s of
         Done       -> Done
-        Skip s'    -> Skip (s' :*: N :*: S1)
-        Yield x s' -> Skip (s' :*: J x :*: S1)
-      next (s :*: J x :*: S1)  = Yield x (s :*: N :*: S2)
-      next (s :*: N :*: S2) = case next0 s of
+        Skip s'    -> Skip (I1 s')
+        Yield x s' -> Skip (I2 s' x)
+      next (I2 s x)  = Yield x (I3 s)
+      next (I3 s) = case next0 s of
         Done       -> Done
-        Skip s'    -> Skip    (s' :*: N :*: S2)
-        Yield x s' -> Yield c (s' :*: J x :*: S1)
-      next _ = internalError "intersperse"
+        Skip s'    -> Skip    (I3 s')
+        Yield x s' -> Yield c (I2 s' x)
 {-# INLINE [0] intersperse #-}
 
 -- ----------------------------------------------------------------------------
@@ -325,17 +329,16 @@
 -- functions may map one input character to two or three output
 -- characters.
 
-caseConvert :: (forall s. Char -> s -> Step (PairS (PairS s Char) Char) Char)
+caseConvert :: (forall s. Char -> s -> Step (CC s) Char)
             -> Stream Char -> Stream Char
-caseConvert remap (Stream next0 s0 len) = Stream next (s0 :*: '\0' :*: '\0') len
+caseConvert remap (Stream next0 s0 len) = Stream next (CC s0 '\0' '\0') len
   where
-    {-# INLINE next #-}
-    next (s :*: '\0' :*: _) =
+    next (CC s '\0' _) =
         case next0 s of
           Done       -> Done
-          Skip s'    -> Skip (s' :*: '\0' :*: '\0')
+          Skip s'    -> Skip (CC s' '\0' '\0')
           Yield c s' -> remap c s'
-    next (s :*: a :*: b) = Yield a (s :*: b :*: '\0')
+    next (CC s a b)  =  Yield a (CC s b '\0')
 
 -- | /O(n)/ Convert a string to folded case.  This function is mainly
 -- useful for performing caseless (or case insensitive) string
@@ -480,11 +483,13 @@
 -- | /O(n)/ Concatenate a list of streams. Subject to array fusion.
 concat :: [Stream Char] -> Stream Char
 concat = L.foldr append empty
+{-# INLINE [0] concat #-}
 
 -- | Map a function over a stream that results in a stream and concatenate the
 -- results.
 concatMap :: (Char -> Stream Char) -> Stream Char -> Stream Char
 concatMap f = foldr (append . f) empty
+{-# INLINE [0] concatMap #-}
 
 -- | /O(n)/ any @p @xs determines if any character in the stream
 -- @xs@ satisifes the predicate @p@.
@@ -590,21 +595,22 @@
     | n < 0     = empty
     | otherwise = Stream next 0 (fromIntegral n) -- HINT maybe too low
   where
-    {-# INLINE next #-}
     next i | i >= n    = Done
            | otherwise = Yield c (i + 1)
 {-# INLINE [0] replicateCharI #-}
 
+data RI s = RI !s {-# UNPACK #-} !Int64
+
 replicateI :: Int64 -> Stream Char -> Stream Char
 replicateI n (Stream next0 s0 len) =
-    Stream next (0 :*: s0) (fromIntegral (max 0 n) * len)
+    Stream next (RI s0 0) (fromIntegral (max 0 n) * len)
   where
-    next (k :*: s)
+    next (RI s k)
         | k >= n = Done
         | otherwise = case next0 s of
-                        Done       -> Skip    (k+1 :*: s0)
-                        Skip s'    -> Skip    (k :*: s')
-                        Yield x s' -> Yield x (k :*: s')
+                        Done       -> Skip    (RI s0 (k+1))
+                        Skip s'    -> Skip    (RI s' k)
+                        Yield x s' -> Yield x (RI s' k)
 {-# INLINE [0] replicateI #-}
 
 -- | /O(n)/, where @n@ is the length of the result. The unfoldr function
@@ -772,7 +778,6 @@
 filter :: (Char -> Bool) -> Stream Char -> Stream Char
 filter p (Stream next0 s0 len) = Stream next s0 len -- HINT maybe too high
   where
-    {-# INLINE next #-}
     next !s = case next0 s of
                 Done                   -> Done
                 Skip    s'             -> Skip    s'
@@ -781,7 +786,7 @@
 {-# INLINE [0] filter #-}
 
 {-# RULES
-  "Stream filter/filter fusion" forall p q s.
+  "STREAM filter/filter fusion" forall p q s.
   filter p (filter q s) = filter (\x -> q x && p x) s
   #-}
 
@@ -816,7 +821,6 @@
 zipWith f (Stream next0 sa0 len1) (Stream next1 sb0 len2) =
     Stream next (sa0 :*: sb0 :*: N) (smaller len1 len2)
     where
-      {-# INLINE next #-}
       next (sa :*: sb :*: N) = case next0 sa of
                                  Done -> Done
                                  Skip sa' -> Skip (sa' :*: sb :*: N)
diff --git a/Data/Text/Fusion/Internal.hs b/Data/Text/Fusion/Internal.hs
--- a/Data/Text/Fusion/Internal.hs
+++ b/Data/Text/Fusion/Internal.hs
@@ -15,7 +15,8 @@
 
 module Data.Text.Fusion.Internal
     (
-      M(..)
+      CC(..)
+    , M(..)
     , M8
     , PairS(..)
     , S(..)
@@ -27,6 +28,9 @@
 
 import Data.Text.Fusion.Size
 import Data.Word (Word8)
+
+-- | Specialised tuple for case conversion.
+data CC s = CC !s {-# UNPACK #-} !Char {-# UNPACK #-} !Char
 
 -- | Specialised, strict Maybe-like type.
 data M a = N
diff --git a/Data/Text/Lazy.hs b/Data/Text/Lazy.hs
--- a/Data/Text/Lazy.hs
+++ b/Data/Text/Lazy.hs
@@ -119,6 +119,7 @@
     , splitAt
     , spanBy
     , break
+    , breakEnd
     , breakBy
     , group
     , groupBy
@@ -163,11 +164,12 @@
     -- , sort
     ) where
 
-import Prelude (Char, Bool(..), Int, Maybe(..), String,
+import Prelude (Char, Bool(..), Maybe(..), String,
                 Eq(..), Ord(..), Read(..), Show(..),
                 (&&), (+), (-), (.), ($), (++),
                 div, flip, fromIntegral, not, otherwise)
 import qualified Prelude as P
+import Control.DeepSeq (NFData(..))
 import Data.Int (Int64)
 import qualified Data.List as L
 import Data.Char (isSpace)
@@ -206,6 +208,10 @@
 instance IsString Text where
     fromString = pack
 
+instance NFData Text where
+    rnf Empty        = ()
+    rnf (Chunk _ ts) = rnf ts
+
 -- | /O(n)/ Convert a 'String' into a 'Text'.
 --
 -- This function is subject to array fusion.
@@ -376,7 +382,7 @@
 -- 'Text's and concatenates the list after interspersing the first
 -- argument between each element of the list.
 intercalate :: Text -> [Text] -> Text
-intercalate t ts = unstream (S.intercalate (stream t) (L.map stream ts))
+intercalate t = concat . (L.intersperse t)
 {-# INLINE intercalate #-}
 
 -- | /O(n)/ The 'intersperse' function takes a character and places it
@@ -445,7 +451,7 @@
   where rev a Empty        = a
         rev a (Chunk t ts) = rev (Chunk (T.reverse t) a) ts
 
--- | /O(m)*O(n)/ Replace every occurrence of one substring with another.
+-- | /O(m+n)/ Replace every occurrence of one substring with another.
 replace :: Text                 -- ^ Text to search for
         -> Text                 -- ^ Replacement text
         -> Text                 -- ^ Input text
@@ -542,18 +548,20 @@
 foldr1 f t = S.foldr1 f (stream t)
 {-# INLINE foldr1 #-}
 
--- | /O(n)/ Concatenate a list of 'Text's. Subject to array fusion.
+-- | /O(n)/ Concatenate a list of 'Text's.
 concat :: [Text] -> Text
-concat ts = unstream (S.concat (L.map stream ts))
+concat = to
+  where
+    go Empty        css = to css
+    go (Chunk c cs) css = Chunk c (go cs css)
+    to []               = Empty
+    to (cs:css)         = go cs css
 {-# INLINE concat #-}
 
 -- | /O(n)/ Map a function over a 'Text' that results in a 'Text', and
--- concatenate the results.  This function is subject to array fusion.
---
--- Note: if in 'concatMap' @f@ @t@, @f@ is defined in terms of fusible
--- functions, it will also be fusible.
+-- concatenate the results.
 concatMap :: (Char -> Text) -> Text -> Text
-concatMap f t = unstream (S.concatMap (stream . f) (stream t))
+concatMap f = concat . foldr ((:) . f) []
 {-# INLINE concatMap #-}
 
 -- | /O(n)/ 'any' @p@ @t@ determines whether any character in the
@@ -637,11 +645,11 @@
                               (s', ys) = mapAccumR f s xs
 
 -- | /O(n*m)/ 'replicate' @n@ @t@ is a 'Text' consisting of the input
--- @t@ repeated @n@ times. Subject to fusion.
+-- @t@ repeated @n@ times.
 replicate :: Int64 -> Text -> Text
-replicate n t
-    | isSingleton t = replicateChar n (head t)
-    | otherwise     = unstream (S.replicateI n (S.stream t))
+replicate n t = concat (rep 0)
+    where rep i | i >= n    = []
+                | otherwise = t : rep (i+1)
 {-# INLINE replicate #-}
 
 -- | /O(n)/ 'replicateChar' @n@ @c@ is a 'Text' of length @n@ with @c@ the
@@ -873,6 +881,18 @@
                     []    -> (src, empty)
                     (x:_) -> let h :*: t = splitAtWord x src
                              in  (h, t)
+
+-- | /O(n+m)/ Similar to 'break', but searches from the end of the string.
+--
+-- The first element of the returned tuple is the prefix of @haystack@
+-- up to and including the last match of @needle@.  The second is the
+-- remainder of @haystack@, following the match.
+--
+-- > breakEnd "::" "a::b::c" ==> ("a::b::", "c")
+breakEnd :: Text -> Text -> (Text, Text)
+breakEnd pat src = let (a,b) = break (reverse pat) (reverse src)
+                   in  (reverse b, reverse a)
+{-# INLINE breakEnd #-}
 
 -- | /O(n+m)/ Find all non-overlapping instances of @needle@ in
 -- @haystack@.  The first element of the returned pair is the prefix
diff --git a/Data/Text/Lazy/Encoding/Fusion.hs b/Data/Text/Lazy/Encoding/Fusion.hs
--- a/Data/Text/Lazy/Encoding/Fusion.hs
+++ b/Data/Text/Lazy/Encoding/Fusion.hs
@@ -53,7 +53,6 @@
 streamUtf8 onErr bs0 = Stream next (bs0 :*: empty :*: 0) unknownSize
     where
       empty = S N N N N
-      {-# INLINE next #-}
       next (bs@(Chunk ps _) :*: S N _ _ _ :*: i)
           | i < len && U8.validate1 a =
               Yield (unsafeChr8 a) (bs :*: empty :*: i+1)
@@ -80,7 +79,6 @@
             Yield (U8.chr4 a b c d) es
           _ -> consume st
          where es = bs :*: empty :*: i
-      {-# INLINE consume #-}
       consume (bs@(Chunk ps rest) :*: s :*: i)
           | i >= B.length ps = consume (rest :*: s  :*: 0)
           | otherwise =
diff --git a/Data/Text/Lazy/Internal.hs b/Data/Text/Lazy/Internal.hs
--- a/Data/Text/Lazy/Internal.hs
+++ b/Data/Text/Lazy/Internal.hs
@@ -31,7 +31,7 @@
     ) where
 
 import qualified Data.Text.Internal as T
-import qualified Data.Text as T
+import Data.Text ()
 import Data.Typeable (Typeable)
 import Data.Word (Word16)
 import Foreign.Storable (sizeOf)
diff --git a/Data/Text/Lazy/Search.hs b/Data/Text/Lazy/Search.hs
--- a/Data/Text/Lazy/Search.hs
+++ b/Data/Text/Lazy/Search.hs
@@ -23,7 +23,6 @@
 import Data.Int (Int64)
 import Data.Word (Word16, Word64)
 import qualified Data.Text.Internal as T
-import qualified Data.Text as T
 import Data.Text.Fusion.Internal (PairS(..))
 import Data.Text.Lazy.Internal (Text(..), foldlChunks)
 import Data.Bits ((.|.), (.&.))
diff --git a/scripts/CaseFolding.hs b/scripts/CaseFolding.hs
--- a/scripts/CaseFolding.hs
+++ b/scripts/CaseFolding.hs
@@ -32,11 +32,11 @@
 mapCF :: [Fold] -> [String]
 mapCF ms = typ ++ (map nice . filter p $ ms) ++ [last]
   where
-    typ = ["foldMapping :: forall s. Char -> s -> Step (PairS (PairS s Char) Char) Char"
+    typ = ["foldMapping :: forall s. Char -> s -> Step (CC s) Char"
            ,"{-# INLINE foldMapping #-}"]
-    last = "foldMapping c s = Yield (toLower c) (s :!: '\\0' :!: '\\0')"
+    last = "foldMapping c s = Yield (toLower c) (CC s '\\0' '\\0')"
     nice c = "-- " ++ name c ++ "\n" ++
-             "foldMapping " ++ showC (code c) ++ " s = Yield " ++ x ++ " (s :!: " ++ y ++ " :!: " ++ z ++ ")"
+             "foldMapping " ++ showC (code c) ++ " s = Yield " ++ x ++ " (CC s " ++ y ++ " " ++ z ++ ")"
        where [x,y,z] = (map showC . take 3) (mapping c ++ repeat '\0')
     p f = status f `elem` "CF" &&
           mapping f /= [toLower (code f)]
diff --git a/scripts/SpecialCasing.hs b/scripts/SpecialCasing.hs
--- a/scripts/SpecialCasing.hs
+++ b/scripts/SpecialCasing.hs
@@ -36,11 +36,11 @@
 mapSC :: String -> (Case -> String) -> (Char -> Char) -> [Case] -> [String]
 mapSC which access twiddle ms = typ ++ (map nice . filter p $ ms) ++ [last]
   where
-    typ = [which ++ "Mapping :: forall s. Char -> s -> Step (PairS (PairS s Char) Char) Char"
+    typ = [which ++ "Mapping :: forall s. Char -> s -> Step (CC s) Char"
            ,"{-# INLINE " ++ which ++ "Mapping #-}"]
-    last = which ++ "Mapping c s = Yield (to" ++ ucFirst which ++ " c) (s :!: '\\0' :!: '\\0')"
+    last = which ++ "Mapping c s = Yield (to" ++ ucFirst which ++ " c) (CC s '\\0' '\\0')"
     nice c = "-- " ++ name c ++ "\n" ++
-             which ++ "Mapping " ++ showC (code c) ++ " s = Yield " ++ x ++ " (s :!: " ++ y ++ " :!: " ++ z ++ ")"
+             which ++ "Mapping " ++ showC (code c) ++ " s = Yield " ++ x ++ " (CC s " ++ y ++ " " ++ z ++ ")"
        where [x,y,z] = (map showC . take 3) (access c ++ repeat '\0')
     p c = [k] /= a && a /= [twiddle k] && null (conditions c)
         where a = access c
diff --git a/tests/Benchmarks.hs b/tests/Benchmarks.hs
new file mode 100644
--- /dev/null
+++ b/tests/Benchmarks.hs
@@ -0,0 +1,400 @@
+{-# LANGUAGE GADTs, MagicHash #-}
+
+import qualified Data.ByteString.Char8 as BS
+import qualified Data.ByteString.Lazy.Char8 as BL
+import qualified Data.ByteString.Lazy.Internal as BL
+import Control.Monad.Trans (liftIO)
+import Control.Exception (evaluate)
+import Criterion.Main
+import Data.Char
+import qualified Codec.Binary.UTF8.Generic as UTF8
+import qualified Data.Text as TS
+import qualified Data.Text.Lazy as TL
+import qualified Data.List as L
+import qualified Data.Text.Encoding as TS
+import qualified Data.Text.Lazy.Encoding as TL
+import qualified Criterion.MultiMap as M
+import Criterion.Config
+import GHC.Base
+
+
+myConfig
+    | False     = defaultConfig {
+                    -- Always display an 800x600 window.
+                    cfgPlot = M.singleton KernelDensity (Window 800 600)
+                  }
+    | otherwise = defaultConfig
+
+instance NFData BS.ByteString
+
+instance NFData BL.ByteString where
+    rnf BL.Empty        = ()
+    rnf (BL.Chunk _ ts) = rnf ts
+
+data B where
+    B :: NFData a => a -> B
+
+instance NFData B where
+    rnf (B b) = rnf b
+
+main = do
+  bsa <- BS.readFile "text/test/russian.txt"
+  let tsa     = TS.decodeUtf8 bsa
+      tsb     = TS.toUpper tsa
+      tla     = TL.fromChunks (TS.chunksOf 16376 tsa)
+      tlb     = TL.fromChunks (TS.chunksOf 16376 tsb)
+      bsb     = TS.encodeUtf8 tsb
+      bla     = BL.fromChunks (chunksOf 16376 bsa)
+      blb     = BL.fromChunks (chunksOf 16376 bsb)
+      bsa_len = BS.length bsa
+      tsa_len = TS.length tsa
+      bla_len = BL.length bla
+      tla_len = TL.length tla
+      la      = UTF8.toString bsa
+      la_len  = L.length la
+      tsb_len = TS.length tsb
+      lb      = TS.unpack tsb
+      bsl     = BS.lines bsa
+      bll     = BL.lines bla
+      tsl     = TS.lines tsa
+      tll     = TL.lines tla
+      ll      = L.lines la
+  defaultMainWith
+    myConfig
+    (liftIO . evaluate $
+     rnf [B tsa, B tsb, B tla, B tlb, B bsa, B bsb, B bla, B blb,
+          B bsa_len, B tsa_len, B bla_len, B tla_len, B la, B la_len,
+          B tsb_len, B lb, B bsl, B bll, B tsl, B tll, B ll])
+    [
+      bgroup "append" [
+        bench "ts" $ nf (TS.append tsb) tsa
+      , bench "tl" $ nf (TL.append tlb) tla
+      , bench "bs" $ nf (BS.append bsb) bsa
+      , bench "bl" $ nf (BL.append blb) bla
+      , bench "l" $ nf ((++) lb) la
+      ],
+      bgroup "concat" [
+        bench "ts" $ nf TS.concat tsl
+      , bench "tl" $ nf TL.concat tll
+      , bench "bs" $ nf BS.concat bsl
+      , bench "bl" $ nf BL.concat bll
+      , bench "l" $ nf L.concat ll
+      ],
+      bgroup "cons" [
+        bench "ts" $ nf (TS.cons c) tsa
+      , bench "tl" $ nf (TL.cons c) tla
+      , bench "bs" $ nf (BS.cons c) bsa
+      , bench "bl" $ nf (BL.cons c) bla
+      , bench "l" $ nf (c:) la
+      ],
+      bgroup "concatMap" [
+        bench "ts" $ nf (TS.concatMap (TS.replicate 3 . TS.singleton)) tsa
+      , bench "tl" $ nf (TL.concatMap (TL.replicate 3 . TL.singleton)) tla
+      , bench "bs" $ nf (BS.concatMap (BS.replicate 3)) bsa
+      , bench "bl" $ nf (BL.concatMap (BL.replicate 3)) bla
+      , bench "l" $ nf (L.concatMap (L.replicate 3 . (:[]))) la
+      ],
+      bgroup "decode" [
+        bench "ts" $ nf TS.decodeUtf8 bsa
+      , bench "tl" $ nf TL.decodeUtf8 bla
+      , bench "bs" $ nf BS.unpack bsa
+      , bench "bl" $ nf BL.unpack bla
+      , bench "l" $ nf UTF8.toString bsa
+      ],
+      bgroup "drop" [
+        bench "ts" $ nf (TS.drop (tsa_len `div` 3)) tsa
+      , bench "tl" $ nf (TL.drop (tla_len `div` 3)) tla
+      , bench "bs" $ nf (BS.drop (bsa_len `div` 3)) bsa
+      , bench "bl" $ nf (BL.drop (bla_len `div` 3)) bla
+      , bench "l" $ nf (L.drop (la_len `div` 3)) la
+      ],
+      bgroup "filter" [
+        bench "ts" $ nf (TS.filter p0) tsa
+      , bench "tl" $ nf (TL.filter p0) tla
+      , bench "bs" $ nf (BS.filter p0) bsa
+      , bench "bl" $ nf (BL.filter p0) bla
+      , bench "l" $ nf (L.filter p0) la
+      ],
+      bgroup "filter.filter" [
+        bench "ts" $ nf (TS.filter p1 . TS.filter p0) tsa
+      , bench "tl" $ nf (TL.filter p1 . TL.filter p0) tla
+      , bench "bs" $ nf (BS.filter p1 . BS.filter p0) bsa
+      , bench "bl" $ nf (BL.filter p1 . BL.filter p0) bla
+      , bench "l" $ nf (L.filter p1 . L.filter p0) la
+      ],
+      bgroup "foldl'" [
+        bench "ts" $ nf (TS.foldl' len 0) tsa
+      , bench "tl" $ nf (TL.foldl' len 0) tla
+      , bench "bs" $ nf (BS.foldl' len 0) bsa
+      , bench "bl" $ nf (BL.foldl' len 0) bla
+      , bench "l" $ nf (L.foldl' len 0) la
+      ],
+      bgroup "foldr" [
+        bench "ts" $ nf (L.length . TS.foldr (:) []) tsa
+      , bench "tl" $ nf (L.length . TL.foldr (:) []) tla
+      , bench "bs" $ nf (L.length . BS.foldr (:) []) bsa
+      , bench "bl" $ nf (L.length . BL.foldr (:) []) bla
+      , bench "l" $ nf (L.length . L.foldr (:) []) la
+      ],
+      bgroup "head" [
+        bench "ts" $ nf TS.head tsa
+      , bench "tl" $ nf TL.head tla
+      , bench "bs" $ nf BS.head bsa
+      , bench "bl" $ nf BL.head bla
+      , bench "l" $ nf L.head la
+      ],
+      bgroup "init" [
+        bench "ts" $ nf TS.init tsa
+      , bench "tl" $ nf TL.init tla
+      , bench "bs" $ nf BS.init bsa
+      , bench "bl" $ nf BL.init bla
+      , bench "l" $ nf L.init la
+      ],
+      bgroup "intercalate" [
+        bench "ts" $ nf (TS.intercalate tsw) tsl
+      , bench "tl" $ nf (TL.intercalate tlw) tll
+      , bench "bs" $ nf (BS.intercalate bsw) bsl
+      , bench "bl" $ nf (BL.intercalate blw) bll
+      , bench "l" $ nf (L.intercalate lw) ll
+      ],
+      bgroup "intersperse" [
+        bench "ts" $ nf (TS.intersperse c) tsa
+      , bench "tl" $ nf (TL.intersperse c) tla
+      , bench "bs" $ nf (BS.intersperse c) bsa
+      , bench "bl" $ nf (BL.intersperse c) bla
+      , bench "l" $ nf (L.intersperse c) la
+      ],
+      bgroup "isInfixOf" [
+        bench "ts" $ nf (TS.isInfixOf tsw) tsa
+      , bench "tl" $ nf (TL.isInfixOf tlw) tla
+      , bench "bs" $ nf (BS.isInfixOf bsw) bsa
+        -- no isInfixOf for lazy bytestrings
+      , bench "l" $ nf (L.isInfixOf lw) la
+      ],
+      bgroup "last" [
+        bench "ts" $ nf TS.last tsa
+      , bench "tl" $ nf TL.last tla
+      , bench "bs" $ nf BS.last bsa
+      , bench "bl" $ nf BL.last bla
+      , bench "l" $ nf L.last la
+      ],
+      bgroup "map" [
+        bench "ts" $ nf (TS.map f) tsa
+      , bench "tl" $ nf (TL.map f) tla
+      , bench "bs" $ nf (BS.map f) bsa
+      , bench "bl" $ nf (BL.map f) bla
+      , bench "l" $ nf (L.map f) la
+      ],
+      bgroup "map.map" [
+        bench "ts" $ nf (TS.map f . TS.map f) tsa
+      , bench "tl" $ nf (TL.map f . TL.map f) tla
+      , bench "bs" $ nf (BS.map f . BS.map f) bsa
+      , bench "bl" $ nf (BL.map f . BL.map f) bla
+      , bench "l" $ nf (L.map f . L.map f) la
+      ],
+      bgroup "replicate char" [
+        bench "ts" $ nf (TS.replicate bsa_len) (TS.singleton c)
+      , bench "tl" $ nf (TL.replicate (fromIntegral bsa_len)) (TL.singleton c)
+      , bench "bs" $ nf (BS.replicate bsa_len) c
+      , bench "bl" $ nf (BL.replicate (fromIntegral bsa_len)) c
+      , bench "l" $ nf (L.replicate bsa_len) c
+      ],
+      bgroup "replicate string" [
+        bench "ts" $ nf (TS.replicate (bsa_len `div` TS.length tsw)) tsw
+      , bench "tl" $ nf (TL.replicate (fromIntegral bsa_len `div` TL.length tlw)) tlw
+      , bench "l" $ nf (replicat (bsa_len `div` TS.length tsw)) lw
+      ],
+      bgroup "reverse" [
+        bench "ts" $ nf TS.reverse tsa
+      , bench "tl" $ nf TL.reverse tla
+      , bench "bs" $ nf BS.reverse bsa
+      , bench "bl" $ nf BL.reverse bla
+      , bench "l" $ nf L.reverse la
+      ],
+      bgroup "take" [
+        bench "ts" $ nf (TS.take (tsa_len `div` 3)) tsa
+      , bench "tl" $ nf (TL.take (tla_len `div` 3)) tla
+      , bench "bs" $ nf (BS.take (bsa_len `div` 3)) bsa
+      , bench "bl" $ nf (BL.take (bla_len `div` 3)) bla
+      , bench "l" $ nf (L.take (la_len `div` 3)) la
+      ],
+      bgroup "tail" [
+        bench "ts" $ nf TS.tail tsa
+      , bench "tl" $ nf TL.tail tla
+      , bench "bs" $ nf BS.tail bsa
+      , bench "bl" $ nf BL.tail bla
+      , bench "l" $ nf L.tail la
+      ],
+      bgroup "toLower" [
+        bench "ts" $ nf TS.toLower tsa
+      , bench "tl" $ nf TL.toLower tla
+      , bench "bs" $ nf (BS.map toLower) bsa
+      , bench "bl" $ nf (BL.map toLower) bla
+      , bench "l" $ nf (L.map toLower) la
+      ],
+      bgroup "toUpper" [
+        bench "ts" $ nf TS.toUpper tsa
+      , bench "tl" $ nf TL.toUpper tla
+      , bench "bs" $ nf (BS.map toUpper) bsa
+      , bench "bl" $ nf (BL.map toUpper) bla
+      , bench "l" $ nf (L.map toUpper) la
+      ],
+      bgroup "words" [
+        bench "ts" $ nf TS.words tsa
+      , bench "tl" $ nf TL.words tla
+      , bench "bs" $ nf BS.words bsa
+      , bench "bl" $ nf BL.words bla
+      , bench "l" $ nf L.words la
+      ],
+      bgroup "zipWith" [
+        bench "ts" $ nf (TS.zipWith min tsb) tsa
+      , bench "tl" $ nf (TL.zipWith min tlb) tla
+      , bench "bs" $ nf (BS.zipWith min bsb) bsa
+      , bench "bl" $ nf (BL.zipWith min blb) bla
+      , bench "l" $ nf (L.zipWith min lb) la
+      ],
+      bgroup "length" [
+        bgroup "cons" [
+          bench "ts" $ nf (TS.length . TS.cons c) tsa
+        , bench "tl" $ nf (TL.length . TL.cons c) tla
+        , bench "bs" $ nf (BS.length . BS.cons c) bsa
+        , bench "bl" $ nf (BL.length . BL.cons c) bla
+        , bench "l" $ nf (L.length . (:) c) la
+        ],
+        bgroup "decode" [
+          bench "ts" $ nf (TS.length . TS.decodeUtf8) bsa
+        , bench "tl" $ nf (TL.length . TL.decodeUtf8) bla
+        , bench "bs" $ nf (L.length . BS.unpack) bsa
+        , bench "bl" $ nf (L.length . BL.unpack) bla
+        , bench "utf8-string" $ nf (L.length . UTF8.toString) bsa
+        ],
+        bgroup "drop" [
+          bench "ts" $ nf (TS.length . TS.drop (tsa_len `div` 3)) tsa
+        , bench "tl" $ nf (TL.length . TL.drop (tla_len `div` 3)) tla
+        , bench "bs" $ nf (BS.length . BS.drop (bsa_len `div` 3)) bsa
+        , bench "bl" $ nf (BL.length . BL.drop (bla_len `div` 3)) bla
+        , bench "l" $ nf (L.length . L.drop (la_len `div` 3)) la
+        ],
+        bgroup "filter" [
+          bench "ts" $ nf (TS.length . TS.filter p0) tsa
+        , bench "tl" $ nf (TL.length . TL.filter p0) tla
+        , bench "bs" $ nf (BS.length . BS.filter p0) bsa
+        , bench "bl" $ nf (BL.length . BL.filter p0) bla
+        , bench "l" $ nf (L.length . L.filter p0) la
+        ],
+        bgroup "filter.filter" [
+          bench "ts" $ nf (TS.length . TS.filter p1 . TS.filter p0) tsa
+        , bench "tl" $ nf (TL.length . TL.filter p1 . TL.filter p0) tla
+        , bench "bs" $ nf (BS.length . BS.filter p1 . BS.filter p0) bsa
+        , bench "bl" $ nf (BL.length . BL.filter p1 . BL.filter p0) bla
+        , bench "l" $ nf (L.length . L.filter p1 . L.filter p0) la
+        ],
+        bgroup "init" [
+          bench "ts" $ nf (TS.length . TS.init) tsa
+        , bench "tl" $ nf (TL.length . TL.init) tla
+        , bench "bs" $ nf (BS.length . BS.init) bsa
+        , bench "bl" $ nf (BL.length . BL.init) bla
+        , bench "l" $ nf (L.length . L.init) la
+        ],
+        bgroup "intercalate" [
+          bench "ts" $ nf (TS.length . TS.intercalate tsw) tsl
+        , bench "tl" $ nf (TL.length . TL.intercalate tlw) tll
+        , bench "bs" $ nf (BS.length . BS.intercalate bsw) bsl
+        , bench "bl" $ nf (BL.length . BL.intercalate blw) bll
+        , bench "l" $ nf (L.length . L.intercalate lw) ll
+        ],
+        bgroup "intersperse" [
+          bench "ts" $ nf (TS.length . TS.intersperse c) tsa
+        , bench "tl" $ nf (TL.length . TL.intersperse c) tla
+        , bench "bs" $ nf (BS.length . BS.intersperse c) bsa
+        , bench "bl" $ nf (BL.length . BL.intersperse c) bla
+        , bench "l" $ nf (L.length . L.intersperse c) la
+        ],
+        bgroup "map" [
+          bench "ts" $ nf (TS.length . TS.map f) tsa
+        , bench "tl" $ nf (TL.length . TL.map f) tla
+        , bench "bs" $ nf (BS.length . BS.map f) bsa
+        , bench "bl" $ nf (BL.length . BL.map f) bla
+        , bench "l" $ nf (L.length . L.map f) la
+        ],
+        bgroup "map.map" [
+          bench "ts" $ nf (TS.length . TS.map f . TS.map f) tsa
+        , bench "tl" $ nf (TL.length . TL.map f . TL.map f) tla
+        , bench "bs" $ nf (BS.length . BS.map f . BS.map f) bsa
+        , bench "l" $ nf (L.length . L.map f . L.map f) la
+        ],
+        bgroup "replicate char" [
+          bench "ts" $ nf (TS.length . TS.replicate bsa_len) (TS.singleton c)
+        , bench "tl" $ nf (TL.length . TL.replicate (fromIntegral bsa_len)) (TL.singleton c)
+        , bench "bs" $ nf (BS.length . BS.replicate bsa_len) c
+        , bench "bl" $ nf (BL.length . BL.replicate (fromIntegral bsa_len)) c
+        , bench "l" $ nf (L.length . L.replicate bsa_len) c
+        ],
+        bgroup "replicate string" [
+          bench "ts" $ nf (TS.length . TS.replicate (bsa_len `div` TS.length tsw)) tsw
+        , bench "tl" $ nf (TL.length . TL.replicate (fromIntegral bsa_len `div` TL.length tlw)) tlw
+        , bench "l" $ nf (L.length . replicat (bsa_len `div` TS.length tsw)) lw
+        ],
+        bgroup "take" [
+          bench "ts" $ nf (TS.length . TS.take (tsa_len `div` 3)) tsa
+        , bench "tl" $ nf (TL.length . TL.take (tla_len `div` 3)) tla
+        , bench "bs" $ nf (BS.length . BS.take (bsa_len `div` 3)) bsa
+        , bench "bl" $ nf (BL.length . BL.take (bla_len `div` 3)) bla
+        , bench "l" $ nf (L.length . L.take (la_len `div` 3)) la
+        ],
+        bgroup "tail" [
+          bench "ts" $ nf (TS.length . TS.tail) tsa
+        , bench "tl" $ nf (TL.length . TL.tail) tla
+        , bench "bs" $ nf (BS.length . BS.tail) bsa
+        , bench "bl" $ nf (BL.length . BL.tail) bla
+        , bench "l" $ nf (L.length . L.tail) la
+        ],
+        bgroup "toLower" [
+          bench "ts" $ nf (TS.length . TS.toLower) tsa
+        , bench "tl" $ nf (TL.length . TL.toLower) tla
+        , bench "bs" $ nf (BS.length . BS.map toLower) bsa
+        , bench "bl" $ nf (BL.length . BL.map toLower) bla
+        , bench "l" $ nf (L.length . L.map toLower) la
+        ],
+        bgroup "toUpper" [
+          bench "ts" $ nf (TS.length . TS.toUpper) tsa
+        , bench "tl" $ nf (TL.length . TL.toUpper) tla
+        , bench "bs" $ nf (BS.length . BS.map toUpper) bsa
+        , bench "bl" $ nf (BL.length . BL.map toUpper) bla
+        , bench "l" $ nf (L.length . L.map toUpper) la
+        ],
+        bgroup "words" [
+          bench "ts" $ nf (L.length . TS.words) tsa
+        , bench "tl" $ nf (L.length . TL.words) tla
+        , bench "bs" $ nf (L.length . BS.words) bsa
+        , bench "bl" $ nf (L.length . BL.words) bla
+        , bench "l" $ nf (L.length . L.words) la
+        ],
+        bgroup "zipWith" [
+          bench "ts" $ nf (TS.length . TS.zipWith min tsb) tsa
+        , bench "tl" $ nf (TL.length . TL.zipWith min tlb) tla
+        , bench "bs" $ nf (L.length . BS.zipWith min bsb) bsa
+        , bench "bl" $ nf (L.length . BL.zipWith min blb) bla
+        , bench "l" $ nf (L.length . L.zipWith min lb) la
+        ]
+      ]
+    ]
+  where
+    c  = 'й'
+    p0 = (== c)
+    p1 = (/= 'д')
+    lw  = "право"
+    bsw  = UTF8.fromString lw
+    blw  = BL.fromChunks [bsw]
+    tsw  = TS.pack lw
+    tlw  = TL.fromChunks [tsw]
+    f (C# c#) = C# (chr# (ord# c# +# 1#))
+    len l _ = l + (1::Int)
+    replicat n = concat . L.replicate n
+
+chunksOf :: Int -> BS.ByteString -> [BS.ByteString]
+chunksOf k = go
+  where
+    go t = case BS.splitAt k t of
+             (a,b) | BS.null a -> []
+                   | otherwise -> a : go b
diff --git a/tests/Makefile b/tests/Makefile
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -2,9 +2,10 @@
 ghc := ghc
 ghc-opt-flags = -O0
 ghc-base-flags := -funbox-strict-fields -package criterion \
-	-package bytestring -package QuickCheck -package test-framework \
-	-package test-framework-quickcheck -ignore-package text \
+	-package bytestring -ignore-package text \
 	-fno-ignore-asserts
+ghc-test-flags := -package QuickCheck -package test-framework \
+	-package test-framework-quickcheck
 ghc-base-flags += -Wall -fno-warn-orphans -fno-warn-missing-signatures
 ghc-flags := $(ghc-base-flags) -i../dist/build -package-name text-$(version)
 ghc-hpc-flags := $(ghc-base-flags) -fhpc -fno-ignore-asserts -odir hpcdir \
@@ -15,7 +16,7 @@
 
 cabal := $(shell which cabal 2>/dev/null)
 
-all: qc coverage
+all: bm qc coverage
 
 lib: $(lib)
 
@@ -28,6 +29,7 @@
 	cd .. && cabal build
 endif
 
+Properties.o qc qc-hpc: ghc-flags += $(ghc-test-flags)
 Properties.o: QuickCheckUtils.o SlowFunctions.o
 
 QuickCheckUtils.o: $(lib)
@@ -35,7 +37,7 @@
 qc: Properties.o QuickCheckUtils.o SlowFunctions.o
 	$(ghc) $(ghc-flags) -threaded -o $@ $^ $(lib)
 
-sb: SearchBench.o
+sb: SearchBench.o SlowFunctions.o
 	$(ghc) $(ghc-flags) -threaded -o $@ $^ $(lib)
 
 qc-hpc: Properties.hs QuickCheckUtils.hs $(lib-srcs:%=../%)
@@ -52,6 +54,12 @@
 	  --exclude=Data.Text.Fusion.CaseMapping \
 	  --exclude=QuickCheckUtils --srcdir=.. --srcdir=. --destdir=$(dir $@)
 
+Benchmarks.o: ghc-opt-flags = -O
+bm Benchmarks.o: ghc-flags += -hide-package transformers -package utf8-string
+bm: Benchmarks.o
+	$(ghc) $(ghc-flags) -o $@ $^ $(lib)
+
+SlowFunctions.o: ghc-opt-flags = -O2
 SearchBench.o: ghc-opt-flags = -O
 %.o: %.hs
 	$(ghc) $(ghc-flags) $(ghc-opt-flags) -c -o $@ $<
@@ -66,4 +74,4 @@
 	curl -O http://projects.haskell.org/text/text-testdata.tar.bz2
 
 clean:
-	-rm -rf *.o *.hi *.tix qc qc-hpc hpcdir .hpc qc-hpc-html
+	-rm -rf *.o *.hi *.tix bm qc qc-hpc hpcdir .hpc qc-hpc-html
diff --git a/text.cabal b/text.cabal
--- a/text.cabal
+++ b/text.cabal
@@ -1,5 +1,5 @@
 name:           text
-version:        0.5
+version:        0.6
 synopsis:       An efficient packed Unicode text type
 description:    An efficient packed Unicode text type.
 license:        BSD3
@@ -23,6 +23,7 @@
     scripts/SpecialCasing.hs
     scripts/SpecialCasing.txt
     tests/Makefile
+    tests/Benchmarks.hs
     tests/Properties.hs
     tests/QuickCheckUtils.hs
     tests/SlowFunctions.hs
@@ -63,7 +64,8 @@
 
   build-depends:
     base       < 5,
-    bytestring >= 0.9 && < 1.0
+    bytestring >= 0.9 && < 1.0,
+    deepseq    >= 1.1.0.0
   if impl(ghc >= 6.10)
     build-depends:
       ghc-prim, base >= 4
