diff --git a/library/TextBuilderDev.hs b/library/TextBuilderDev.hs
--- a/library/TextBuilderDev.hs
+++ b/library/TextBuilderDev.hs
@@ -1,6 +1,5 @@
 module TextBuilderDev
-  ( -- * --
-    TextBuilder,
+  ( TextBuilder,
 
     -- * Accessors
     buildText,
@@ -78,20 +77,15 @@
 import qualified Data.ByteString as ByteString
 import qualified Data.List.Split as Split
 import qualified Data.Text as Text
-import qualified Data.Text.Array as B
-import qualified Data.Text.Encoding as E
-import qualified Data.Text.Encoding.Error as E
+import qualified Data.Text.Array as TextArray
 import qualified Data.Text.IO as Text
-import qualified Data.Text.Internal as C
+import qualified Data.Text.Internal as TextInternal
 import qualified Data.Text.Lazy as TextLazy
 import qualified Data.Text.Lazy.Builder as TextLazyBuilder
 import qualified DeferredFolds.Unfoldr as Unfoldr
 import TextBuilderDev.Prelude hiding (intercalate, length, null)
-#if MIN_VERSION_text(2,0,0)
-import qualified TextBuilderDev.UTF8 as D
-#else
-import qualified TextBuilderDev.UTF16 as D
-#endif
+import qualified TextBuilderDev.Utf16View as Utf16View
+import qualified TextBuilderDev.Utf8View as Utf8View
 
 -- * --
 
@@ -143,6 +137,22 @@
   toTextBuilder = text . TextLazy.toStrict . TextLazyBuilder.toLazyText
   fromTextBuilder = TextLazyBuilder.fromText . buildText
 
+-- * Action
+
+newtype Action
+  = Action (forall s. TextArray.MArray s -> Int -> ST s Int)
+
+instance Semigroup Action where
+  {-# INLINE (<>) #-}
+  Action writeL <> Action writeR =
+    Action $ \array offset -> do
+      offsetAfter1 <- writeL array offset
+      writeR array offsetAfter1
+
+instance Monoid Action where
+  {-# INLINE mempty #-}
+  mempty = Action $ const $ return
+
 -- * --
 
 -- |
@@ -151,26 +161,17 @@
 data TextBuilder
   = TextBuilder !Action !Int !Int
 
-newtype Action
-  = Action (forall s. B.MArray s -> Int -> ST s ())
-
 instance Semigroup TextBuilder where
-  (<>) (TextBuilder (Action action1) arraySize1 charsAmount1) (TextBuilder (Action action2) arraySize2 charsAmount2) =
-    TextBuilder action arraySize charsAmount
+  (<>) (TextBuilder action1 estimatedArraySize1 textLength1) (TextBuilder action2 estimatedArraySize2 textLength2) =
+    TextBuilder action estimatedArraySize textLength
     where
-      action =
-        Action $ \array offset -> do
-          action1 array offset
-          action2 array (offset + arraySize1)
-      arraySize =
-        arraySize1 + arraySize2
-      charsAmount =
-        charsAmount1 + charsAmount2
+      action = action1 <> action2
+      estimatedArraySize = estimatedArraySize1 + estimatedArraySize2
+      textLength = textLength1 + textLength2
 
 instance Monoid TextBuilder where
   {-# INLINE mempty #-}
-  mempty =
-    TextBuilder (Action (\_ _ -> return ())) 0 0
+  mempty = TextBuilder mempty 0 0
 
 instance IsString TextBuilder where
   fromString = string
@@ -210,42 +211,40 @@
 
 -- * Accessors
 
--- | Get the amount of characters
+-- | Get the amount of characters.
 {-# INLINE length #-}
 length :: TextBuilder -> Int
 length (TextBuilder _ _ x) = x
 
--- | Check whether the builder is empty
+-- | Check whether the builder is empty.
 {-# INLINE null #-}
 null :: TextBuilder -> Bool
 null = (== 0) . length
 
--- | Execute a builder producing a strict text
+-- | Execute a builder producing a strict text.
 buildText :: TextBuilder -> Text
-buildText (TextBuilder (Action action) arraySize _) =
-  C.text array 0 arraySize
-  where
-    array =
-      runST $ do
-        array <- B.new arraySize
-        action array 0
-        B.unsafeFreeze array
+buildText (TextBuilder (Action action) sizeBound _) =
+  runST $ do
+    array <- TextArray.new sizeBound
+    offsetAfter <- action array 0
+    frozenArray <- TextArray.unsafeFreeze array
+    return $ TextInternal.text frozenArray 0 offsetAfter
 
 -- ** Output IO
 
--- | Put builder, to stdout
+-- | Put builder, to stdout.
 putToStdOut :: TextBuilder -> IO ()
 putToStdOut = Text.hPutStr stdout . buildText
 
--- | Put builder, to stderr
+-- | Put builder, to stderr.
 putToStdErr :: TextBuilder -> IO ()
 putToStdErr = Text.hPutStr stderr . buildText
 
--- | Put builder, followed by a line, to stdout
+-- | Put builder, followed by a line, to stdout.
 putLnToStdOut :: TextBuilder -> IO ()
 putLnToStdOut = Text.hPutStrLn stdout . buildText
 
--- | Put builder, followed by a line, to stderr
+-- | Put builder, followed by a line, to stderr.
 putLnToStdErr :: TextBuilder -> IO ()
 putLnToStdErr = Text.hPutStrLn stderr . buildText
 
@@ -261,48 +260,56 @@
 force :: TextBuilder -> TextBuilder
 force = text . buildText
 
--- | Unicode character
+-- | Unicode character.
 {-# INLINE char #-}
 char :: Char -> TextBuilder
-char x =
-  unicodeCodePoint (ord x)
+char = unicodeCodePoint . ord
 
 #if MIN_VERSION_text(2,0,0)
 
--- | Unicode code point
+-- | Unicode code point.
 {-# INLINE unicodeCodePoint #-}
 unicodeCodePoint :: Int -> TextBuilder
 unicodeCodePoint x =
-  D.unicodeCodePoint x utf8CodeUnits1 utf8CodeUnits2 utf8CodeUnits3 utf8CodeUnits4
+  Utf8View.unicodeCodePoint x utf8CodeUnits1 utf8CodeUnits2 utf8CodeUnits3 utf8CodeUnits4
 
 {-# INLINEABLE utf8CodeUnits1 #-}
 utf8CodeUnits1 :: Word8 -> TextBuilder
 utf8CodeUnits1 unit1 = TextBuilder action 1 1
-  where action = Action $ \array offset -> B.unsafeWrite array offset unit1
+  where
+    action = Action $ \array offset ->
+      TextArray.unsafeWrite array offset unit1
+        $> succ offset
 
 {-# INLINEABLE utf8CodeUnits2 #-}
 utf8CodeUnits2 :: Word8 -> Word8 -> TextBuilder
 utf8CodeUnits2 unit1 unit2 = TextBuilder action 2 1
-  where action = Action $ \array offset -> do
-          B.unsafeWrite array (offset + 0) unit1
-          B.unsafeWrite array (offset + 1) unit2
+  where
+    action = Action $ \array offset -> do
+      TextArray.unsafeWrite array (offset + 0) unit1
+      TextArray.unsafeWrite array (offset + 1) unit2
+      return $ offset + 2
 
 {-# INLINEABLE utf8CodeUnits3 #-}
 utf8CodeUnits3 :: Word8 -> Word8 -> Word8 -> TextBuilder
 utf8CodeUnits3 unit1 unit2 unit3 = TextBuilder action 3 1
-  where action = Action $ \array offset -> do
-          B.unsafeWrite array (offset + 0) unit1
-          B.unsafeWrite array (offset + 1) unit2
-          B.unsafeWrite array (offset + 2) unit3
+  where
+    action = Action $ \array offset -> do
+      TextArray.unsafeWrite array (offset + 0) unit1
+      TextArray.unsafeWrite array (offset + 1) unit2
+      TextArray.unsafeWrite array (offset + 2) unit3
+      return $ offset + 3
 
 {-# INLINEABLE utf8CodeUnits4 #-}
 utf8CodeUnits4 :: Word8 -> Word8 -> Word8 -> Word8 -> TextBuilder
 utf8CodeUnits4 unit1 unit2 unit3 unit4 = TextBuilder action 4 1
-  where action = Action $ \array offset -> do
-          B.unsafeWrite array (offset + 0) unit1
-          B.unsafeWrite array (offset + 1) unit2
-          B.unsafeWrite array (offset + 2) unit3
-          B.unsafeWrite array (offset + 3) unit4
+  where
+    action = Action $ \array offset -> do
+      TextArray.unsafeWrite array (offset + 0) unit1
+      TextArray.unsafeWrite array (offset + 1) unit2
+      TextArray.unsafeWrite array (offset + 2) unit3
+      TextArray.unsafeWrite array (offset + 3) unit4
+      return $ offset + 4
 
 {-# INLINE utf16CodeUnits1 #-}
 utf16CodeUnits1 :: Word16 -> TextBuilder
@@ -316,22 +323,24 @@
 
 #else
 
--- | Unicode code point
+-- | Unicode code point.
 {-# INLINE unicodeCodePoint #-}
 unicodeCodePoint :: Int -> TextBuilder
 unicodeCodePoint x =
-  D.unicodeCodePoint x utf16CodeUnits1 utf16CodeUnits2
+  Utf16View.unicodeCodePoint x utf16CodeUnits1 utf16CodeUnits2
 
--- | Single code-unit UTF-16 character
+-- | Single code-unit UTF-16 character.
 {-# INLINEABLE utf16CodeUnits1 #-}
 utf16CodeUnits1 :: Word16 -> TextBuilder
 utf16CodeUnits1 unit =
   TextBuilder action 1 1
   where
     action =
-      Action $ \array offset -> B.unsafeWrite array offset unit
+      Action $ \array offset ->
+        TextArray.unsafeWrite array offset unit
+          $> succ offset
 
--- | Double code-unit UTF-16 character
+-- | Double code-unit UTF-16 character.
 {-# INLINEABLE utf16CodeUnits2 #-}
 utf16CodeUnits2 :: Word16 -> Word16 -> TextBuilder
 utf16CodeUnits2 unit1 unit2 =
@@ -339,36 +348,40 @@
   where
     action =
       Action $ \array offset -> do
-        B.unsafeWrite array offset unit1
-        B.unsafeWrite array (succ offset) unit2
+        TextArray.unsafeWrite array offset unit1
+        TextArray.unsafeWrite array (succ offset) unit2
+        return $ offset + 2
 
--- | Single code-unit UTF-8 character
+-- | Single code-unit UTF-8 character.
 {-# INLINE utf8CodeUnits1 #-}
 utf8CodeUnits1 :: Word8 -> TextBuilder
 utf8CodeUnits1 unit1 =
-  D.utf8CodeUnits1 unit1 utf16CodeUnits1 utf16CodeUnits2
+  Utf16View.utf8CodeUnits1 unit1 utf16CodeUnits1 utf16CodeUnits2
 
--- | Double code-unit UTF-8 character
+-- | Double code-unit UTF-8 character.
 {-# INLINE utf8CodeUnits2 #-}
 utf8CodeUnits2 :: Word8 -> Word8 -> TextBuilder
 utf8CodeUnits2 unit1 unit2 =
-  D.utf8CodeUnits2 unit1 unit2 utf16CodeUnits1 utf16CodeUnits2
+  Utf16View.utf8CodeUnits2 unit1 unit2 utf16CodeUnits1 utf16CodeUnits2
 
--- | Triple code-unit UTF-8 character
+-- | Triple code-unit UTF-8 character.
 {-# INLINE utf8CodeUnits3 #-}
 utf8CodeUnits3 :: Word8 -> Word8 -> Word8 -> TextBuilder
 utf8CodeUnits3 unit1 unit2 unit3 =
-  D.utf8CodeUnits3 unit1 unit2 unit3 utf16CodeUnits1 utf16CodeUnits2
+  Utf16View.utf8CodeUnits3 unit1 unit2 unit3 utf16CodeUnits1 utf16CodeUnits2
 
--- | UTF-8 character out of 4 code units
+-- | UTF-8 character out of 4 code units.
 {-# INLINE utf8CodeUnits4 #-}
 utf8CodeUnits4 :: Word8 -> Word8 -> Word8 -> Word8 -> TextBuilder
 utf8CodeUnits4 unit1 unit2 unit3 unit4 =
-  D.utf8CodeUnits4 unit1 unit2 unit3 unit4 utf16CodeUnits1 utf16CodeUnits2
+  Utf16View.utf8CodeUnits4 unit1 unit2 unit3 unit4 utf16CodeUnits1 utf16CodeUnits2
 
 #endif
 
--- | ASCII byte string
+-- | ASCII byte string.
+--
+-- It's your responsibility to ensure that the bytes are in proper range,
+-- otherwise the produced text will be broken.
 {-# INLINEABLE asciiByteString #-}
 asciiByteString :: ByteString -> TextBuilder
 asciiByteString byteString =
@@ -378,37 +391,44 @@
     action =
       Action $ \array ->
         let step byte next index = do
-              B.unsafeWrite array index (fromIntegral byte)
+              TextArray.unsafeWrite array index (fromIntegral byte)
               next (succ index)
-         in ByteString.foldr step (const (return ())) byteString
+         in ByteString.foldr step return byteString
 
--- | Strict text
+-- | Strict text.
 {-# INLINEABLE text #-}
 text :: Text -> TextBuilder
-text text@(C.Text array offset length) =
+#if MIN_VERSION_text(2,0,0)
+text text@(TextInternal.Text array offset length) =
   TextBuilder action length (Text.length text)
   where
     action =
       Action $ \builderArray builderOffset -> do
-#if MIN_VERSION_text(2,0,0)
-        B.copyI length builderArray builderOffset array offset
+        TextArray.copyI length builderArray builderOffset array offset
+        return $ builderOffset + length
 #else
-        B.copyI builderArray builderOffset array offset (builderOffset + length)
+text text@(TextInternal.Text array offset length) =
+  TextBuilder action length (Text.length text)
+  where
+    action =
+      Action $ \builderArray builderOffset -> do
+        TextArray.copyI builderArray builderOffset array offset (builderOffset + length)
+        return $ builderOffset + length
 #endif
 
--- | Lazy text
+-- | Lazy text.
 {-# INLINE lazyText #-}
 lazyText :: TextLazy.Text -> TextBuilder
 lazyText =
   TextLazy.foldrChunks (mappend . text) mempty
 
--- | String
+-- | String.
 {-# INLINE string #-}
 string :: String -> TextBuilder
 string =
   foldMap char
 
--- | Decimal representation of an integral value
+-- | Decimal representation of an integral value.
 {-# INLINEABLE decimal #-}
 decimal :: Integral a => a -> TextBuilder
 decimal i =
@@ -416,13 +436,13 @@
     then unsignedDecimal i
     else unicodeCodePoint 45 <> unsignedDecimal (negate i)
 
--- | Decimal representation of an unsigned integral value
+-- | Decimal representation of an unsigned integral value.
 {-# INLINEABLE unsignedDecimal #-}
 unsignedDecimal :: Integral a => a -> TextBuilder
 unsignedDecimal =
   foldMap decimalDigit . Unfoldr.decimalDigits
 
--- | Decimal representation of an integral value with thousands separated by the specified character
+-- | Decimal representation of an integral value with thousands separated by the specified character.
 {-# INLINEABLE thousandSeparatedDecimal #-}
 thousandSeparatedDecimal :: Integral a => Char -> a -> TextBuilder
 thousandSeparatedDecimal separatorChar a =
@@ -430,15 +450,32 @@
     then thousandSeparatedUnsignedDecimal separatorChar a
     else unicodeCodePoint 45 <> thousandSeparatedUnsignedDecimal separatorChar (negate a)
 
--- | Decimal representation of an unsigned integral value with thousands separated by the specified character
+-- | Decimal representation of an unsigned integral value with thousands separated by the specified character.
 {-# INLINEABLE thousandSeparatedUnsignedDecimal #-}
 thousandSeparatedUnsignedDecimal :: Integral a => Char -> a -> TextBuilder
-thousandSeparatedUnsignedDecimal separatorChar a =
-  fold $ do
-    (index, digit) <- Unfoldr.zipWithReverseIndex $ Unfoldr.decimalDigits a
-    if mod index 3 == 0 && index /= 0
-      then return (decimalDigit digit <> char separatorChar)
-      else return (decimalDigit digit)
+thousandSeparatedUnsignedDecimal separatorChar =
+  processRightmostDigit
+  where
+    processRightmostDigit value =
+      case divMod value 10 of
+        (value, digit) ->
+          processAnotherDigit [decimalDigit digit] 1 value
+    processAnotherDigit builders index value =
+      if value == 0
+        then mconcat builders
+        else case divMod value 10 of
+          (value, digit) ->
+            if mod index 3 == 0
+              then
+                processAnotherDigit
+                  (decimalDigit digit : char separatorChar : builders)
+                  (succ index)
+                  value
+              else
+                processAnotherDigit
+                  (decimalDigit digit : builders)
+                  (succ index)
+                  value
 
 -- | Data size in decimal notation over amount of bytes.
 {-# INLINEABLE dataSizeInBytesInDecimal #-}
@@ -478,19 +515,19 @@
         then thousandSeparatedDecimal separatorChar byExtraTen
         else thousandSeparatedDecimal separatorChar byExtraTen <> "." <> decimalDigit remainder
 
--- | Unsigned binary number
+-- | Unsigned binary number.
 {-# INLINE unsignedBinary #-}
 unsignedBinary :: Integral a => a -> TextBuilder
 unsignedBinary =
   foldMap decimalDigit . Unfoldr.binaryDigits
 
--- | Unsigned binary number
+-- | Unsigned binary number.
 {-# INLINE unsignedPaddedBinary #-}
 unsignedPaddedBinary :: (Integral a, FiniteBits a) => a -> TextBuilder
 unsignedPaddedBinary a =
   padFromLeft (finiteBitSize a) '0' $ foldMap decimalDigit $ Unfoldr.binaryDigits a
 
--- | Hexadecimal representation of an integral value
+-- | Hexadecimal representation of an integral value.
 {-# INLINE hexadecimal #-}
 hexadecimal :: Integral a => a -> TextBuilder
 hexadecimal i =
@@ -498,19 +535,19 @@
     then unsignedHexadecimal i
     else unicodeCodePoint 45 <> unsignedHexadecimal (negate i)
 
--- | Unsigned hexadecimal representation of an integral value
+-- | Unsigned hexadecimal representation of an integral value.
 {-# INLINE unsignedHexadecimal #-}
 unsignedHexadecimal :: Integral a => a -> TextBuilder
 unsignedHexadecimal =
   foldMap hexadecimalDigit . Unfoldr.hexadecimalDigits
 
--- | Decimal digit
+-- | Decimal digit.
 {-# INLINE decimalDigit #-}
 decimalDigit :: Integral a => a -> TextBuilder
 decimalDigit n =
   unicodeCodePoint (fromIntegral n + 48)
 
--- | Hexadecimal digit
+-- | Hexadecimal digit.
 {-# INLINE hexadecimalDigit #-}
 hexadecimalDigit :: Integral a => a -> TextBuilder
 hexadecimalDigit n =
@@ -518,7 +555,7 @@
     then unicodeCodePoint (fromIntegral n + 48)
     else unicodeCodePoint (fromIntegral n + 87)
 
--- | Intercalate builders
+-- | Intercalate builders.
 {-# INLINE intercalate #-}
 intercalate :: Foldable f => TextBuilder -> f TextBuilder -> TextBuilder
 intercalate separator = extract . foldl' step init
@@ -531,7 +568,7 @@
           else element
     extract (Product2 _ builder) = builder
 
--- | Intercalate projecting values to builder
+-- | Intercalate projecting values to builder.
 {-# INLINE intercalateMap #-}
 intercalateMap :: Foldable f => TextBuilder -> (a -> TextBuilder) -> f a -> TextBuilder
 intercalateMap separator mapper = extract . foldl' step init
@@ -543,7 +580,7 @@
         Just acc -> acc <> separator <> mapper element
     extract = fromMaybe mempty
 
--- | Pad a builder from the left side to the specified length with the specified character
+-- | Pad a builder from the left side to the specified length with the specified character.
 {-# INLINEABLE padFromLeft #-}
 padFromLeft :: Int -> Char -> TextBuilder -> TextBuilder
 padFromLeft paddedLength paddingChar builder =
@@ -552,7 +589,7 @@
         then builder
         else foldMap char (replicate (paddedLength - builderLength) paddingChar) <> builder
 
--- | Pad a builder from the right side to the specified length with the specified character
+-- | Pad a builder from the right side to the specified length with the specified character.
 {-# INLINEABLE padFromRight #-}
 padFromRight :: Int -> Char -> TextBuilder -> TextBuilder
 padFromRight paddedLength paddingChar builder =
@@ -609,7 +646,8 @@
   hours <- state (swap . flip divMod 24)
   days <- get
   return $
-    padFromLeft 2 '0' (decimal days) <> ":"
+    padFromLeft 2 '0' (decimal days)
+      <> ":"
       <> padFromLeft 2 '0' (decimal hours)
       <> ":"
       <> padFromLeft 2 '0' (decimal minutes)
@@ -638,7 +676,8 @@
 {-# INLINE hexData #-}
 hexData :: ByteString -> TextBuilder
 hexData =
-  intercalate " " . fmap mconcat
+  intercalate " "
+    . fmap mconcat
     . Split.chunksOf 2
     . fmap byte
     . ByteString.unpack
diff --git a/library/TextBuilderDev/UTF16.hs b/library/TextBuilderDev/UTF16.hs
deleted file mode 100644
--- a/library/TextBuilderDev/UTF16.hs
+++ /dev/null
@@ -1,48 +0,0 @@
-module TextBuilderDev.UTF16 where
-
-import TextBuilderDev.Prelude
-import qualified TextBuilderDev.Unicode as Unicode
-
--- |
--- A matching function, which chooses the continuation to run.
-type UTF16View =
-  forall x. (Word16 -> x) -> (Word16 -> Word16 -> x) -> x
-
-{-# INLINE char #-}
-char :: Char -> UTF16View
-char x =
-  unicodeCodePoint (ord x)
-
-{-# INLINE unicodeCodePoint #-}
-unicodeCodePoint :: Int -> UTF16View
-unicodeCodePoint x case1 case2 =
-  if x < 0x10000
-    then case1 (fromIntegral x)
-    else case2 case2Unit1 case2Unit2
-  where
-    m =
-      x - 0x10000
-    case2Unit1 =
-      fromIntegral (shiftR m 10 + 0xD800)
-    case2Unit2 =
-      fromIntegral ((m .&. 0x3FF) + 0xDC00)
-
-{-# INLINE utf8CodeUnits1 #-}
-utf8CodeUnits1 :: Word8 -> UTF16View
-utf8CodeUnits1 x case1 _ =
-  case1 (fromIntegral x)
-
-{-# INLINE utf8CodeUnits2 #-}
-utf8CodeUnits2 :: Word8 -> Word8 -> UTF16View
-utf8CodeUnits2 byte1 byte2 case1 _ =
-  case1 (shiftL (fromIntegral byte1 - 0xC0) 6 + fromIntegral byte2 - 0x80)
-
-{-# INLINE utf8CodeUnits3 #-}
-utf8CodeUnits3 :: Word8 -> Word8 -> Word8 -> UTF16View
-utf8CodeUnits3 byte1 byte2 byte3 =
-  unicodeCodePoint (Unicode.utf8CodeUnits3 byte1 byte2 byte3)
-
-{-# INLINE utf8CodeUnits4 #-}
-utf8CodeUnits4 :: Word8 -> Word8 -> Word8 -> Word8 -> UTF16View
-utf8CodeUnits4 byte1 byte2 byte3 byte4 =
-  unicodeCodePoint (Unicode.utf8CodeUnits4 byte1 byte2 byte3 byte4)
diff --git a/library/TextBuilderDev/UTF8.hs b/library/TextBuilderDev/UTF8.hs
deleted file mode 100644
--- a/library/TextBuilderDev/UTF8.hs
+++ /dev/null
@@ -1,33 +0,0 @@
-module TextBuilderDev.UTF8 where
-
-import TextBuilderDev.Prelude
-
--- |
--- A matching function, which chooses the continuation to run.
-type UTF8View =
-  forall x.
-  (Word8 -> x) ->
-  (Word8 -> Word8 -> x) ->
-  (Word8 -> Word8 -> Word8 -> x) ->
-  (Word8 -> Word8 -> Word8 -> Word8 -> x) ->
-  x
-
-{-# INLINE unicodeCodePoint #-}
-unicodeCodePoint :: Int -> UTF8View
-unicodeCodePoint x case1 case2 case3 case4
-  | x < 0x80 = case1 (fromIntegral x)
-  | x < 0x800 =
-      case2
-        (fromIntegral $ x `shiftR` 6 .|. 0xC0)
-        (fromIntegral $ (x .&. 0x3F) .|. 0x80)
-  | x < 0x10000 =
-      case3
-        (fromIntegral $ x `shiftR` 12 .|. 0xE0)
-        (fromIntegral $ (x `shiftR` 6) .&. 0x3F .|. 0x80)
-        (fromIntegral $ (x .&. 0x3F) .|. 0x80)
-  | otherwise =
-      case4
-        (fromIntegral $ x `shiftR` 18 .|. 0xF0)
-        (fromIntegral $ (x `shiftR` 12) .&. 0x3F .|. 0x80)
-        (fromIntegral $ (x `shiftR` 6) .&. 0x3F .|. 0x80)
-        (fromIntegral $ (x .&. 0x3F) .|. 0x80)
diff --git a/library/TextBuilderDev/Unicode.hs b/library/TextBuilderDev/Unicode.hs
--- a/library/TextBuilderDev/Unicode.hs
+++ b/library/TextBuilderDev/Unicode.hs
@@ -9,7 +9,8 @@
 utf8CodeUnits3 byte1 byte2 byte3 =
   shiftL (fromIntegral byte1 - 0xE0) 12
     + shiftL (fromIntegral byte2 - 0x80) 6
-    + fromIntegral byte3 - 0x80
+    + fromIntegral byte3
+    - 0x80
 
 {-# INLINE utf8CodeUnits4 #-}
 utf8CodeUnits4 :: Word8 -> Word8 -> Word8 -> Word8 -> Int
@@ -17,4 +18,5 @@
   shiftL (fromIntegral byte1 - 0xF0) 18
     + shiftL (fromIntegral byte2 - 0x80) 12
     + shiftL (fromIntegral byte3 - 0x80) 6
-    + fromIntegral byte4 - 0x80
+    + fromIntegral byte4
+    - 0x80
diff --git a/library/TextBuilderDev/Utf16View.hs b/library/TextBuilderDev/Utf16View.hs
new file mode 100644
--- /dev/null
+++ b/library/TextBuilderDev/Utf16View.hs
@@ -0,0 +1,48 @@
+module TextBuilderDev.Utf16View where
+
+import TextBuilderDev.Prelude
+import qualified TextBuilderDev.Unicode as Unicode
+
+-- |
+-- A matching function, which chooses the continuation to run.
+type Utf16View =
+  forall x. (Word16 -> x) -> (Word16 -> Word16 -> x) -> x
+
+{-# INLINE char #-}
+char :: Char -> Utf16View
+char x =
+  unicodeCodePoint (ord x)
+
+{-# INLINE unicodeCodePoint #-}
+unicodeCodePoint :: Int -> Utf16View
+unicodeCodePoint x case1 case2 =
+  if x < 0x10000
+    then case1 (fromIntegral x)
+    else case2 case2Unit1 case2Unit2
+  where
+    m =
+      x - 0x10000
+    case2Unit1 =
+      fromIntegral (shiftR m 10 + 0xD800)
+    case2Unit2 =
+      fromIntegral ((m .&. 0x3FF) + 0xDC00)
+
+{-# INLINE utf8CodeUnits1 #-}
+utf8CodeUnits1 :: Word8 -> Utf16View
+utf8CodeUnits1 x case1 _ =
+  case1 (fromIntegral x)
+
+{-# INLINE utf8CodeUnits2 #-}
+utf8CodeUnits2 :: Word8 -> Word8 -> Utf16View
+utf8CodeUnits2 byte1 byte2 case1 _ =
+  case1 (shiftL (fromIntegral byte1 - 0xC0) 6 + fromIntegral byte2 - 0x80)
+
+{-# INLINE utf8CodeUnits3 #-}
+utf8CodeUnits3 :: Word8 -> Word8 -> Word8 -> Utf16View
+utf8CodeUnits3 byte1 byte2 byte3 =
+  unicodeCodePoint (Unicode.utf8CodeUnits3 byte1 byte2 byte3)
+
+{-# INLINE utf8CodeUnits4 #-}
+utf8CodeUnits4 :: Word8 -> Word8 -> Word8 -> Word8 -> Utf16View
+utf8CodeUnits4 byte1 byte2 byte3 byte4 =
+  unicodeCodePoint (Unicode.utf8CodeUnits4 byte1 byte2 byte3 byte4)
diff --git a/library/TextBuilderDev/Utf8View.hs b/library/TextBuilderDev/Utf8View.hs
new file mode 100644
--- /dev/null
+++ b/library/TextBuilderDev/Utf8View.hs
@@ -0,0 +1,33 @@
+module TextBuilderDev.Utf8View where
+
+import TextBuilderDev.Prelude
+
+-- |
+-- A matching function, which chooses the continuation to run.
+type Utf8View =
+  forall x.
+  (Word8 -> x) ->
+  (Word8 -> Word8 -> x) ->
+  (Word8 -> Word8 -> Word8 -> x) ->
+  (Word8 -> Word8 -> Word8 -> Word8 -> x) ->
+  x
+
+{-# INLINE unicodeCodePoint #-}
+unicodeCodePoint :: Int -> Utf8View
+unicodeCodePoint x case1 case2 case3 case4
+  | x < 0x80 = case1 (fromIntegral x)
+  | x < 0x800 =
+      case2
+        (fromIntegral $ x `shiftR` 6 .|. 0xC0)
+        (fromIntegral $ (x .&. 0x3F) .|. 0x80)
+  | x < 0x10000 =
+      case3
+        (fromIntegral $ x `shiftR` 12 .|. 0xE0)
+        (fromIntegral $ (x `shiftR` 6) .&. 0x3F .|. 0x80)
+        (fromIntegral $ (x .&. 0x3F) .|. 0x80)
+  | otherwise =
+      case4
+        (fromIntegral $ x `shiftR` 18 .|. 0xF0)
+        (fromIntegral $ (x `shiftR` 12) .&. 0x3F .|. 0x80)
+        (fromIntegral $ (x `shiftR` 6) .&. 0x3F .|. 0x80)
+        (fromIntegral $ (x .&. 0x3F) .|. 0x80)
diff --git a/test/Main.hs b/test/Main.hs
--- a/test/Main.hs
+++ b/test/Main.hs
@@ -52,8 +52,8 @@
         testProperty "Decimal" $ \(x :: Integer) ->
           (fromString . show) x === (B.buildText (B.decimal x)),
         testProperty "Hexadecimal vs std show" $ \(x :: Integer) ->
-          x >= 0
-            ==> (fromString . showHex x) "" === (B.buildText . B.hexadecimal) x,
+          x >= 0 ==>
+            (fromString . showHex x) "" === (B.buildText . B.hexadecimal) x,
         testProperty "TextBuilderDev.null is isomorphic to Text.null" $ \(text :: Text) ->
           B.null (B.toTextBuilder text) === Text.null text,
         testProperty "(TextBuilderDev.unicodeCodePoint <>) is isomorphic to Text.cons" $
diff --git a/text-builder-dev.cabal b/text-builder-dev.cabal
--- a/text-builder-dev.cabal
+++ b/text-builder-dev.cabal
@@ -1,7 +1,7 @@
 cabal-version: 3.0
 
 name: text-builder-dev
-version: 0.3.3
+version: 0.3.3.1
 category: Text
 synopsis: Edge of developments for "text-builder"
 description:
@@ -22,19 +22,19 @@
   type: git
   location: git://github.com/nikita-volkov/text-builder-dev.git
 
-common language-settings
+common base-settings
   default-extensions: BangPatterns, ConstraintKinds, CPP, DataKinds, DefaultSignatures, DeriveDataTypeable, DeriveFoldable, DeriveFunctor, DeriveGeneric, DeriveTraversable, EmptyDataDecls, FlexibleContexts, FlexibleInstances, FunctionalDependencies, GADTs, GeneralizedNewtypeDeriving, InstanceSigs, LambdaCase, LiberalTypeSynonyms, MagicHash, MultiParamTypeClasses, MultiWayIf, NoImplicitPrelude, NoMonomorphismRestriction, OverloadedStrings, PatternGuards, ParallelListComp, QuasiQuotes, RankNTypes, RecordWildCards, ScopedTypeVariables, StandaloneDeriving, TemplateHaskell, TupleSections, TypeApplications, TypeFamilies, TypeOperators, ViewPatterns
   default-language: Haskell2010
 
 library
-  import: language-settings
+  import: base-settings
   hs-source-dirs: library
   exposed-modules:
     TextBuilderDev
   other-modules:
     TextBuilderDev.Unicode
-    TextBuilderDev.UTF16
-    TextBuilderDev.UTF8
+    TextBuilderDev.Utf16View
+    TextBuilderDev.Utf8View
     TextBuilderDev.Prelude
   build-depends:
     base >=4.11 && <5,
@@ -46,7 +46,7 @@
     transformers >=0.5 && <0.7,
 
 test-suite test
-  import: language-settings
+  import: base-settings
   type: exitcode-stdio-1.0
   hs-source-dirs: test
   main-is: Main.hs
@@ -62,8 +62,9 @@
     text-builder-dev,
 
 benchmark benchmark-text
-  import: language-settings
+  import: base-settings
   type: exitcode-stdio-1.0
+  ghc-options: -O2
   hs-source-dirs: benchmark-text
   main-is: Main.hs
   build-depends:
@@ -72,8 +73,9 @@
     text-builder-dev,
 
 benchmark benchmark-char
-  import: language-settings
+  import: base-settings
   type: exitcode-stdio-1.0
+  ghc-options: -O2
   hs-source-dirs: benchmark-char
   main-is: Main.hs
   build-depends:
