diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,40 @@
+## 0.0.13
+
+Block:
+* Optimise fold
+
+UArray:
+* Re-organise type to be more modular for later change
+* Remove the pinned array explicit status in favor of asking
+  the runtime system directly on demand.
+* Optimise fold operations
+* Optimise all&any
+* Optimise isPrefixOf
+* Optimise isSuffixOf
+* Optimise finding byte
+* Add an optimise function to break on line (CRLF & LF) as part of a stream
+
+String:
+* Optimise length
+* Optimise all&any
+* Optimise foldr
+* Remove many unboxed tuples (next, prev, ..) in favor of a strict unpack
+  constructor
+* Optimise lines using array breakLine
+
+Collection:
+* add stripPrefix & stripSuffix
+
+Tests:
+* Improve performance
+
+Misc:
+* Cleanup Offset/Size types with the C boundary
+* Faster Offset/Size convertions
+* Add Base64 support
+* Add LE/BE instance for NormalForm
+* Add UUID generation and parsing
+
 ## 0.0.12
 
 * Fix build windows building & time subsystem
diff --git a/Foundation.hs b/Foundation.hs
--- a/Foundation.hs
+++ b/Foundation.hs
@@ -86,6 +86,8 @@
     , Prelude.Float
     , Prelude.Double
     , CountOf(..), Offset(..)
+    , toCount
+    , fromCount
       -- ** Collection types
     , UArray
     , PrimType
@@ -197,3 +199,11 @@
 -- | Returns a list of the program's command line arguments (not including the program name).
 getArgs :: Prelude.IO [String]
 getArgs = (Data.List.map fromList <$> System.Environment.getArgs)
+
+fromCount :: CountOf ty -> Prelude.Int
+fromCount (CountOf n) = n
+
+toCount :: Prelude.Int -> CountOf ty
+toCount i
+    | i Prelude.<= 0    = CountOf 0
+    | Prelude.otherwise = CountOf i
diff --git a/Foundation/Array/Bitmap.hs b/Foundation/Array/Bitmap.hs
--- a/Foundation/Array/Bitmap.hs
+++ b/Foundation/Array/Bitmap.hs
@@ -257,7 +257,7 @@
 mutableLength (MutableBitmap sz _) = sz
 
 empty :: Bitmap
-empty = Bitmap 0 A.empty
+empty = Bitmap 0 mempty
 
 new :: PrimMonad prim => CountOf Bool -> prim (MutableBitmap (PrimState prim))
 new sz@(CountOf len) =
@@ -279,7 +279,7 @@
     runST $ do
     mba <- A.new nbElements
     ba  <- loop mba (0 :: Int) allBools
-    return (Bitmap len ba)
+    pure (Bitmap len ba)
   where
     loop mba _ [] = A.unsafeFreeze mba
     loop mba i l  = do
diff --git a/Foundation/Array/Boxed.hs b/Foundation/Array/Boxed.hs
--- a/Foundation/Array/Boxed.hs
+++ b/Foundation/Array/Boxed.hs
@@ -60,6 +60,8 @@
     , foldr1
     , all
     , any
+    , isPrefixOf
+    , isSuffixOf
     , builderAppend
     , builderBuild
     , builderBuild_
@@ -219,7 +221,7 @@
 thaw array = do
     m <- new (length array)
     unsafeCopyAtRO m (Offset 0) array (Offset 0) (length array)
-    return m
+    pure m
 {-# INLINE thaw #-}
 
 freeze :: PrimMonad prim => MArray ty (PrimState prim) -> prim (Array ty)
@@ -277,7 +279,7 @@
   where len = length v'
         endIdx = Offset 0 `offsetPlusE` len
         fill i f' r'
-            | i == endIdx = return r'
+            | i == endIdx = pure r'
             | otherwise   = do f' v' i r'
                                fill (i + Offset 1) f' r'
 
@@ -367,7 +369,7 @@
     r <- new (mconcat $ fmap length l)
     loop r (Offset 0) l
     unsafeFreeze r
-  where loop _ _ []     = return ()
+  where loop _ _ []     = pure ()
         loop r i (x:xs) = do
             unsafeCopyAtRO r i x (Offset 0) lx
             loop r (i `offsetPlusE` lx) xs
@@ -584,7 +586,7 @@
     doSort ford ma = qsort 0 (sizeLastOffset len) >> unsafeFreeze ma
       where
         qsort lo hi
-            | lo >= hi  = return ()
+            | lo >= hi  = pure ()
             | otherwise = do
                 p <- partition lo hi
                 qsort lo (pred p)
@@ -592,16 +594,16 @@
         partition lo hi = do
             pivot <- unsafeRead ma hi
             let loop i j
-                    | j == hi   = return i
+                    | j == hi   = pure i
                     | otherwise = do
                         aj <- unsafeRead ma j
                         i' <- if ford aj pivot == GT
-                                then return i
+                                then pure i
                                 else do
                                     ai <- unsafeRead ma i
                                     unsafeWrite ma j ai
                                     unsafeWrite ma i aj
-                                    return $ i + 1
+                                    pure $ i + 1
                         loop i' (j+1)
 
             i <- loop lo lo
@@ -609,7 +611,7 @@
             ahi <- unsafeRead ma hi
             unsafeWrite ma hi ai
             unsafeWrite ma i ahi
-            return i
+            pure i
 
 filter :: forall ty . (ty -> Bool) -> Array ty -> Array ty
 filter predicate vec = runST (new len >>= copyFilterFreeze predicate (unsafeIndex vec))
@@ -619,7 +621,7 @@
     copyFilterFreeze predi getVec mvec = loop (Offset 0) (Offset 0) >>= freezeUntilIndex mvec
       where
         loop d s
-            | s .==# len  = return d
+            | s .==# len  = pure d
             | predi v     = unsafeWrite mvec d v >> loop (d+1) (s+1)
             | otherwise   = loop d (s+1)
           where
@@ -682,6 +684,22 @@
       | p (unsafeIndex ba i) = True
       | otherwise = loop (i + 1)
 
+isPrefixOf :: Eq ty => Array ty -> Array ty -> Bool
+isPrefixOf pre arr
+    | pLen > pArr = False
+    | otherwise   = pre == take pLen arr
+  where
+    !pLen = length pre
+    !pArr = length arr
+
+isSuffixOf :: Eq ty => Array ty -> Array ty -> Bool
+isSuffixOf suffix arr
+    | pLen > pArr = False
+    | otherwise   = suffix == revTake pLen arr
+  where
+    !pLen = length suffix
+    !pArr = length arr
+
 builderAppend :: PrimMonad state => ty -> Builder (Array ty) (MArray ty) ty state err ()
 builderAppend v = Builder $ State $ \(i, st, e) ->
     if i .==# chunkSize st
@@ -689,13 +707,13 @@
             cur      <- unsafeFreeze (curChunk st)
             newChunk <- new (chunkSize st)
             unsafeWrite newChunk 0 v
-            return ((), (Offset 1, st { prevChunks     = cur : prevChunks st
+            pure ((), (Offset 1, st { prevChunks     = cur : prevChunks st
                                       , prevChunksSize = chunkSize st + prevChunksSize st
                                       , curChunk       = newChunk
                                       }, e))
         else do
             unsafeWrite (curChunk st) i v
-            return ((), (i+1, st, e))
+            pure ((), (i+1, st, e))
 
 builderBuild :: PrimMonad m => Int -> Builder (Array ty) (MArray ty) ty m err () -> m (Either err (Array ty))
 builderBuild sizeChunksI ab
@@ -704,17 +722,17 @@
         first         <- new sizeChunks
         ((), (i, st, e)) <- runState (runBuilder ab) (Offset 0, BuildingState [] (CountOf 0) first sizeChunks, Nothing)
         case e of
-          Just err -> return (Left err)
+          Just err -> pure (Left err)
           Nothing -> do
             cur <- unsafeFreezeShrink (curChunk st) (offsetAsSize i)
             -- Build final array
             let totalSize = prevChunksSize st + offsetAsSize i
             bytes <- new totalSize >>= fillFromEnd totalSize (cur : prevChunks st) >>= unsafeFreeze
-            return (Right bytes)
+            pure (Right bytes)
   where
     sizeChunks = CountOf sizeChunksI
 
-    fillFromEnd _   []     mua = return mua
+    fillFromEnd _   []     mua = pure mua
     fillFromEnd !end (x:xs) mua = do
         let sz = length x
         unsafeCopyAtRO mua (sizeAsOffset (end - sz)) x (Offset 0) sz
diff --git a/Foundation/Array/Unboxed.hs b/Foundation/Array/Unboxed.hs
--- a/Foundation/Array/Unboxed.hs
+++ b/Foundation/Array/Unboxed.hs
@@ -5,11 +5,10 @@
 -- Stability   : experimental
 -- Portability : portable
 --
--- A simple array abstraction that allow to use typed
--- array of bytes where the array is pinned in memory
--- to allow easy use with Foreign interfaces, ByteString
--- and always aligned to 64 bytes.
+-- An unboxed array of primitive types
 --
+-- All the cells in the array are in one chunk of contiguous
+-- memory.
 {-# LANGUAGE MagicHash #-}
 {-# LANGUAGE UnboxedTuples #-}
 {-# LANGUAGE ScopedTypeVariables #-}
@@ -31,7 +30,6 @@
     , unsafeThaw
     -- * Creation
     , new
-    , empty
     , create
     , createFromIO
     , createFromPtr
@@ -68,9 +66,9 @@
     , revTake
     , revSplitAt
     , splitOn
-    , splitElem
     , break
     , breakElem
+    , breakLine
     , elem
     , indices
     , intersperse
@@ -90,6 +88,8 @@
     , foldl1'
     , all
     , any
+    , isPrefixOf
+    , isSuffixOf
     , foreignMem
     , fromForeignPtr
     , builderAppend
@@ -105,76 +105,29 @@
 import           GHC.Word
 import           GHC.ST
 import           GHC.Ptr
-import           GHC.IO (unsafeDupablePerformIO)
 import           GHC.ForeignPtr (ForeignPtr)
 import           Foreign.Marshal.Utils (copyBytes)
-import           Foreign.C.Types (CInt, CSize)
-import qualified Prelude
 import           Foundation.Internal.Base
 import           Foundation.Internal.Primitive
 import           Foundation.Internal.Proxy
 import           Foundation.Primitive.Types.OffsetSize
 import           Foundation.Internal.MonadTrans
 import           Foundation.Collection.NonEmpty
-import qualified Foundation.Primitive.Base16 as Base16
 import           Foundation.Primitive.Monad
 import           Foundation.Primitive.Types
-import           Foundation.Primitive.NormalForm
 import           Foundation.Primitive.FinalPtr
 import           Foundation.Primitive.Utils
 import           Foundation.Primitive.Exception
-import           Foundation.System.Bindings.Hs
+import           Foundation.Primitive.UArray.Base
+import           Foundation.Primitive.Block (Block(..), MutableBlock(..))
 import           Foundation.Array.Unboxed.Mutable hiding (sub, copyToPtr)
 import           Foundation.Numerical
 import           Foundation.Boot.Builder
-import qualified Data.List
-
--- | An array of type built on top of GHC primitive.
---
--- The elements need to have fixed sized and the representation is a
--- packed contiguous array in memory that can easily be passed
--- to foreign interface
-data UArray ty =
-      UVecBA {-# UNPACK #-} !(Offset ty)
-             {-# UNPACK #-} !(CountOf ty)
-             {-# UNPACK #-} !PinnedStatus {- unpinned / pinned flag -}
-                            !ByteArray#
-    | UVecAddr {-# UNPACK #-} !(Offset ty)
-               {-# UNPACK #-} !(CountOf ty)
-                              !(FinalPtr ty)
-    deriving (Typeable)
-
-instance Data ty => Data (UArray ty) where
-    dataTypeOf _ = arrayType
-    toConstr _   = error "toConstr"
-    gunfold _ _  = error "gunfold"
-
-arrayType :: DataType
-arrayType = mkNoRepType "Foundation.UArray"
-
-instance NormalForm (UArray ty) where
-    toNormalForm (UVecBA _ _ _ !_) = ()
-    toNormalForm (UVecAddr {}) = ()
-instance (PrimType ty, Show ty) => Show (UArray ty) where
-    show v = show (toList v)
-instance (PrimType ty, Eq ty) => Eq (UArray ty) where
-    (==) = equal
-instance (PrimType ty, Ord ty) => Ord (UArray ty) where
-    {-# SPECIALIZE instance Ord (UArray Word8) #-}
-    compare = vCompare
-
-instance PrimType ty => Monoid (UArray ty) where
-    mempty  = empty
-    mappend = append
-    mconcat = concat
-
-instance PrimType ty => IsList (UArray ty) where
-    type Item (UArray ty) = ty
-    fromList = vFromList
-    toList = vToList
-
-vectorProxyTy :: UArray ty -> Proxy ty
-vectorProxyTy _ = Proxy
+import           Foundation.System.Bindings.Hs (sysHsMemFindByteBa, sysHsMemFindByteAddr)
+import qualified Foundation.Boot.List as List
+import qualified Foundation.Primitive.Base16 as Base16
+import qualified Foundation.Primitive.UArray.BA as PrimBA
+import qualified Foundation.Primitive.UArray.Addr as PrimAddr
 
 -- | Copy every cells of an existing array to a new array
 copy :: PrimType ty => UArray ty -> UArray ty
@@ -188,7 +141,7 @@
 thaw array = do
     ma <- new (length array)
     unsafeCopyAtRO ma azero array (Offset 0) (length array)
-    return ma
+    pure ma
 {-# INLINE thaw #-}
 
 -- | Return the element at a specific index from an array.
@@ -202,94 +155,18 @@
     !len = length array
 {-# INLINE index #-}
 
--- | Return the element at a specific index from an array without bounds checking.
---
--- Reading from invalid memory can return unpredictable and invalid values.
--- use 'index' if unsure.
-unsafeIndex :: forall ty . PrimType ty => UArray ty -> Offset ty -> ty
-unsafeIndex (UVecBA start _ _ ba) n = primBaIndex ba (start + n)
-unsafeIndex (UVecAddr start _ fptr) n = withUnsafeFinalPtr fptr (\(Ptr addr) -> return (primAddrIndex addr (start+n)) :: IO ty)
-{-# INLINE unsafeIndex #-}
-
-unsafeIndexer :: (PrimMonad prim, PrimType ty) => UArray ty -> ((Offset ty -> ty) -> prim a) -> prim a
-unsafeIndexer (UVecBA start _ _ ba) f = f (\n -> primBaIndex ba (start + n))
-unsafeIndexer (UVecAddr start _ fptr) f = withFinalPtr fptr $ \(Ptr addr) -> f (\n -> primAddrIndex addr (start + n))
-{-# INLINE unsafeIndexer #-}
-
-unsafeDewrap :: (ByteArray# -> Offset ty -> a)
-             -> (Ptr ty -> Offset ty -> ST s a)
-             -> UArray ty
-             -> a
-unsafeDewrap _ g (UVecAddr start _ fptr) = withUnsafeFinalPtr fptr $ \ptr -> g ptr start
-unsafeDewrap f _ (UVecBA start _ _ ba)   = f ba start
-{-# INLINE unsafeDewrap #-}
-
-unsafeDewrap2 :: (ByteArray# -> Offset ty -> ByteArray# -> Offset ty -> a)
-              -> (Ptr ty -> Offset ty -> Ptr ty -> Offset ty -> ST s a)
-              -> (ByteArray# -> Offset ty -> Ptr ty -> Offset ty -> ST s a)
-              -> (Ptr ty -> Offset ty -> ByteArray# -> Offset ty -> ST s a)
-              -> UArray ty
-              -> UArray ty
-              -> a
-unsafeDewrap2 f _ _ _ (UVecBA start1 _ _ ba1)   (UVecBA start2 _ _ ba2)   = f ba1 start1 ba2 start2
-unsafeDewrap2 _ f _ _ (UVecAddr start1 _ fptr1) (UVecAddr start2 _ fptr2) = withUnsafeFinalPtr fptr1 $ \ptr1 ->
-                                                                                  withFinalPtr fptr2 $ \ptr2 -> f ptr1 start1 ptr2 start2
-unsafeDewrap2 _ _ f _ (UVecBA start1 _ _ ba1)   (UVecAddr start2 _ fptr2) = withUnsafeFinalPtr fptr2 $ \ptr2 -> f ba1 start1 ptr2 start2
-unsafeDewrap2 _ _ _ f (UVecAddr start1 _ fptr1) (UVecBA start2 _ _ ba2)   = withUnsafeFinalPtr fptr1 $ \ptr1 -> f ptr1 start1 ba2 start2
-{-# INLINE [2] unsafeDewrap2 #-}
-
 foreignMem :: PrimType ty
            => FinalPtr ty -- ^ the start pointer with a finalizer
            -> CountOf ty  -- ^ the number of elements (in elements, not bytes)
            -> UArray ty
-foreignMem fptr nb = UVecAddr (Offset 0) nb fptr
+foreignMem fptr nb = UArray (Offset 0) nb (UArrayAddr fptr)
 
 fromForeignPtr :: PrimType ty
                => (ForeignPtr ty, Int, Int) -- ForeignPtr, an offset in prim elements, a size in prim elements
                -> UArray ty
-fromForeignPtr (fptr, ofs, len)   = UVecAddr (Offset ofs) (CountOf len) (toFinalPtrForeign fptr)
+fromForeignPtr (fptr, ofs, len) = UArray (Offset ofs) (CountOf len) (UArrayAddr $ toFinalPtrForeign fptr)
 
-length :: UArray ty -> CountOf ty
-length (UVecAddr _ len _) = len
-length (UVecBA _ len _ _) = len
-{-# INLINE[1] length #-}
 
--- TODO Optimise with copyByteArray#
--- | Copy @n@ sequential elements from the specified offset in a source array
---   to the specified position in a destination array.
---
---   This function does not check bounds. Accessing invalid memory can return
---   unpredictable and invalid values.
-unsafeCopyAtRO :: (PrimMonad prim, PrimType ty)
-               => MUArray ty (PrimState prim) -- ^ destination array
-               -> Offset ty                   -- ^ offset at destination
-               -> UArray ty                   -- ^ source array
-               -> Offset ty                   -- ^ offset at source
-               -> CountOf ty                     -- ^ number of elements to copy
-               -> prim ()
-unsafeCopyAtRO (MUVecMA dstStart _ _ dstMba) ed uvec@(UVecBA srcStart _ _ srcBa) es n =
-    primitive $ \st -> (# copyByteArray# srcBa os dstMba od nBytes st, () #)
-  where
-    sz = primSizeInBytes (vectorProxyTy uvec)
-    !(Offset (I# os))   = offsetOfE sz (srcStart+es)
-    !(Offset (I# od))   = offsetOfE sz (dstStart+ed)
-    !(CountOf (I# nBytes)) = sizeOfE sz n
-unsafeCopyAtRO (MUVecMA dstStart _ _ dstMba) ed uvec@(UVecAddr srcStart _ srcFptr) es n =
-    withFinalPtr srcFptr $ \srcPtr ->
-        let !(Ptr srcAddr) = srcPtr `plusPtr` os
-         in primitive $ \s -> (# compatCopyAddrToByteArray# srcAddr dstMba od nBytes s, () #)
-  where
-    sz  = primSizeInBytes (vectorProxyTy uvec)
-    !(Offset os)        = offsetOfE sz (srcStart+es)
-    !(Offset (I# od))   = offsetOfE sz (dstStart+ed)
-    !(CountOf (I# nBytes)) = sizeOfE sz n
-unsafeCopyAtRO dst od src os n = loop od os
-  where
-    !endIndex = os `offsetPlusE` n
-    loop d i
-        | i == endIndex = return ()
-        | otherwise     = unsafeWrite dst d (unsafeIndex src i) >> loop (d+1) (i+1)
-
 -- | Allocate a new array with a fill function that has access to the elements of
 --   the source array.
 unsafeCopyFrom :: (PrimType a, PrimType b)
@@ -301,31 +178,16 @@
 unsafeCopyFrom v' newLen f = new newLen >>= fill 0 >>= unsafeFreeze
   where len = length v'
         fill i r'
-            | i .==# len = return r'
+            | i .==# len = pure r'
             | otherwise  = do f v' i r'
                               fill (i + 1) r'
 
--- | Freeze a mutable array into an array.
---
--- the MUArray must not be changed after freezing.
-unsafeFreeze :: PrimMonad prim => MUArray ty (PrimState prim) -> prim (UArray ty)
-unsafeFreeze (MUVecMA start len pinnedState mba) = primitive $ \s1 ->
-    case unsafeFreezeByteArray# mba s1 of
-        (# s2, ba #) -> (# s2, UVecBA start len pinnedState ba #)
-unsafeFreeze (MUVecAddr start len fptr) = return $ UVecAddr start len fptr
-{-# INLINE unsafeFreeze #-}
-
-unsafeFreezeShrink :: (PrimType ty, PrimMonad prim) => MUArray ty (PrimState prim) -> CountOf ty -> prim (UArray ty)
-unsafeFreezeShrink (MUVecMA start _ pinnedState mba) n = unsafeFreeze (MUVecMA start n pinnedState mba)
-unsafeFreezeShrink (MUVecAddr start _ fptr) n = unsafeFreeze (MUVecAddr start n fptr)
-{-# INLINE unsafeFreezeShrink #-}
-
 freeze :: (PrimType ty, PrimMonad prim) => MUArray ty (PrimState prim) -> prim (UArray ty)
 freeze ma = do
     ma' <- new len
     copyAt ma' (Offset 0) ma (Offset 0) len
     unsafeFreeze ma'
-  where len = CountOf $ mutableLength ma
+  where len = mutableLength ma
 
 freezeShrink :: (PrimType ty, PrimMonad prim) => MUArray ty (PrimState prim) -> CountOf ty -> prim (UArray ty)
 freezeShrink ma n = do
@@ -337,19 +199,11 @@
 unsafeSlide mua s e = doSlide mua s e
   where
     doSlide :: (PrimType ty, PrimMonad prim) => MUArray ty (PrimState prim) -> Offset ty -> Offset ty -> prim ()
-    doSlide (MUVecMA mbStart _ _ mba) start end  =
+    doSlide (MUArray mbStart _ (MUArrayMBA (MutableBlock mba))) start end  =
         primMutableByteArraySlideToStart mba (offsetInBytes $ mbStart+start) (offsetInBytes end)
-    doSlide (MUVecAddr mbStart _ fptr) start end = withFinalPtr fptr $ \(Ptr addr) ->
+    doSlide (MUArray mbStart _ (MUArrayAddr fptr)) start end = withFinalPtr fptr $ \(Ptr addr) ->
         primMutableAddrSlideToStart addr (offsetInBytes $ mbStart+start) (offsetInBytes end)
 
--- | Thaw an immutable array.
---
--- The UArray must not be used after thawing.
-unsafeThaw :: (PrimType ty, PrimMonad prim) => UArray ty -> prim (MUArray ty (PrimState prim))
-unsafeThaw (UVecBA start len pinnedState ba) = primitive $ \st -> (# st, MUVecMA start len pinnedState (unsafeCoerce# ba) #)
-unsafeThaw (UVecAddr start len fptr) = return $ MUVecAddr start len fptr
-{-# INLINE unsafeThaw #-}
-
 -- | Create a new array of size @n by settings each cells through the
 -- function @f.
 create :: forall ty . PrimType ty
@@ -357,7 +211,7 @@
        -> (Offset ty -> ty) -- ^ the function that set the value at the index
        -> UArray ty         -- ^ the array created
 create n initializer
-    | n == 0    = empty
+    | n == 0    = mempty
     | otherwise = runST (new n >>= iter initializer)
   where
     iter :: (PrimType ty, PrimMonad prim) => (Offset ty -> ty) -> MUArray ty (PrimState prim) -> prim (UArray ty)
@@ -375,12 +229,12 @@
              -> (Ptr ty -> IO (CountOf ty)) -- ^ filling function that
              -> IO (UArray ty)
 createFromIO size filler
-    | size == 0 = return empty
+    | size == 0 = pure mempty
     | otherwise = do
         mba <- newPinned size
         r   <- withMutablePtr mba $ \p -> filler p
         case r of
-            0             -> return empty -- make sure we don't keep our array referenced by using empty
+            0             -> pure mempty -- make sure we don't keep our array referenced by using empty
             _ | r < 0     -> error "filler returned negative number"
               | otherwise -> unsafeFreezeShrink mba r
 
@@ -397,209 +251,13 @@
 -----------------------------------------------------------------------
 -- higher level collection implementation
 -----------------------------------------------------------------------
-data BA0 = BA0 !ByteArray# -- zero ba
 
-empty_ :: BA0
-empty_ = runST $ primitive $ \s1 ->
-    case newByteArray# 0# s1           of { (# s2, mba #) ->
-    case unsafeFreezeByteArray# mba s2 of { (# s3, ba  #) ->
-        (# s3, BA0 ba #) }}
-
-empty :: UArray ty
-empty = UVecBA 0 0 unpinned ba where !(BA0 ba) = empty_
-
 singleton :: PrimType ty => ty -> UArray ty
 singleton ty = create 1 (const ty)
 
 replicate :: PrimType ty => CountOf ty -> ty -> UArray ty
 replicate sz ty = create sz (const ty)
 
--- | make an array from a list of elements.
-vFromList :: PrimType ty => [ty] -> UArray ty
-vFromList l = runST $ do
-    ma <- new (CountOf len)
-    iter azero l $ \i x -> unsafeWrite ma i x
-    unsafeFreeze ma
-  where len = Data.List.length l
-        iter _  []     _ = return ()
-        iter !i (x:xs) z = z i x >> iter (i+1) xs z
-
--- | transform an array to a list.
-vToList :: forall ty . PrimType ty => UArray ty -> [ty]
-vToList a
-    | len == 0  = []
-    | otherwise = unsafeDewrap goBa goPtr a
-  where
-    !len = length a
-    goBa ba start = loop start
-      where
-        !end = start `offsetPlusE` len
-        loop !i | i == end  = []
-                | otherwise = primBaIndex ba i : loop (i+1)
-    goPtr (Ptr addr) start = pureST (loop start)
-      where
-        !end = start `offsetPlusE` len
-        loop !i | i == end  = []
-                | otherwise = primAddrIndex addr i : loop (i+1)
-
--- | Check if two vectors are identical
-equal :: (PrimType ty, Eq ty) => UArray ty -> UArray ty -> Bool
-equal a b
-    | la /= lb  = False
-    | otherwise = unsafeDewrap2 goBaBa goPtrPtr goBaPtr goPtrBa a b
-  where
-    !la = length a
-    !lb = length b
-    goBaBa ba1 start1 ba2 start2 = loop start1 start2
-      where
-        !end = start1 `offsetPlusE` la
-        loop !i !o | i == end  = True
-                   | otherwise = primBaIndex ba1 i == primBaIndex ba2 o && loop (i+o1) (o+o1)
-    goPtrPtr (Ptr addr1) start1 (Ptr addr2) start2 = pureST (loop start1 start2)
-      where
-        !end = start1 `offsetPlusE` la
-        loop !i !o | i == end  = True
-                   | otherwise = primAddrIndex addr1 i == primAddrIndex addr2 o && loop (i+o1) (o+o1)
-    goBaPtr ba1 start1 (Ptr addr2) start2 = pureST (loop start1 start2)
-      where
-        !end = start1 `offsetPlusE` la
-        loop !i !o | i == end  = True
-                   | otherwise = primBaIndex ba1 i == primAddrIndex addr2 o && loop (i+o1) (o+o1)
-    goPtrBa (Ptr addr1) start1 ba2 start2 = pureST (loop start1 start2)
-      where
-        !end = start1 `offsetPlusE` la
-        loop !i !o | i == end  = True
-                   | otherwise = primAddrIndex addr1 i == primBaIndex ba2 o && loop (i+o1) (o+o1)
-
-    o1 = Offset (I# 1#)
-{-# RULES "UArray/Eq/Word8" [3] equal = equalBytes #-}
-{-# INLINEABLE [2] equal #-}
-
-equalBytes :: UArray Word8 -> UArray Word8 -> Bool
-equalBytes a b
-    | la /= lb  = False
-    | otherwise = memcmp a b (csizeOfSize $ sizeInBytes la) == 0
-  where
-    !la = length a
-    !lb = length b
-
-equalMemcmp :: PrimType ty => UArray ty -> UArray ty -> Bool
-equalMemcmp a b
-    | la /= lb  = False
-    | otherwise = memcmp a b (csizeOfSize $ sizeInBytes la) == 0
-  where
-    !la = length a
-    !lb = length b
-
--- | Compare 2 vectors
-vCompare :: (Ord ty, PrimType ty) => UArray ty -> UArray ty -> Ordering
-vCompare a b = unsafeDewrap2 goBaBa goPtrPtr goBaPtr goPtrBa a b
-  where
-    !la = length a
-    !lb = length b
-    o1 = Offset (I# 1#)
-    goBaBa ba1 start1 ba2 start2 = loop start1 start2
-      where
-        !end = start1 `offsetPlusE` min la lb
-        loop !i !o | i == end   = la `compare` lb
-                   | v1 == v2   = loop (i + o1) (o + o1)
-                   | otherwise  = v1 `compare` v2
-          where v1 = primBaIndex ba1 i
-                v2 = primBaIndex ba2 o
-    goPtrPtr (Ptr addr1) start1 (Ptr addr2) start2 = pureST (loop start1 start2)
-      where
-        !end = start1 `offsetPlusE` min la lb
-        loop !i !o | i == end   = la `compare` lb
-                   | v1 == v2   = loop (i + o1) (o + o1)
-                   | otherwise  = v1 `compare` v2
-          where v1 = primAddrIndex addr1 i
-                v2 = primAddrIndex addr2 o
-    goBaPtr ba1 start1 (Ptr addr2) start2 = pureST (loop start1 start2)
-      where
-        !end  = start1 `offsetPlusE` min la lb
-        loop !i !o | i == end   = la `compare` lb
-                   | v1 == v2   = loop (i + o1) (o + o1)
-                   | otherwise  = v1 `compare` v2
-          where v1 = primBaIndex ba1 i
-                v2 = primAddrIndex addr2 o
-    goPtrBa (Ptr addr1) start1 ba2 start2 = pureST (loop start1 start2)
-      where
-        !end  = start1 `offsetPlusE` min la lb
-        loop !i !o | i == end   = la `compare` lb
-                   | v1 == v2   = loop (i + o1) (o + o1)
-                   | otherwise  = v1 `compare` v2
-          where v1 = primAddrIndex addr1 i
-                v2 = primBaIndex ba2 o
--- {-# SPECIALIZE [3] vCompare :: UArray Word8 -> UArray Word8 -> Ordering = vCompareBytes #-}
-{-# RULES "UArray/Ord/Word8" [3] vCompare = vCompareBytes #-}
-{-# INLINEABLE [2] vCompare #-}
-
-vCompareBytes :: UArray Word8 -> UArray Word8 -> Ordering
-vCompareBytes = vCompareMemcmp
-
-vCompareMemcmp :: (Ord ty, PrimType ty) => UArray ty -> UArray ty -> Ordering
-vCompareMemcmp a b = cintToOrdering $ memcmp a b sz
-  where
-    la = length a
-    lb = length b
-    sz = csizeOfSize $ sizeInBytes $ min la lb
-    cintToOrdering :: CInt -> Ordering
-    cintToOrdering 0 = la `compare` lb
-    cintToOrdering r | r < 0     = LT
-                     | otherwise = GT
-{-# SPECIALIZE [3] vCompareMemcmp :: UArray Word8 -> UArray Word8 -> Ordering #-}
-
-memcmp :: PrimType ty => UArray ty -> UArray ty -> CSize -> CInt
-memcmp a b sz = unsafeDewrap2
-    (\s1 o1 s2 o2 -> unsafeDupablePerformIO $ sysHsMemcmpBaBa s1 (offsetToCSize o1) s2 (offsetToCSize o2) sz)
-    (\s1 o1 s2 o2 -> unsafePrimToST $ sysHsMemcmpPtrPtr s1 (offsetToCSize o1) s2 (offsetToCSize o2) sz)
-    (\s1 o1 s2 o2 -> unsafePrimToST $ sysHsMemcmpBaPtr s1 (offsetToCSize o1) s2 (offsetToCSize o2) sz)
-    (\s1 o1 s2 o2 -> unsafePrimToST $ sysHsMemcmpPtrBa s1 (offsetToCSize o1) s2 (offsetToCSize o2) sz)
-    a b
-  where
-    offsetToCSize ofs = csizeOfOffset $ offsetInBytes ofs
-{-# SPECIALIZE [3] memcmp :: UArray Word8 -> UArray Word8 -> CSize -> CInt #-}
-
--- | Append 2 arrays together by creating a new bigger array
-append :: PrimType ty => UArray ty -> UArray ty -> UArray ty
-append a b
-    | la == azero = b
-    | lb == azero = a
-    | otherwise = runST $ do
-        r  <- new (la+lb)
-        ma <- unsafeThaw a
-        mb <- unsafeThaw b
-        copyAt r (Offset 0) ma (Offset 0) la
-        copyAt r (sizeAsOffset la) mb (Offset 0) lb
-        unsafeFreeze r
-  where
-    !la = length a
-    !lb = length b
-
-concat :: PrimType ty => [UArray ty] -> UArray ty
-concat [] = empty
-concat l  =
-    case filterAndSum (CountOf 0) [] l of
-        (_,[])            -> empty
-        (_,[x])           -> x
-        (totalLen,chunks) -> runST $ do
-            r <- new totalLen
-            doCopy r (Offset 0) chunks
-            unsafeFreeze r
-  where
-    -- TODO would go faster not to reverse but pack from the end instead
-    filterAndSum !totalLen acc []     = (totalLen, Prelude.reverse acc)
-    filterAndSum !totalLen acc (x:xs)
-        | len == CountOf 0 = filterAndSum totalLen acc xs
-        | otherwise      = filterAndSum (len+totalLen) (x:acc) xs
-      where len = length x
-
-    doCopy _ _ []     = return ()
-    doCopy r i (x:xs) = do
-        unsafeCopyAtRO r i x (Offset 0) lx
-        doCopy r (i `offsetPlusE` lx) xs
-      where lx = length x
-
 -- | update an array by creating a new array with the updates.
 --
 -- the operation copy the previous array, modify it in place, then freeze it.
@@ -630,43 +288,33 @@
           => UArray ty -- ^ the source array to copy
           -> Ptr ty    -- ^ The destination address where the copy is going to start
           -> prim ()
-copyToPtr (UVecBA start sz _ ba) (Ptr p) = primitive $ \s1 ->
-    (# compatCopyByteArrayToAddr# ba offset p szBytes s1, () #)
-  where
-    !(Offset (I# offset)) = offsetInBytes start
-    !(CountOf (I# szBytes)) = sizeInBytes sz
-copyToPtr (UVecAddr start sz fptr) dst =
-    unsafePrimFromIO $ withFinalPtr fptr $ \ptr -> copyBytes dst (ptr `plusPtr` os) szBytes
+copyToPtr arr dst@(Ptr dst#) = onBackendPrim copyBa copyPtr arr
   where
-    !(Offset os)    = offsetInBytes start
-    !(CountOf szBytes) = sizeInBytes sz
-
-data TmpBA = TmpBA ByteArray#
+    !(Offset os@(I# os#)) = offsetInBytes $ offset arr
+    !(CountOf szBytes@(I# szBytes#)) = sizeInBytes $ length arr
+    copyBa ba = primitive $ \s1 -> (# compatCopyByteArrayToAddr# ba os# dst# szBytes# s1, () #)
+    copyPtr fptr = unsafePrimFromIO $ withFinalPtr fptr $ \ptr -> copyBytes dst (ptr `plusPtr` os) szBytes
 
-withPtr :: (PrimMonad prim, PrimType ty)
+withPtr :: forall ty prim a . (PrimMonad prim, PrimType ty)
         => UArray ty
         -> (Ptr ty -> prim a)
         -> prim a
-withPtr vec@(UVecAddr start _ fptr)  f =
-    withFinalPtr fptr (\ptr -> f (ptr `plusPtr` os))
-  where
-    sz           = primSizeInBytes (vectorProxyTy vec)
-    !(Offset os) = offsetOfE sz start
-withPtr vec@(UVecBA start _ pstatus a) f
-    | isPinned pstatus = f (Ptr (byteArrayContents# a) `plusPtr` os)
-    | otherwise        = do
-        -- TODO don't copy the whole vector, and just allocate+copy the slice.
-        let !sz# = sizeofByteArray# a
-        (TmpBA ba) <- primitive $ \s -> do
-            case newAlignedPinnedByteArray# sz# 8# s of { (# s2, mba #) ->
-            case copyByteArray# a 0# mba 0# sz# s2 of { s3 ->
-            case unsafeFreezeByteArray# mba s3 of { (# s4, ba #) -> (# s4, TmpBA ba #) }}}
-        r <- f (Ptr (byteArrayContents# ba))
-        unsafePrimFromIO $ primitive $ \s -> case touch# ba s of { s2 -> (# s2, () #) }
+withPtr a f
+    | isPinned a == Pinned =
+        onBackendPrim (\ba -> f (Ptr (byteArrayContents# ba) `plusPtr` os))
+                      (\fptr -> withFinalPtr fptr $ \ptr -> f (ptr `plusPtr` os))
+                      a
+    | otherwise = do
+        arr <- do
+            trampoline <- newPinned (length a)
+            unsafeCopyAtRO trampoline 0 a 0 (length a)
+            unsafeFreeze trampoline
+        r <- withPtr arr f
+        touch arr
         pure r
   where
-    sz           = primSizeInBytes (vectorProxyTy vec)
-    !(Offset os) = offsetOfE sz start
+    !sz          = primSizeInBytes (Proxy :: Proxy ty)
+    !(Offset os) = offsetOfE sz $ offset a
 {-# INLINE withPtr #-}
 
 -- | Recast an array of type a to an array of b
@@ -687,98 +335,103 @@
     missing = alen `mod` bs
 
 unsafeRecast :: (PrimType a, PrimType b) => UArray a -> UArray b
-unsafeRecast (UVecBA start len pinStatus b) = UVecBA (primOffsetRecast start) (sizeRecast len) pinStatus b
-unsafeRecast (UVecAddr start len a) = UVecAddr (primOffsetRecast start) (sizeRecast len) (castFinalPtr a)
+unsafeRecast (UArray start len backend) = UArray (primOffsetRecast start) (sizeRecast len) $
+    case backend of
+        UArrayAddr fptr     -> UArrayAddr (castFinalPtr fptr)
+        UArrayBA (Block ba) -> UArrayBA (Block ba)
 {-# INLINE [1] unsafeRecast #-}
-{-# RULES "unsafeRecast from Word8" [2] forall a . unsafeRecast a = unsafeRecastBytes a #-}
-
-unsafeRecastBytes :: PrimType a => UArray Word8 -> UArray a
-unsafeRecastBytes (UVecBA start len pinStatus b) = UVecBA (primOffsetRecast start) (sizeRecast len) pinStatus b
-unsafeRecastBytes (UVecAddr start len a) = UVecAddr (primOffsetRecast start) (sizeRecast len) (castFinalPtr a)
-{-# INLINE [1] unsafeRecastBytes #-}
+{-# SPECIALIZE [3] unsafeRecast :: PrimType a => UArray Word8 -> UArray a #-}
 
 null :: UArray ty -> Bool
-null (UVecBA _ sz _ _) = sz == CountOf 0
-null (UVecAddr _ l _)  = l == CountOf 0
+null arr = length arr == 0
 
 -- | Take a count of elements from the array and create an array with just those elements
-take :: PrimType ty => CountOf ty -> UArray ty -> UArray ty
-take n v
+take :: CountOf ty -> UArray ty -> UArray ty
+take n arr@(UArray start len backend)
     | n <= 0    = empty
-    | n >= vlen = v
-    | otherwise =
-        case v of
-            UVecBA start _ pinst ba -> UVecBA start n pinst ba
-            UVecAddr start _ fptr   -> UVecAddr start n fptr
-  where
-    vlen = length v
+    | n >= len  = arr
+    | otherwise = UArray start n backend
 
-unsafeTake :: PrimType ty => CountOf ty -> UArray ty -> UArray ty
-unsafeTake sz (UVecBA start _ pinst ba) = UVecBA start sz pinst ba
-unsafeTake sz (UVecAddr start _ fptr)   = UVecAddr start sz fptr
+unsafeTake :: CountOf ty -> UArray ty -> UArray ty
+unsafeTake sz (UArray start _ ba) = UArray start sz ba
 
 -- | Drop a count of elements from the array and return the new array minus those dropped elements
-drop :: PrimType ty => CountOf ty -> UArray ty -> UArray ty
-drop n v
-    | n <= 0    = v
-    | n >= vlen = empty
-    | otherwise =
-        case v of
-            UVecBA start len pinst ba -> UVecBA (start `offsetPlusE` n) (len - n) pinst ba
-            UVecAddr start len fptr   -> UVecAddr (start `offsetPlusE` n) (len - n) fptr
-  where
-    vlen = length v
+drop :: CountOf ty -> UArray ty -> UArray ty
+drop n arr@(UArray start len backend)
+    | n <= 0    = arr
+    | n >= len  = empty
+    | otherwise = UArray (start `offsetPlusE` n) (len - n) backend
 
-unsafeDrop :: PrimType ty => CountOf ty -> UArray ty -> UArray ty
-unsafeDrop n (UVecBA start sz pinst ba) = UVecBA (start `offsetPlusE` sz) (sz `sizeSub` n) pinst ba
-unsafeDrop n (UVecAddr start sz fptr)   = UVecAddr (start `offsetPlusE` sz) (sz `sizeSub` n) fptr
+unsafeDrop :: CountOf ty -> UArray ty -> UArray ty
+unsafeDrop n (UArray start sz backend) = UArray (start `offsetPlusE` n) (sz `sizeSub` n) backend
 
 -- | Split an array into two, with a count of at most N elements in the first one
 -- and the remaining in the other.
-splitAt :: PrimType ty => CountOf ty -> UArray ty -> (UArray ty, UArray ty)
-splitAt nbElems v
-    | nbElems <= 0 = (empty, v)
-    | n == vlen    = (v, empty)
-    | otherwise    =
-        case v of
-            UVecBA start len pinst ba -> ( UVecBA start                   n         pinst ba
-                                         , UVecBA (start `offsetPlusE` n) (len - n) pinst ba)
-            UVecAddr start len fptr    -> ( UVecAddr start                   n         fptr
-                                          , UVecAddr (start `offsetPlusE` n) (len - n) fptr)
+splitAt :: CountOf ty -> UArray ty -> (UArray ty, UArray ty)
+splitAt nbElems arr@(UArray start len backend)
+    | nbElems <= 0 = (empty, arr)
+    | n == len     = (arr, empty)
+    | otherwise    = (UArray start n backend, UArray (start `offsetPlusE` n) (len - n) backend)
   where
-    n    = min nbElems vlen
-    vlen = length v
+    n    = min nbElems len
 
-splitElem :: PrimType ty => ty -> UArray ty -> (# UArray ty, UArray ty #)
-splitElem !ty r@(UVecBA start len pinst ba)
-    | k == end   = (# r, empty #)
-    | k == start = (# empty, r #)
-    | otherwise  =
-        (# UVecBA start (offsetAsSize k - offsetAsSize start) pinst ba
-        ,  UVecBA k     (len - (offsetAsSize k - offsetAsSize start)) pinst ba
-        #)
+breakElem :: PrimType ty => ty -> UArray ty -> (UArray ty, UArray ty)
+breakElem !ty arr@(UArray start len backend)
+    | k == end   = (arr, empty)
+    | k == start = (empty, arr)
+    | otherwise  = ( UArray start (offsetAsSize k - offsetAsSize start) backend
+                   , UArray k     (len - (offsetAsSize k - offsetAsSize start)) backend)
   where
     !end = start `offsetPlusE` len
-    !k = loop start
-    loop !i | i < end && t /= ty = loop (i+Offset 1)
-            | otherwise          = i
-        where t                  = primBaIndex ba i
-splitElem !ty r@(UVecAddr start len fptr)
-    | k == end  = (# r, empty #)
-    | otherwise =
-        (# UVecAddr start (offsetAsSize k - offsetAsSize start) fptr
-        ,  UVecAddr k     (len - (offsetAsSize k - offsetAsSize start)) fptr
-        #)
+    !k = onBackend goBa (\fptr -> pure . goAddr fptr) arr
+    goBa ba = PrimBA.findIndexElem ty ba start end
+    goAddr _ (Ptr addr) = PrimAddr.findIndexElem ty addr start end
+{-# NOINLINE [3] breakElem #-}
+{-# RULES "breakElem Word8" [3] breakElem = breakElemByte #-}
+{-# SPECIALIZE [3] breakElem :: Word32 -> UArray Word32 -> (UArray Word32, UArray Word32) #-}
+
+breakElemByte :: Word8 -> UArray Word8 -> (UArray Word8, UArray Word8)
+breakElemByte !ty arr@(UArray start len backend)
+    | k == end   = (arr, empty)
+    | k == start = (empty, arr)
+    | otherwise  = ( UArray start (offsetAsSize k - offsetAsSize start) backend
+                   , UArray k     (len - (offsetAsSize k - offsetAsSize start)) backend)
   where
-    !(Ptr addr) = withFinalPtrNoTouch fptr id
     !end = start `offsetPlusE` len
-    !k = loop start
-    loop !i | i < end && t /= ty = loop (i+Offset 1)
-            | otherwise          = i
-        where t                  = primAddrIndex addr i
-{-# SPECIALIZE [3] splitElem :: Word8 -> UArray Word8 -> (# UArray Word8, UArray Word8 #) #-}
-{-# SPECIALIZE [3] splitElem :: Word32 -> UArray Word32 -> (# UArray Word32, UArray Word32 #) #-}
+    !k = onBackend goBa (\fptr -> pure . goAddr fptr) arr
+    goBa ba = sysHsMemFindByteBa ba start end ty
+    goAddr _ (Ptr addr) = sysHsMemFindByteAddr addr start end ty
 
+-- | Similar to breakElem specialized to split on linefeed
+--
+-- it either returns:
+-- * Left. no line has been found, and whether the last character is a CR
+-- * Right, a line has been found with an optional CR, and it returns
+--   the array of bytes on the left of the CR/LF, and the
+--   the array of bytes on the right of the LF.
+--
+breakLine :: UArray Word8 -> Either Bool (UArray Word8, UArray Word8)
+breakLine arr@(UArray start len backend)
+    | end == start = Left False
+    | k2 == end    = Left (k1 /= k2)
+    | k2 == start  = Right (empty, if k2 + 1 == end then empty else unsafeDrop 1 arr)
+    | otherwise    = Right ( unsafeTake (offsetAsSize k1 - offsetAsSize start) arr
+                           , if k2+1 == end then empty else UArray (k2+1) (len - (offsetAsSize (k2+1) - offsetAsSize start)) backend)
+  where
+    !end = start `offsetPlusE` len
+    -- return (offset of CR, offset of LF, whether the last element was a carriage return
+    !(k1, k2) = onBackend goBa (\fptr -> pure . goAddr fptr) arr
+    lineFeed = 0xa
+    carriageReturn = 0xd
+    goBa ba =
+        let k = sysHsMemFindByteBa ba start end lineFeed
+            cr = if k > start then PrimBA.primIndex ba (k `offsetSub` 1) == carriageReturn else False
+         in (if cr then k `offsetSub` 1 else k, k)
+    goAddr _ (Ptr addr) =
+        let k = sysHsMemFindByteAddr addr start end lineFeed
+            cr = if k > start then PrimAddr.primIndex addr (k `offsetSub` 1) == carriageReturn else False
+         in (if cr then k `offsetSub` 1 else k, k)
+
 -- inverse a CountOf that is specified from the end (e.g. take n elements from the end)
 countFromStart :: UArray ty -> CountOf ty -> CountOf ty
 countFromStart v sz@(CountOf sz')
@@ -787,17 +440,17 @@
   where len@(CountOf len') = length v
 
 -- | Take the N elements from the end of the array
-revTake :: PrimType ty => CountOf ty -> UArray ty -> UArray ty
+revTake :: CountOf ty -> UArray ty -> UArray ty
 revTake n v = drop (countFromStart v n) v
 
 -- | Drop the N elements from the end of the array
-revDrop :: PrimType ty => CountOf ty -> UArray ty -> UArray ty
+revDrop :: CountOf ty -> UArray ty -> UArray ty
 revDrop n v = take (countFromStart v n) v
 
 -- | Split an array at the N element from the end, and return
 -- the last N elements in the first part of the tuple, and whatever first
 -- elements remaining in the second
-revSplitAt :: PrimType ty => CountOf ty -> UArray ty -> (UArray ty, UArray ty)
+revSplitAt :: CountOf ty -> UArray ty -> (UArray ty, UArray ty)
 revSplitAt n v = (drop sz v, take sz v) where sz = countFromStart v n
 
 splitOn :: PrimType ty => (ty -> Bool) -> UArray ty -> [UArray ty]
@@ -818,20 +471,13 @@
                         else loop prevIdx idx'
     {-# INLINE go #-}
 
-pureST :: a -> ST s a
-pureST = pure
-
 sub :: PrimType ty => UArray ty -> Offset ty -> Offset ty -> UArray ty
-sub vec startIdx expectedEndIdx
-    | startIdx >= endIdx = empty
-    | otherwise          =
-        case vec of
-            UVecBA start _ pinst ba -> UVecBA (start + startIdx) newLen pinst ba
-            UVecAddr start _ fptr   -> UVecAddr (start + startIdx) newLen fptr
+sub (UArray start len backend) startIdx expectedEndIdx
+    | startIdx >= endIdx = mempty
+    | otherwise          = UArray (start + startIdx) newLen backend
   where
     newLen = endIdx - startIdx
     endIdx = min expectedEndIdx (0 `offsetPlusE` len)
-    len = length vec
 
 findIndex :: forall ty . PrimType ty => ty -> UArray ty -> Maybe (Offset ty)
 findIndex tyOuter ba = runST $ unsafeIndexer ba (go tyOuter)
@@ -842,22 +488,22 @@
     go ty getIdx = loop (Offset 0)
       where
         loop ofs
-            | ofs .==# len     = return Nothing
-            | getIdx ofs == ty = return $ Just ofs
+            | ofs .==# len     = pure Nothing
+            | getIdx ofs == ty = pure $ Just ofs
             | otherwise        = loop (ofs + Offset 1)
 {-# SPECIALIZE [3] findIndex :: Word8 -> UArray Word8 -> Maybe (Offset Word8) #-}
 
 break :: forall ty . PrimType ty => (ty -> Bool) -> UArray ty -> (UArray ty, UArray ty)
 break xpredicate xv
-    | len == 0  = (empty, empty)
+    | len == 0  = (mempty, mempty)
     | otherwise = runST $ unsafeIndexer xv (go xv xpredicate)
   where
     !len = length xv
     go :: PrimType ty => UArray ty -> (ty -> Bool) -> (Offset ty -> ty) -> ST s (UArray ty, UArray ty)
-    go v predicate getIdx = return (findBreak $ Offset 0)
+    go v predicate getIdx = pure (findBreak $ Offset 0)
       where
         findBreak !i
-            | i .==# len           = (v, empty)
+            | i .==# len           = (v, mempty)
             | predicate (getIdx i) = splitAt (offsetAsSize i) v
             | otherwise            = findBreak (i + Offset 1)
         {-# INLINE findBreak #-}
@@ -871,31 +517,13 @@
 {-# RULES "break (== ty)" [3] forall (x :: Word8) . break (== x) = breakElem x #-}
 -}
 
-breakElem :: PrimType ty => ty -> UArray ty -> (UArray ty, UArray ty)
-breakElem xelem xv = let (# v1, v2 #) = splitElem xelem xv in (v1, v2)
-{-# SPECIALIZE [2] breakElem :: Word8 -> UArray Word8 -> (UArray Word8, UArray Word8) #-}
-{-# SPECIALIZE [2] breakElem :: Word32 -> UArray Word32 -> (UArray Word32, UArray Word32) #-}
-
 elem :: PrimType ty => ty -> UArray ty -> Bool
-elem !ty (UVecBA start len _ ba)
-    | k == end   = False
-    | otherwise  = True
-  where
-    !end = start `offsetPlusE` len
-    !k = loop start
-    loop !i | i < end && t /= ty = loop (i+Offset 1)
-            | otherwise          = i
-        where t                  = primBaIndex ba i
-elem ty (UVecAddr start len fptr)
-    | k == end  = False
-    | otherwise = True
+elem !ty arr = onBackend goBa (\_ -> pure . goAddr) arr /= end
   where
-    !(Ptr addr) = withFinalPtrNoTouch fptr id
-    !end = start `offsetPlusE` len
-    !k = loop start
-    loop !i | i < end && t /= ty = loop (i+Offset 1)
-            | otherwise          = i
-        where t                  = primAddrIndex addr i
+    !start = offset arr
+    !end = start `offsetPlusE` length arr
+    goBa ba = PrimBA.findIndexElem ty ba start end
+    goAddr (Ptr addr) = PrimAddr.findIndexElem ty addr start end
 {-# SPECIALIZE [2] elem :: Word8 -> UArray Word8 -> Bool #-}
 
 intersperse :: forall ty . PrimType ty => ty -> UArray ty -> UArray ty
@@ -975,7 +603,7 @@
 
 sortBy :: forall ty . PrimType ty => (ty -> ty -> Ordering) -> UArray ty -> UArray ty
 sortBy xford vec
-    | len == 0  = empty
+    | len == 0  = mempty
     | otherwise = runST (thaw vec >>= doSort xford)
   where
     len = length vec
@@ -983,7 +611,7 @@
     doSort ford ma = qsort 0 (sizeLastOffset len) >> unsafeFreeze ma
       where
         qsort lo hi
-            | lo >= hi  = return ()
+            | lo >= hi  = pure ()
             | otherwise = do
                 p <- partition lo hi
                 qsort lo (pred p)
@@ -991,16 +619,16 @@
         partition lo hi = do
             pivot <- unsafeRead ma hi
             let loop i j
-                    | j == hi   = return i
+                    | j == hi   = pure i
                     | otherwise = do
                         aj <- unsafeRead ma j
                         i' <- if ford aj pivot == GT
-                                then return i
+                                then pure i
                                 else do
                                     ai <- unsafeRead ma i
                                     unsafeWrite ma j ai
                                     unsafeWrite ma i aj
-                                    return $ i + 1
+                                    pure $ i + 1
                         loop i' (j+1)
 
             i <- loop lo lo
@@ -1008,66 +636,47 @@
             ahi <- unsafeRead ma hi
             unsafeWrite ma hi ai
             unsafeWrite ma i ahi
-            return i
+            pure i
 
 filter :: forall ty . PrimType ty => (ty -> Bool) -> UArray ty -> UArray ty
 filter predicate arr = runST $ do
     (newLen, ma) <- newNative (length arr) $ \mba ->
-                case arr of
-                    (UVecAddr start _ fptr) -> withFinalPtr fptr (goAddr mba start)
-                    (UVecBA start _ _ ba)   -> goBA mba ba start
+            onBackendPrim (\ba -> PrimBA.filter predicate mba ba start end)
+                          (\fptr -> withFinalPtr fptr $ \(Ptr addr) ->
+                                        PrimAddr.filter predicate mba addr start end)
+                          arr
     unsafeFreezeShrink ma newLen
   where
-    !len = length arr
-    o1 = Offset 1
-
-    goBA :: PrimType ty => MutableByteArray# s -> ByteArray# -> Offset ty -> ST s (CountOf ty)
-    goBA dst src start = loop azero start
-      where
-        end = start `offsetPlusE` len
-        loop !d !s
-            | s == end    = pure (offsetAsSize d)
-            | predicate v = primMbaWrite dst d v >> loop (d+o1) (s+o1)
-            | otherwise   = loop d (s+o1)
-          where
-            v = primBaIndex src s
-    goAddr :: PrimType ty => MutableByteArray# s -> Offset ty -> (Ptr addr) -> ST s (CountOf ty)
-    goAddr dst start (Ptr addr) = loop azero start
-      where
-        end = start `offsetPlusE` len
-        loop !d !s
-            | s == end    = pure (offsetAsSize d)
-            | predicate v = primMbaWrite dst d v >> loop (d+o1) (s+o1)
-            | otherwise   = loop d (s+o1)
-          where
-            v = primAddrIndex addr s
+    !len   = length arr
+    !start = offset arr
+    !end   = start `offsetPlusE` len
 
 reverse :: PrimType ty => UArray ty -> UArray ty
 reverse a
-    | len == CountOf 0 = empty
-    | otherwise     = runST $ do
-        ((), ma) <- newNative len $ \mba ->
-                case a of
-                    (UVecBA start _ _ ba)   -> goNative endOfs mba ba start
-                    (UVecAddr start _ fptr) -> withFinalPtr fptr $ \ptr -> goAddr endOfs mba ptr start
+    | len == 0  = mempty
+    | otherwise = runST $ do
+        ((), ma) <- newNative len $ \mba -> onBackendPrim (goNative mba)
+                                                          (\fptr -> withFinalPtr fptr $ goAddr mba)
+                                                          a
         unsafeFreeze ma
   where
     !len = length a
-    !endOfs = Offset 0 `offsetPlusE` len
+    !end = 0 `offsetPlusE` len
+    !start = offset a
+    !endI = sizeAsOffset ((start + end) - Offset 1)
 
-    goNative :: PrimType ty => Offset ty -> MutableByteArray# s -> ByteArray# -> Offset ty -> ST s ()
-    goNative !end !ma !ba !srcStart = loop (Offset 0)
+    goNative :: MutableByteArray# s -> ByteArray# -> ST s ()
+    goNative !ma !ba = loop 0
       where
-        !endI = sizeAsOffset ((srcStart + end) - Offset 1)
         loop !i
-            | i == end  = return ()
-            | otherwise = primMbaWrite ma i (primBaIndex ba (sizeAsOffset (endI - i))) >> loop (i+Offset 1)
-    goAddr !end !ma (Ptr ba) !srcStart = loop (Offset 0)
+            | i == end  = pure ()
+            | otherwise = primMbaWrite ma i (primBaIndex ba (sizeAsOffset (endI - i))) >> loop (i+1)
+    goAddr :: MutableByteArray# s -> Ptr ty -> ST s ()
+    goAddr !ma (Ptr addr) = loop 0
       where
-        !endI = sizeAsOffset ((srcStart + end) - Offset 1)
         loop !i
-            | i == end  = return ()
-            | otherwise = primMbaWrite ma i (primAddrIndex ba (sizeAsOffset (endI - i))) >> loop (i+Offset 1)
+            | i == end  = pure ()
+            | otherwise = primMbaWrite ma i (primAddrIndex addr (sizeAsOffset (endI - i))) >> loop (i+1)
 {-# SPECIALIZE [3] reverse :: UArray Word8 -> UArray Word8 #-}
 
 -- Finds where are the insertion points when we search for a `needle`
@@ -1091,7 +700,7 @@
         in case matcher == needle of
              -- TODO: Move away from right-appending as it's gonna be slow.
              True  -> go (currentOffset `offsetPlusE` needleLen) (ipoints <> [currentOffset])
-             False -> go (currentOffset + Offset 1) ipoints
+             False -> go (currentOffset + 1) ipoints
 
 -- | Replace all the occurrencies of `needle` with `replacement` in
 -- the `haystack` string.
@@ -1101,7 +710,7 @@
       True -> error "Foundation.Array.Unboxed.replace: empty needle"
       False -> do
         let insertionPoints = indices needle haystack
-        let !occs           = Prelude.length insertionPoints
+        let !occs           = List.length insertionPoints
         let !newLen         = haystackLen - (multBy needleLen occs) + (multBy replacementLen occs)
         ms <- new newLen
         loop ms (Offset 0) (Offset 0) insertionPoints
@@ -1149,38 +758,46 @@
         | otherwise  = unsafeIndex vec i `f` loop (i+1)
 
 foldl' :: PrimType ty => (a -> ty -> a) -> a -> UArray ty -> a
-foldl' f initialAcc vec = loop 0 initialAcc
+foldl' f initialAcc arr = onBackend goNative (\_ -> pure . goAddr) arr
   where
-    !len = length vec
-    loop i !acc
-        | i .==# len = acc
-        | otherwise  = loop (i+1) (f acc (unsafeIndex vec i))
+    !len = length arr
+    !start = offset arr
+    !end = start `offsetPlusE` len
+    goNative ba = PrimBA.foldl f initialAcc ba start end
+    goAddr (Ptr ptr) = PrimAddr.foldl f initialAcc ptr start end
+{-# SPECIALIZE [3] foldl' :: (a -> Word8 -> a) -> a -> UArray Word8 -> a #-}
 
 foldl1' :: PrimType ty => (ty -> ty -> ty) -> NonEmpty (UArray ty) -> ty
-foldl1' f arr = let (initialAcc, rest) = splitAt 1 $ getNonEmpty arr
-               in foldl' f (unsafeIndex initialAcc 0) rest
+foldl1' f (NonEmpty arr) = onBackend goNative (\_ -> pure . goAddr) arr
+  where
+    !len = length arr
+    !start = offset arr
+    !end = start `offsetPlusE` len
+    goNative ba = PrimBA.foldl1 f ba start end
+    goAddr (Ptr ptr) = PrimAddr.foldl1 f ptr start end
+{-# SPECIALIZE [3] foldl1' :: (Word8 -> Word8 -> Word8) -> NonEmpty (UArray Word8) -> Word8 #-}
 
 foldr1 :: PrimType ty => (ty -> ty -> ty) -> NonEmpty (UArray ty) -> ty
 foldr1 f arr = let (initialAcc, rest) = revSplitAt 1 $ getNonEmpty arr
                in foldr f (unsafeIndex initialAcc 0) rest
 
 all :: PrimType ty => (ty -> Bool) -> UArray ty -> Bool
-all p uv = loop 0
+all predicate arr = onBackend (\ba -> PrimBA.all predicate ba start end)
+                              (\_ (Ptr ptr) -> pure (PrimAddr.all predicate ptr start end))
+                              arr
   where
-    len = length uv
-    loop !i
-      | i .==# len = True
-      | not $ p (unsafeIndex uv i) = False
-      | otherwise = loop (i + 1)
+    start = offset arr
+    end = start `offsetPlusE` length arr
+{-# SPECIALIZE [3] all :: (Word8 -> Bool) -> UArray Word8 -> Bool #-}
 
 any :: PrimType ty => (ty -> Bool) -> UArray ty -> Bool
-any p uv = loop 0
+any predicate arr = onBackend (\ba -> PrimBA.any predicate ba start end)
+                              (\_ (Ptr ptr) -> pure (PrimAddr.any predicate ptr start end))
+                              arr
   where
-    len = length uv
-    loop !i
-      | i .==# len = False
-      | p (unsafeIndex uv i) = True
-      | otherwise = loop (i + 1)
+    start = offset arr
+    end = start `offsetPlusE` length arr
+{-# SPECIALIZE [3] any :: (Word8 -> Bool) -> UArray Word8 -> Bool #-}
 
 builderAppend :: (PrimType ty, PrimMonad state) => ty -> Builder (UArray ty) (MUArray ty) ty state err ()
 builderAppend v = Builder $ State $ \(i, st, e) ->
@@ -1189,13 +806,13 @@
             cur      <- unsafeFreeze (curChunk st)
             newChunk <- new (chunkSize st)
             unsafeWrite newChunk 0 v
-            return ((), (Offset 1, st { prevChunks     = cur : prevChunks st
-                                      , prevChunksSize = chunkSize st + prevChunksSize st
-                                      , curChunk       = newChunk
-                                      }, e))
+            pure ((), (Offset 1, st { prevChunks     = cur : prevChunks st
+                                    , prevChunksSize = chunkSize st + prevChunksSize st
+                                    , curChunk       = newChunk
+                                    }, e))
         else do
             unsafeWrite (curChunk st) i v
-            return ((), (i + 1, st, e))
+            pure ((), (i + 1, st, e))
 
 builderBuild :: (PrimType ty, PrimMonad m) => Int -> Builder (UArray ty) (MUArray ty) ty m err () -> m (Either err (UArray ty))
 builderBuild sizeChunksI ab
@@ -1204,17 +821,17 @@
         first         <- new sizeChunks
         ((), (i, st, e)) <- runState (runBuilder ab) (Offset 0, BuildingState [] (CountOf 0) first sizeChunks, Nothing)
         case e of
-          Just err -> return (Left err)
+          Just err -> pure (Left err)
           Nothing -> do
             cur <- unsafeFreezeShrink (curChunk st) (offsetAsSize i)
             -- Build final array
             let totalSize = prevChunksSize st + offsetAsSize i
             bytes <- new totalSize >>= fillFromEnd totalSize (cur : prevChunks st) >>= unsafeFreeze
-            return (Right bytes)
+            pure (Right bytes)
   where
       sizeChunks = CountOf sizeChunksI
 
-      fillFromEnd _   []     mua = return mua
+      fillFromEnd _   []     mua = pure mua
       fillFromEnd !end (x:xs) mua = do
           let sz = length x
           unsafeCopyAtRO mua (sizeAsOffset (end - sz)) x (Offset 0) sz
@@ -1225,7 +842,7 @@
 
 toHexadecimal :: PrimType ty => UArray ty -> UArray Word8
 toHexadecimal ba
-    | len == CountOf 0 = empty
+    | len == CountOf 0 = mempty
     | otherwise     = runST $ do
         ma <- new (len `scale` 2)
         unsafeIndexer b8 (go ma)
@@ -1239,7 +856,7 @@
     go !ma !getAt = loop 0 0
       where
         loop !dIdx !sIdx
-            | sIdx == endOfs = return ()
+            | sIdx == endOfs = pure ()
             | otherwise      = do
                 let !(W8# !w)      = getAt sIdx
                     (# wHi, wLo #) = Base16.unsafeConvertByte w
@@ -1249,7 +866,7 @@
 
 toBase64Internal :: PrimType ty => Addr# -> UArray ty -> Bool -> UArray Word8
 toBase64Internal table src padded
-    | len == CountOf 0 = empty
+    | len == CountOf 0 = mempty
     | otherwise = runST $ do
         ma <- new dstLen
         unsafeIndexer b8 (go ma)
@@ -1259,6 +876,7 @@
     !len = length b8
     !dstLen = outputLengthBase64 padded len
     !endOfs = Offset 0 `offsetPlusE` len
+    !dstEndOfs = Offset 0 `offsetPlusE` dstLen
 
     go :: MUArray Word8 s -> (Offset Word8 -> Word8) -> ST s ()
     go !ma !getAt = loop 0 0
@@ -1266,43 +884,44 @@
         eqChar = 0x3d :: Word8
 
         loop !sIdx !dIdx
-            | sIdx >= endOfs = return ()
+            | sIdx == endOfs = when padded $ do
+                when (dIdx `offsetPlusE` CountOf 1 <= dstEndOfs) $ unsafeWrite ma dIdx eqChar
+                when (dIdx `offsetPlusE` CountOf 2 == dstEndOfs) $ unsafeWrite ma (dIdx `offsetPlusE` CountOf 1) eqChar
             | otherwise = do
-                let !a = getAt sIdx
-                    !b = if sIdx `offsetPlusE` CountOf 1 >= endOfs then 0 else getAt (sIdx `offsetPlusE` CountOf 1)
-                    !c = if sIdx `offsetPlusE` CountOf 2 >= endOfs then 0 else getAt (sIdx `offsetPlusE` CountOf 2)
+                let !b2Idx = sIdx `offsetPlusE` CountOf 1
+                    !b3Idx = sIdx `offsetPlusE` CountOf 2
 
-                let (w,x,y,z) = convert3 table a b c
+                    !b2Available = b2Idx < endOfs
+                    !b3Available = b3Idx < endOfs
 
+                    !b1 = getAt sIdx
+                    !b2 = if b2Available then getAt b2Idx else 0
+                    !b3 = if b3Available then getAt b3Idx else 0
+
+                    (w,x,y,z) = convert3 table b1 b2 b3
+
+                    sNextIncr = 1 + fromEnum b2Available + fromEnum b3Available
+                    dNextIncr = 1 + sNextIncr
+
                 unsafeWrite ma dIdx w
                 unsafeWrite ma (dIdx `offsetPlusE` CountOf 1) x
 
-                if sIdx `offsetPlusE` CountOf 1 < endOfs
-                    then
-                        unsafeWrite ma (dIdx `offsetPlusE` CountOf 2) y
-                    else
-                        when padded (unsafeWrite ma (dIdx `offsetPlusE` CountOf 2) eqChar)
-                if sIdx `offsetPlusE` CountOf 2 < endOfs
-                    then
-                        unsafeWrite ma (dIdx `offsetPlusE` CountOf 3) z
-                    else
-                        when padded (unsafeWrite ma (dIdx `offsetPlusE` CountOf 3) eqChar)
+                when b2Available $ unsafeWrite ma (dIdx `offsetPlusE` CountOf 2) y
+                when b3Available $ unsafeWrite ma (dIdx `offsetPlusE` CountOf 3) z
 
-                loop (sIdx `offsetPlusE` CountOf 3) (dIdx `offsetPlusE` CountOf 4)
+                loop (sIdx `offsetPlusE` CountOf sNextIncr) (dIdx `offsetPlusE` CountOf dNextIncr)
 
 outputLengthBase64 :: Bool -> CountOf Word8 -> CountOf Word8
 outputLengthBase64 padding (CountOf inputLenInt) = outputLength
   where
-    outputLength = if padding then CountOf lenWithPadding else CountOf (lenWithPadding - numPadChars)
-
-    lenWithPadding :: Int
-    lenWithPadding = 4 * roundUp (Prelude.fromIntegral inputLenInt / 3.0 :: Double)
-
-    numPadChars :: Int
-    numPadChars = case inputLenInt `mod` 3 of
-        1 -> 2
-        2 -> 1
-        _ -> 0
+    outputLength = if padding then CountOf lenWithPadding else CountOf lenWithoutPadding
+    lenWithPadding
+        | m == 0    = 4 * d
+        | otherwise = 4 * (d + 1)
+    lenWithoutPadding
+        | m == 0    = 4 * d
+        | otherwise = 4 * d + m + 1
+    (d,m) = inputLenInt `divMod` 3
 
 convert3 :: Addr# -> Word8 -> Word8 -> Word8 -> (Word8, Word8, Word8, Word8)
 convert3 table (W8# a) (W8# b) (W8# c) =
@@ -1314,3 +933,21 @@
   where
     idx :: Word# -> Word8
     idx i = W8# (indexWord8OffAddr# table (word2Int# i))
+
+isPrefixOf :: PrimType ty => UArray ty -> UArray ty -> Bool
+isPrefixOf pre arr
+    | pLen > pArr = False
+    | otherwise   = pre == unsafeTake pLen arr
+  where
+    !pLen = length pre
+    !pArr = length arr
+{-# SPECIALIZE [3] isPrefixOf :: UArray Word8 -> UArray Word8 -> Bool #-}
+
+isSuffixOf :: PrimType ty => UArray ty -> UArray ty -> Bool
+isSuffixOf suffix arr
+    | pLen > pArr = False
+    | otherwise   = suffix == revTake pLen arr
+  where
+    !pLen = length suffix
+    !pArr = length arr
+{-# SPECIALIZE [3] isSuffixOf :: UArray Word8 -> UArray Word8 -> Bool #-}
diff --git a/Foundation/Array/Unboxed/ByteArray.hs b/Foundation/Array/Unboxed/ByteArray.hs
--- a/Foundation/Array/Unboxed/ByteArray.hs
+++ b/Foundation/Array/Unboxed/ByteArray.hs
@@ -19,7 +19,7 @@
     -- naive haskell way. TODO: call memset or a 32-bit/64-bit method
     forM_ [0..(sizeLastOffset len)] $ \i -> unsafeWrite mba i val
   where
-    len = mutableLengthSize mba
+    len = mutableLength mba
 
 {-
 mutableByteArraySetBetween :: PrimMonad prim => MUArray Word8 (PrimState prim) -> Word8 -> Offset Word8 -> CountOf Word8 -> prim ()
diff --git a/Foundation/Array/Unboxed/Mutable.hs b/Foundation/Array/Unboxed/Mutable.hs
--- a/Foundation/Array/Unboxed/Mutable.hs
+++ b/Foundation/Array/Unboxed/Mutable.hs
@@ -1,6 +1,5 @@
 -- |
--- Module      : Foundation.Array.Unboxed.Mutable
--- License     : BSD-style
+-- Module      : Foundation.Array.Unboxed.Mutable -- License     : BSD-style
 -- Maintainer  : Vincent Hanquez <vincent@snarc.org>
 -- Stability   : experimental
 -- Portability : portable
@@ -18,8 +17,9 @@
     -- * Property queries
     , sizeInMutableBytesOfContent
     , mutableLength
-    , mutableLengthSize
+    , mutableOffset
     , mutableSame
+    , onMutableBackend
     -- * Allocation & Copy
     , new
     , newPinned
@@ -42,7 +42,6 @@
 import           GHC.Types
 import           GHC.Ptr
 import           Foundation.Internal.Base
-import qualified Foundation.Primitive.Runtime as Runtime
 import           Foundation.Internal.Primitive
 import           Foundation.Internal.Proxy
 import           Foundation.Primitive.Types.OffsetSize
@@ -50,31 +49,16 @@
 import           Foundation.Primitive.Types
 import           Foundation.Primitive.FinalPtr
 import           Foundation.Primitive.Exception
+import qualified Foundation.Primitive.Block.Mutable as MBLK
+import           Foundation.Primitive.Block         (MutableBlock(..))
+import           Foundation.Primitive.UArray.Base hiding (empty)
 import           Foundation.Numerical
 import           Foreign.Marshal.Utils (copyBytes)
 
--- | A Mutable array of types built on top of GHC primitive.
---
--- Element in this array can be modified in place.
-data MUArray ty st =
-      MUVecMA {-# UNPACK #-} !(Offset ty)
-              {-# UNPACK #-} !(CountOf ty)
-              {-# UNPACK #-} !PinnedStatus
-                             (MutableByteArray# st)
-    | MUVecAddr {-# UNPACK #-} !(Offset ty)
-                {-# UNPACK #-} !(CountOf ty)
-                               !(FinalPtr ty)
-
-mutableArrayProxyTy :: MUArray ty st -> Proxy ty
-mutableArrayProxyTy _ = Proxy
-
-sizeInMutableBytesOfContent :: PrimType ty => MUArray ty s -> Size8
-sizeInMutableBytesOfContent = primSizeInBytes . mutableArrayProxyTy
+sizeInMutableBytesOfContent :: forall ty s . PrimType ty => MUArray ty s -> Size8
+sizeInMutableBytesOfContent _ = primSizeInBytes (Proxy :: Proxy ty)
 {-# INLINE sizeInMutableBytesOfContent #-}
 
-mvectorProxyTy :: MUArray ty s -> Proxy ty
-mvectorProxyTy _ = Proxy
-
 -- | read a cell in a mutable array.
 --
 -- If the index is out of bounds, an error is raised.
@@ -82,18 +66,9 @@
 read array n
     | isOutOfBound n len = primOutOfBound OOB_Read n len
     | otherwise          = unsafeRead array n
-  where len = mutableLengthSize array
+  where len = mutableLength array
 {-# INLINE read #-}
 
--- | read from a cell in a mutable array without bounds checking.
---
--- Reading from invalid memory can return unpredictable and invalid values.
--- use 'read' if unsure.
-unsafeRead :: (PrimMonad prim, PrimType ty) => MUArray ty (PrimState prim) -> Offset ty -> prim ty
-unsafeRead (MUVecMA start _ _ mba) i = primMbaRead mba (start + i)
-unsafeRead (MUVecAddr start _ fptr) i = withFinalPtr fptr $ \(Ptr addr) -> primAddrRead addr (start + i)
-{-# INLINE unsafeRead #-}
-
 -- | Write to a cell in a mutable array.
 --
 -- If the index is out of bounds, an error is raised.
@@ -102,177 +77,54 @@
     | isOutOfBound n len = primOutOfBound OOB_Write n len
     | otherwise          = unsafeWrite array n val
   where
-    len = mutableLengthSize array
+    len = mutableLength array
 {-# INLINE write #-}
 
--- | write to a cell in a mutable array without bounds checking.
---
--- Writing with invalid bounds will corrupt memory and your program will
--- become unreliable. use 'write' if unsure.
-unsafeWrite :: (PrimMonad prim, PrimType ty) => MUArray ty (PrimState prim) -> Offset ty -> ty -> prim ()
-unsafeWrite (MUVecMA start _ _ mba)  i v = primMbaWrite mba (start+i) v
-unsafeWrite (MUVecAddr start _ fptr) i v = withFinalPtr fptr $ \(Ptr addr) -> primAddrWrite addr (start+i) v
-{-# INLINE unsafeWrite #-}
-
--- | Create a new pinned mutable array of size @n.
---
--- all the cells are uninitialized and could contains invalid values.
---
--- All mutable arrays are allocated on a 64 bits aligned addresses
-newPinned :: (PrimMonad prim, PrimType ty) => CountOf ty -> prim (MUArray ty (PrimState prim))
-newPinned n = newFake n Proxy
-  where newFake :: (PrimMonad prim, PrimType ty) => CountOf ty -> Proxy ty -> prim (MUArray ty (PrimState prim))
-        newFake sz ty = primitive $ \s1 ->
-            case newAlignedPinnedByteArray# bytes 8# s1 of
-                (# s2, mba #) -> (# s2, MUVecMA (Offset 0) sz pinned mba #)
-          where
-                !(CountOf (I# bytes)) = sizeOfE (primSizeInBytes ty) sz
-        {-# INLINE newFake #-}
-
-newUnpinned :: (PrimMonad prim, PrimType ty) => CountOf ty -> prim (MUArray ty (PrimState prim))
-newUnpinned n = newFake n Proxy
-  where newFake :: (PrimMonad prim, PrimType ty) => CountOf ty -> Proxy ty -> prim (MUArray ty (PrimState prim))
-        newFake sz ty = primitive $ \s1 ->
-            case newByteArray# bytes s1 of
-                (# s2, mba #) -> (# s2, MUVecMA (Offset 0) sz unpinned mba #)
-          where
-                !(CountOf (I# bytes)) = sizeOfE (primSizeInBytes ty) sz
-        {-# INLINE newFake #-}
-
-empty :: PrimMonad prim => prim (MUArray ty (PrimState prim))
-empty = primitive $ \s1 -> case newByteArray# 0# s1 of { (# s2, mba #) -> (# s2, MUVecMA 0 0 unpinned mba #) }
-
--- | Create a new mutable array of size @n.
---
--- When memory for a new array is allocated, we decide if that memory region
--- should be pinned (will not be copied around by GC) or unpinned (can be
--- moved around by GC) depending on its size.
---
--- You can change the threshold value used by setting the environment variable
--- @HS_FOUNDATION_UARRAY_UNPINNED_MAX@.
-new :: (PrimMonad prim, PrimType ty) => CountOf ty -> prim (MUArray ty (PrimState prim))
-new sz
-    | sizeRecast sz <= maxSizeUnpinned = newUnpinned sz
-    | otherwise                        = newPinned sz
-  where
-    -- Safe to use here: If the value changes during runtime, this will only
-    -- have an impact on newly created arrays.
-    maxSizeUnpinned = Runtime.unsafeUArrayUnpinnedMaxSize
-{-# INLINE new #-}
+empty :: (PrimType ty, PrimMonad prim) => prim (MUArray ty (PrimState prim))
+empty = MUArray 0 0 . MUArrayMBA <$> MBLK.mutableEmpty
 
 mutableSame :: MUArray ty st -> MUArray ty st -> Bool
-mutableSame (MUVecMA sa ea _ ma) (MUVecMA sb eb _ mb) = (sa == sb) && (ea == eb) && bool# (sameMutableByteArray# ma mb)
-mutableSame (MUVecAddr s1 e1 f1) (MUVecAddr s2 e2 f2) = (s1 == s2) && (e1 == e2) && finalPtrSameMemory f1 f2
-mutableSame MUVecMA {}     MUVecAddr {}   = False
-mutableSame MUVecAddr {}   MUVecMA {}     = False
-
-
-newNative :: (PrimMonad prim, PrimType ty)
-          => CountOf ty
-          -> (MutableByteArray# (PrimState prim) -> prim a)
-          -> prim (a, MUArray ty (PrimState prim))
-newNative n f = do
-    muvec <- new n
-    case muvec of
-        (MUVecMA _ _ _ mba) -> f mba >>= \a -> pure (a, muvec)
-        MUVecAddr {}        -> error "internal error: unboxed new only supposed to allocate natively"
+mutableSame (MUArray sa ea (MUArrayMBA (MutableBlock ma))) (MUArray sb eb (MUArrayMBA (MutableBlock mb))) = (sa == sb) && (ea == eb) && bool# (sameMutableByteArray# ma mb)
+mutableSame (MUArray s1 e1 (MUArrayAddr f1)) (MUArray s2 e2 (MUArrayAddr f2)) = (s1 == s2) && (e1 == e2) && finalPtrSameMemory f1 f2
+mutableSame _ _ = False
 
 mutableForeignMem :: (PrimMonad prim, PrimType ty)
                   => FinalPtr ty -- ^ the start pointer with a finalizer
                   -> Int         -- ^ the number of elements (in elements, not bytes)
                   -> prim (MUArray ty (PrimState prim))
-mutableForeignMem fptr nb = return $ MUVecAddr (Offset 0) (CountOf nb) fptr
-
--- | Copy a number of elements from an array to another array with offsets
-copyAt :: (PrimMonad prim, PrimType ty)
-       => MUArray ty (PrimState prim) -- ^ destination array
-       -> Offset ty                  -- ^ offset at destination
-       -> MUArray ty (PrimState prim) -- ^ source array
-       -> Offset ty                  -- ^ offset at source
-       -> CountOf ty                    -- ^ number of elements to copy
-       -> prim ()
-copyAt (MUVecMA dstStart _ _ dstMba) ed uvec@(MUVecMA srcStart _ _ srcBa) es n =
-    primitive $ \st -> (# copyMutableByteArray# srcBa os dstMba od nBytes st, () #)
-  where
-    !sz                 = primSizeInBytes (mutableArrayProxyTy uvec)
-    !(Offset (I# os))   = offsetOfE sz (srcStart + es)
-    !(Offset (I# od))   = offsetOfE sz (dstStart + ed)
-    !(CountOf (I# nBytes)) = sizeOfE sz n
-copyAt (MUVecMA dstStart _ _ dstMba) ed muvec@(MUVecAddr srcStart _ srcFptr) es n =
-    withFinalPtr srcFptr $ \srcPtr ->
-        let !(Ptr srcAddr) = srcPtr `plusPtr` os
-         in primitive $ \s -> (# compatCopyAddrToByteArray# srcAddr dstMba od nBytes s, () #)
-  where
-    !sz                 = primSizeInBytes (mutableArrayProxyTy muvec)
-    !(Offset os)        = offsetOfE sz (srcStart + es)
-    !(Offset (I# od))   = offsetOfE sz (dstStart + ed)
-    !(CountOf (I# nBytes)) = sizeOfE sz n
-copyAt dst od src os n = loop od os
-  where
-    !endIndex = os `offsetPlusE` n
-    loop !d !i
-        | i == endIndex = return ()
-        | otherwise     = unsafeRead src i >>= unsafeWrite dst d >> loop (d+1) (i+1)
+mutableForeignMem fptr nb = pure $ MUArray (Offset 0) (CountOf nb) (MUArrayAddr fptr)
 
 sub :: (PrimMonad prim, PrimType ty)
     => MUArray ty (PrimState prim)
     -> Int -- The number of elements to drop ahead
     -> Int -- Then the number of element to retain
     -> prim (MUArray ty (PrimState prim))
-sub (MUVecMA start sz pstatus mba) dropElems' takeElems
-    | takeElems <= 0 = empty
-    | resultEmpty    = empty
-    | otherwise      = return $ MUVecMA (start `offsetPlusE` dropElems) (min (CountOf takeElems) (sz - dropElems)) pstatus mba
-  where
-    dropElems = max 0 (CountOf dropElems')
-    resultEmpty = dropElems >= sz
-sub (MUVecAddr start sz addr) dropElems' takeElems
+sub (MUArray start sz back) dropElems' takeElems
     | takeElems <= 0 = empty
     | resultEmpty    = empty
-    | otherwise      = return $ MUVecAddr (start `offsetPlusE` dropElems) (min (CountOf takeElems) (sz - dropElems)) addr
+    | otherwise      = pure $ MUArray (start `offsetPlusE` dropElems) (min (CountOf takeElems) (sz - dropElems)) back
   where
     dropElems = max 0 (CountOf dropElems')
     resultEmpty = dropElems >= sz
 
-{-
-copyAddr :: (PrimMonad prim, PrimType ty)
-         => MUArray ty (PrimState prim) -- ^ destination array
-         -> Offset ty                  -- ^ offset at destination
-         -> Ptr Word8                   -- ^ source ptr
-         -> Offset ty                  -- ^ offset at source
-         -> CountOf ty                    -- ^ number of elements to copy
-         -> prim ()
-copyAddr (MUVecMA dstStart _ _ dst) dstOfs (Ptr src) srcOfs sz = primitive $ \s ->
-    (# compatCopyAddrToByteArray# (plusAddr# src os) dst od sz s, () #)
-copyAddr (MUVecAddr start _ fptr) od src os sz =
-    withFinalPtr fptr $ \dst ->
-        unsafePrimFromIO $ copyBytes (dst `plusPtr` od) (src `plusPtr` os) sz
-        --memcpy addr to addr
-        -}
-
 -- | return the numbers of elements in a mutable array
-mutableLength :: PrimType ty => MUArray ty st -> Int
-mutableLength (MUVecMA _ (CountOf end) _ _) = end
-mutableLength (MUVecAddr _ (CountOf end) _) = end
-
-mutableLengthSize :: PrimType ty => MUArray ty st -> CountOf ty
-mutableLengthSize (MUVecMA _ end _ _) = end
-mutableLengthSize (MUVecAddr _ end _) = end
+mutableLength :: PrimType ty => MUArray ty st -> CountOf ty
+mutableLength (MUArray _ end _)   = end
 
-withMutablePtrHint :: (PrimMonad prim, PrimType ty)
+withMutablePtrHint :: forall ty prim a . (PrimMonad prim, PrimType ty)
                    => Bool
                    -> Bool
                    -> MUArray ty (PrimState prim)
                    -> (Ptr ty -> prim a)
                    -> prim a
-withMutablePtrHint _ _ vec@(MUVecAddr start _ fptr)  f =
+withMutablePtrHint _ _ (MUArray start _ (MUArrayAddr fptr))  f =
     withFinalPtr fptr (\ptr -> f (ptr `plusPtr` os))
   where
-    sz           = primSizeInBytes (mvectorProxyTy vec)
+    sz           = primSizeInBytes (Proxy :: Proxy ty)
     !(Offset os) = offsetOfE sz start
-withMutablePtrHint skipCopy skipCopyBack vec@(MUVecMA start vecSz pstatus a) f
-    | isPinned pstatus = mutableByteArrayContent a >>= \ptr -> f (ptr `plusPtr` os)
-    | otherwise        = do
+withMutablePtrHint skipCopy skipCopyBack vec@(MUArray start vecSz (MUArrayMBA (MutableBlock a))) f
+    | isMutablePinned vec == Pinned = mutableByteArrayContent a >>= \ptr -> f (ptr `plusPtr` os)
+    | otherwise                     = do
         trampoline <- newPinned vecSz
         if not skipCopy
             then copyAt trampoline 0 vec 0 vecSz
@@ -284,7 +136,7 @@
         pure r
   where
     !(Offset os) = offsetOfE sz start
-    sz           = primSizeInBytes (mvectorProxyTy vec)
+    sz           = primSizeInBytes (Proxy :: Proxy ty)
 
     mutableByteArrayContent :: PrimMonad prim => MutableByteArray# (PrimState prim) -> prim (Ptr ty)
     mutableByteArrayContent mba = primitive $ \s1 ->
@@ -308,35 +160,36 @@
 -- | Copy from a pointer, @count@ elements, into the mutable array
 copyFromPtr :: forall prim ty . (PrimMonad prim, PrimType ty)
             => Ptr ty -> CountOf ty -> MUArray ty (PrimState prim) -> prim ()
-copyFromPtr (Ptr p) count (MUVecMA ofs arrSz _ mba)
-    | count > arrSz = primOutOfBound OOB_MemCopy (sizeAsOffset count) arrSz
-    | otherwise     = primitive $ \st -> (# copyAddrToByteArray# p mba od countBytes st, () #)
-  where
-    !sz                     = primSizeInBytes (Proxy :: Proxy ty)
-    !(CountOf (I# countBytes)) = sizeOfE sz count
-    !(Offset (I# od))       = offsetOfE sz ofs
-copyFromPtr p count (MUVecAddr ofs arrSz fptr)
+copyFromPtr src@(Ptr src#) count marr
     | count > arrSz = primOutOfBound OOB_MemCopy (sizeAsOffset count) arrSz
-    | otherwise     = withFinalPtr fptr $ \dstPtr ->
-        unsafePrimFromIO $ copyBytes (dstPtr `plusPtr` os) p bytes
+    | otherwise     = onMutableBackend copyNative copyPtr marr
   where
-        sz = primSizeInBytes (Proxy :: Proxy ty)
-        !(CountOf bytes) = sizeOfE sz count
-        !(Offset os) = offsetOfE sz ofs
+    arrSz = mutableLength marr
+    ofs = mutableOffset marr
 
+    sz = primSizeInBytes (Proxy :: Proxy ty)
+    !(CountOf bytes@(I# bytes#)) = sizeOfE sz count
+    !(Offset od@(I# od#)) = offsetOfE sz $ ofs
+
+    copyNative mba = primitive $ \st -> (# copyAddrToByteArray# src# mba od# bytes# st, () #)
+    copyPtr fptr = withFinalPtr fptr $ \dst ->
+        unsafePrimFromIO $ copyBytes (dst `plusPtr` od) src bytes
+
 -- | Copy all the block content to the memory starting at the destination address
 copyToPtr :: forall ty prim . (PrimType ty, PrimMonad prim)
           => MUArray ty (PrimState prim) -- ^ the source mutable array to copy
           -> Ptr ty                      -- ^ The destination address where the copy is going to start
           -> prim ()
-copyToPtr (MUVecMA start sz _ ma) (Ptr p) = primitive $ \s1 ->
-    case unsafeFreezeByteArray# ma s1 of
-        (# s2, ba #) -> (# compatCopyByteArrayToAddr# ba offset p szBytes s2, () #)
-  where
-    !(Offset (I# offset)) = offsetInBytes start
-    !(CountOf (I# szBytes)) = sizeInBytes sz
-copyToPtr (MUVecAddr start sz fptr) dst =
-    unsafePrimFromIO $ withFinalPtr fptr $ \ptr -> copyBytes dst (ptr `plusPtr` os) szBytes
+copyToPtr marr dst@(Ptr dst#) = onMutableBackend copyNative copyPtr marr
   where
-    !(Offset os)    = offsetInBytes start
-    !(CountOf szBytes) = sizeInBytes sz
+    copyNative mba = primitive $ \s1 ->
+        case unsafeFreezeByteArray# mba s1 of
+            (# s2, ba #) -> (# compatCopyByteArrayToAddr# ba os# dst# szBytes# s2, () #)
+    copyPtr fptr = unsafePrimFromIO $ withFinalPtr fptr $ \ptr ->
+        copyBytes dst (ptr `plusPtr` os) szBytes
+
+    !(Offset os@(I# os#)) = offsetInBytes $ mutableOffset marr
+    !(CountOf szBytes@(I# szBytes#)) = sizeInBytes $ mutableLength marr
+
+mutableOffset :: MUArray ty st -> Offset ty
+mutableOffset (MUArray ofs _ _) = ofs
diff --git a/Foundation/Boot/List.hs b/Foundation/Boot/List.hs
--- a/Foundation/Boot/List.hs
+++ b/Foundation/Boot/List.hs
@@ -1,15 +1,23 @@
+{-# LANGUAGE CPP #-}
 module Foundation.Boot.List
     ( length
     , sum
+    , reverse
     ) where
 
 import Foundation.Internal.Base
 import Foundation.Numerical.Additive
+import qualified GHC.List as List
 
 -- | Compute the size of the list
 length :: [a] -> Int
-length []     = 0
-length (_:xs) = succ (length xs)
+#if MIN_VERSION_base(4,8,0)
+length = List.foldl' (\c _ -> c+1) 0
+#else
+length = loop 0
+  where loop !acc []     = acc
+        loop !acc (_:xs) = loop (1+acc) xs
+#endif
 
 -- | Sum the element in a list
 sum :: Additive n => [n] -> n
@@ -19,3 +27,9 @@
     loop !acc [] = acc
     loop !acc (x:xs) = loop (acc+x) xs
     {-# INLINE loop #-}
+
+reverse :: [a] -> [a]
+reverse l =  go l []
+  where
+    go []     acc = acc
+    go (x:xs) acc = go xs (x:acc)
diff --git a/Foundation/Check/Arbitrary.hs b/Foundation/Check/Arbitrary.hs
--- a/Foundation/Check/Arbitrary.hs
+++ b/Foundation/Check/Arbitrary.hs
@@ -11,8 +11,7 @@
 
 import           Foundation.Primitive.Imports
 import           Foundation.Primitive
-import           Foundation.Primitive.IntegralConv (wordToChar)
-import           Foundation.Primitive.Floating
+import           Foundation.Primitive.IntegralConv
 import           Foundation.Primitive.Types.OffsetSize
 import           Foundation.Check.Gen
 import           Foundation.Random
@@ -32,45 +31,41 @@
 
 -- prim types
 instance Arbitrary Int where
-    arbitrary = arbitraryPrimtype
+    arbitrary = int64ToInt <$> arbitraryInt64
 instance Arbitrary Word where
-    arbitrary = arbitraryPrimtype
+    arbitrary = word64ToWord <$> arbitraryWord64
 instance Arbitrary Word64 where
-    arbitrary = arbitraryPrimtype
+    arbitrary = arbitraryWord64
 instance Arbitrary Word32 where
-    arbitrary = arbitraryPrimtype
+    arbitrary = integralDownsize <$> arbitraryWord64
 instance Arbitrary Word16 where
-    arbitrary = arbitraryPrimtype
+    arbitrary = integralDownsize <$> arbitraryWord64
 instance Arbitrary Word8 where
-    arbitrary = arbitraryPrimtype
+    arbitrary = integralDownsize <$> arbitraryWord64
 instance Arbitrary Int64 where
-    arbitrary = arbitraryPrimtype
+    arbitrary = arbitraryInt64
 instance Arbitrary Int32 where
-    arbitrary = arbitraryPrimtype
+    arbitrary = integralDownsize <$> arbitraryInt64
 instance Arbitrary Int16 where
-    arbitrary = arbitraryPrimtype
+    arbitrary = integralDownsize <$> arbitraryInt64
 instance Arbitrary Int8 where
-    arbitrary = arbitraryPrimtype
+    arbitrary = integralDownsize <$> arbitraryInt64
 instance Arbitrary Char where
     arbitrary = arbitraryChar
 instance Arbitrary (CountOf ty) where
     arbitrary = CountOf <$> arbitrary
 
 instance Arbitrary Bool where
-    arbitrary = flip testBit 0 <$> (arbitraryPrimtype :: Gen Word)
+    arbitrary = flip testBit 0 <$> arbitraryWord64
 
 instance Arbitrary String where
     arbitrary = genWithParams $ \params ->
         fromList <$> (genMax (genMaxSizeString params) >>= \i -> replicateM (integralCast i) arbitrary)
 
 instance Arbitrary Float where
-    arbitrary = toFloat <$> arbitrary <*> arbitrary <*> arbitrary
-      where toFloat i n Nothing  = integerToFloat i + (naturalToFloat n / 100000)
-            toFloat i n (Just e) = (integerToFloat i + (naturalToFloat n / 1000000)) * (integerToFloat e)
+    arbitrary = arbitraryF32
 instance Arbitrary Double where
-    arbitrary = toDouble <$> arbitrary <*> arbitrary <*> arbitrary
-      where toDouble i n Nothing  = integerToDouble i + (naturalToDouble n / 100000)
-            toDouble i n (Just e) = (integerToDouble i + (naturalToDouble n / 1000000)) * (integerToDouble e)
+    arbitrary = arbitraryF64
 
 instance Arbitrary a => Arbitrary (Maybe a) where
     arbitrary = frequency $ nonEmpty_ [ (1, pure Nothing), (4, Just <$> arbitrary) ]
@@ -121,13 +116,22 @@
     , (1, wordToChar <$> genMax 0x10ffff)
     ]
 
-arbitraryPrimtype :: PrimType ty => Gen ty
-arbitraryPrimtype = genWithRng getRandomPrimType
+arbitraryWord64 :: Gen Word64
+arbitraryWord64 = genWithRng getRandomWord64
 
-arbitraryUArrayOf :: PrimType ty => Word -> Gen (UArray ty)
-arbitraryUArrayOf size =
-    between (0, size) >>= \sz -> (fromList <$> replicateM (integralCast sz) arbitraryPrimtype)
+arbitraryInt64 :: Gen Int64
+arbitraryInt64 = integralCast <$> arbitraryWord64
 
+arbitraryF64 :: Gen Double
+arbitraryF64 = genWithRng getRandomF64
+
+arbitraryF32 :: Gen Float
+arbitraryF32 = genWithRng getRandomF32
+
+arbitraryUArrayOf :: (PrimType ty, Arbitrary ty) => Word -> Gen (UArray ty)
+arbitraryUArrayOf size = between (0, size) >>=
+    \sz -> fromList <$> replicateM (integralCast sz) arbitrary
+
 -- | Call one of the generator weighted
 frequency :: NonEmpty [(Word, Gen a)] -> Gen a
 frequency (getNonEmpty -> l) = between (0, sum) >>= pickOne l
@@ -151,4 +155,4 @@
   where range = y - x
 
 genMax :: Word -> Gen Word
-genMax m = (flip mod m) <$> arbitraryPrimtype
+genMax m = flip mod m <$> arbitrary
diff --git a/Foundation/Check/Main.hs b/Foundation/Check/Main.hs
--- a/Foundation/Check/Main.hs
+++ b/Foundation/Check/Main.hs
@@ -98,7 +98,7 @@
             Right c -> pure c
 
     -- use the user defined seed or generate a new seed
-    seed <- maybe getRandomPrimType pure $ udfSeed cfg
+    seed <- maybe getRandomWord64 pure $ udfSeed cfg
 
     let testState = newState cfg seed
 
diff --git a/Foundation/Collection.hs b/Foundation/Collection.hs
--- a/Foundation/Collection.hs
+++ b/Foundation/Collection.hs
@@ -14,6 +14,7 @@
     , Element
     , InnerFunctor(..)
     , Foldable(..)
+    , Fold1able(..)
     , Mappable(..)
     , traverse_
     , mapM_
diff --git a/Foundation/Collection/Collection.hs b/Foundation/Collection/Collection.hs
--- a/Foundation/Collection/Collection.hs
+++ b/Foundation/Collection/Collection.hs
@@ -146,8 +146,8 @@
     elem = S.elem
     minimum = Data.List.minimum . toList . getNonEmpty -- TODO faster implementation
     maximum = Data.List.maximum . toList . getNonEmpty -- TODO faster implementation
-    all p = Data.List.all p . toList
-    any p = Data.List.any p . toList
+    all = S.all
+    any = S.any
 
 instance Collection c => Collection (NonEmpty c) where
     null _ = False
diff --git a/Foundation/Collection/Sequential.hs b/Foundation/Collection/Sequential.hs
--- a/Foundation/Collection/Sequential.hs
+++ b/Foundation/Collection/Sequential.hs
@@ -192,6 +192,18 @@
             | otherwise   = loop (succ i)
           where c2Sub = take len1 $ drop i c2
 
+    -- | Try to strip a prefix from a collection
+    stripPrefix :: Eq (Element c) => c -> c -> Maybe c
+    stripPrefix pre s
+        | isPrefixOf pre s = Just $ drop (length pre) s
+        | otherwise        = Nothing
+
+    -- | Try to strip a suffix from a collection
+    stripSuffix :: Eq (Element c) => c -> c -> Maybe c
+    stripSuffix suf s
+        | isSuffixOf suf s = Just $ revDrop (length suf) s
+        | otherwise        = Nothing
+
 -- Temporary utility functions
 mconcatCollection :: (Monoid (Item c), Sequential c) => c -> Element c
 mconcatCollection c = mconcat (toList c)
@@ -263,6 +275,8 @@
     sortBy = UV.sortBy
     singleton = fromList . (:[])
     replicate = UV.replicate
+    isPrefixOf = UV.isPrefixOf
+    isSuffixOf = UV.isSuffixOf
 
 instance Sequential (BA.Array ty) where
     take = BA.take
@@ -285,6 +299,8 @@
     sortBy = BA.sortBy
     singleton = BA.singleton
     replicate = BA.replicate
+    isSuffixOf = BA.isSuffixOf
+    isPrefixOf = BA.isPrefixOf
 
 instance Sequential S.String where
     take = S.take
@@ -311,3 +327,5 @@
     isSuffixOf = S.isSuffixOf
     isPrefixOf = S.isPrefixOf
     isInfixOf  = S.isInfixOf
+    stripPrefix = S.stripPrefix
+    stripSuffix = S.stripSuffix
diff --git a/Foundation/Conduit/Textual.hs b/Foundation/Conduit/Textual.hs
--- a/Foundation/Conduit/Textual.hs
+++ b/Foundation/Conduit/Textual.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE OverloadedStrings #-}
 module Foundation.Conduit.Textual
     ( lines
     , words
@@ -5,7 +6,7 @@
     , toBytes
     ) where
 
-import           Foundation.Internal.Base hiding (throw)
+import           Foundation.Primitive.Imports hiding (throw)
 import           Foundation.Array.Unboxed (UArray)
 import           Foundation.String (String)
 import           Foundation.Collection
@@ -19,22 +20,27 @@
 -- This is very similar to Prelude lines except
 -- it work directly on Conduit
 --
--- Note that if the newline character is not coming,
+-- Note that if the newline character is not ever appearing in the stream,
 -- this function will keep accumulating data until OOM
+--
+-- TODO: make a size-limited function
 lines :: Monad m => Conduit String String m ()
-lines = await >>= maybe (finish []) (go [])
+lines = await >>= maybe (finish []) (go False [])
   where
     mconcatRev = mconcat . reverse
 
     finish l = if null l then return () else yield (mconcatRev l)
 
-    go prevs nextBuf =
-        case S.uncons next' of
-            Just (_, rest') -> yield (mconcatRev (line : prevs)) >> go mempty rest'
-            Nothing         ->
+    go prevCR prevs nextBuf = do
+        case S.breakLine nextBuf of
+            Right (line, next)
+                | S.null line && prevCR -> yield (mconcatRev (line : stripCRFromHead prevs)) >> go False mempty next
+                | otherwise             -> yield (mconcatRev (line : prevs)) >> go False mempty next
+            Left lastCR ->
                 let nextCurrent = nextBuf : prevs
-                 in await >>= maybe (finish nextCurrent) (go nextCurrent)
-      where (line, next') = S.breakElem '\n' nextBuf
+                 in await >>= maybe (finish nextCurrent) (go lastCR nextCurrent)
+    stripCRFromHead []     = []
+    stripCRFromHead (x:xs) = S.revDrop 1 x:xs
 
 words :: Monad m => Conduit String String m ()
 words = await >>= maybe (finish []) (go [])
diff --git a/Foundation/Hashing/FNV.hs b/Foundation/Hashing/FNV.hs
--- a/Foundation/Hashing/FNV.hs
+++ b/Foundation/Hashing/FNV.hs
@@ -25,12 +25,12 @@
 import qualified Foundation.Array.Unboxed as A
 import           Foundation.Primitive.Types.OffsetSize
 import           Foundation.Primitive.Types
+import           Foundation.Primitive.IntegralConv
 import           Foundation.Numerical
 import           Foundation.Hashing.Hasher
 import           Data.Bits
 import           GHC.Prim
 import           GHC.ST
-import qualified Prelude
 
 -- | FNV1(a) hash (32 bit variants)
 newtype FNV1Hash32 = FNV1Hash32 Word32
@@ -41,11 +41,11 @@
     deriving (Show,Eq,Ord)
 
 xor32 :: Word -> Word8 -> Word
-xor32 !a !b = a `xor` Prelude.fromIntegral b
+xor32 !a !b = a `xor` integralUpsize b
 {-# INLINE xor32 #-}
 
 xor64 :: Word64 -> Word8 -> Word64
-xor64 !a !b = a `xor` Prelude.fromIntegral b
+xor64 !a !b = a `xor` integralUpsize b
 {-# INLINE xor64 #-}
 
 -- | FNV1 32 bit state
@@ -81,7 +81,7 @@
     type HashInitParam FNV1_32 = Word
     hashNew = FNV1_32 0
     hashNewParam w = FNV1_32 w
-    hashEnd (FNV1_32 w) = FNV1Hash32 (Prelude.fromIntegral w)
+    hashEnd (FNV1_32 w) = FNV1Hash32 (integralDownsize w)
     hashMix8 = fnv1_32_Mix8
     hashMixBytes = fnv1_32_mixBa
 
@@ -90,7 +90,7 @@
     type HashInitParam FNV1a_32 = Word
     hashNew = FNV1a_32 0
     hashNewParam w = FNV1a_32 w
-    hashEnd (FNV1a_32 w) = FNV1Hash32 (Prelude.fromIntegral w)
+    hashEnd (FNV1a_32 w) = FNV1Hash32 (integralDownsize w)
     hashMix8 = fnv1a_32_Mix8
     hashMixBytes = fnv1a_32_mixBa
 
@@ -99,7 +99,7 @@
     type HashInitParam FNV1_64 = Word64
     hashNew = FNV1_64 0xcbf29ce484222325
     hashNewParam w = FNV1_64 w
-    hashEnd (FNV1_64 w) = FNV1Hash64 (Prelude.fromIntegral w)
+    hashEnd (FNV1_64 w) = FNV1Hash64 w
     hashMix8 = fnv1_64_Mix8
     hashMixBytes = fnv1_64_mixBa
 
@@ -108,7 +108,7 @@
     type HashInitParam FNV1a_64 = Word64
     hashNew = FNV1a_64 0xcbf29ce484222325
     hashNewParam w = FNV1a_64 w
-    hashEnd (FNV1a_64 w) = FNV1Hash64 (Prelude.fromIntegral w)
+    hashEnd (FNV1a_64 w) = FNV1Hash64 w
     hashMix8 = fnv1a_64_Mix8
     hashMixBytes = fnv1a_64_mixBa
 
diff --git a/Foundation/Hashing/Hashable.hs b/Foundation/Hashing/Hashable.hs
--- a/Foundation/Hashing/Hashable.hs
+++ b/Foundation/Hashing/Hashable.hs
@@ -14,6 +14,7 @@
 
 import Foundation.Internal.Base
 import Foundation.Internal.Natural
+import Foundation.Primitive.IntegralConv
 import Foundation.Numerical.Primitives
 import Foundation.Numerical.Multiplicative
 import Foundation.Array
@@ -21,7 +22,6 @@
 import Foundation.String
 import Foundation.Collection.Foldable
 import Foundation.Hashing.Hasher
-import qualified Prelude
 
 -- | Type with the ability to be hashed
 --
@@ -50,7 +50,7 @@
       where
         loop 0 acc = acc
         loop w acc =
-            let b = Prelude.fromIntegral w
+            let b = integralDownsize (w :: Natural) :: Word8
              in loop (w `div` 256) (hashMix8 b acc)
 instance Hashable Int8 where
     hashMix w = hashMix8 (integralConvert w)
@@ -63,12 +63,13 @@
 instance Hashable Integer where
     hashMix i iacc
         | i == 0    = hashMix8 0 iacc
-        | i < 0     = loop (-i) (hashMix8 1 iacc)
-        | otherwise = loop i (hashMix8 0 iacc)
+        | i < 0     = loop (integerToNatural i) (hashMix8 1 iacc)
+        | otherwise = loop (integerToNatural i) (hashMix8 0 iacc)
       where
+        loop :: Hasher st => Natural -> st -> st
         loop 0 acc = acc
         loop w acc =
-            let b = Prelude.fromIntegral w
+            let b = integralDownsize w :: Word8
              in loop (w `div` 256) (hashMix8 b acc)
 
 instance Hashable String where
diff --git a/Foundation/Hashing/Hasher.hs b/Foundation/Hashing/Hasher.hs
--- a/Foundation/Hashing/Hasher.hs
+++ b/Foundation/Hashing/Hasher.hs
@@ -4,10 +4,10 @@
     ) where
 
 import           Foundation.Internal.Base
+import           Foundation.Primitive.IntegralConv
 import           Foundation.Array (UArray)
 import qualified Foundation.Array.Unboxed as A
 import           Data.Bits
-import qualified Prelude
 
 -- | Incremental Hashing state. Represent an hashing algorithm
 --
@@ -57,18 +57,18 @@
     hashMixBytes ba st = A.foldl' (flip hashMix8) st (A.unsafeRecast ba)
 
 unWord16 :: Word16 -> (# Word8, Word8 #)
-unWord16 w = (# Prelude.fromIntegral (w `unsafeShiftR` 8)
-             ,  Prelude.fromIntegral w #)
+unWord16 w = (# integralDownsize (w `unsafeShiftR` 8)
+             ,  integralDownsize w #)
 {-# INLINE unWord16 #-}
 
 unWord32 :: Word32 -> (# Word8, Word8, Word8, Word8 #)
-unWord32 w = (# Prelude.fromIntegral (w `unsafeShiftR` 24)
-             ,  Prelude.fromIntegral (w `unsafeShiftR` 16)
-             ,  Prelude.fromIntegral (w `unsafeShiftR` 8)
-             ,  Prelude.fromIntegral w #)
+unWord32 w = (# integralDownsize (w `unsafeShiftR` 24)
+             ,  integralDownsize (w `unsafeShiftR` 16)
+             ,  integralDownsize (w `unsafeShiftR` 8)
+             ,  integralDownsize w #)
 {-# INLINE unWord32 #-}
 
 unWord64_32 :: Word64 -> (# Word32, Word32 #)
-unWord64_32 w = (# Prelude.fromIntegral (w `unsafeShiftR` 32)
-                ,  Prelude.fromIntegral w #)
+unWord64_32 w = (# integralDownsize (w `unsafeShiftR` 32)
+                ,  integralDownsize w #)
 {-# INLINE unWord64_32 #-}
diff --git a/Foundation/Internal/Natural.hs b/Foundation/Internal/Natural.hs
--- a/Foundation/Internal/Natural.hs
+++ b/Foundation/Internal/Natural.hs
@@ -2,11 +2,13 @@
 {-# LANGUAGE GeneralizedNewtypeDeriving #-}
 module Foundation.Internal.Natural
     ( Natural
+    , integerToNatural
     ) where
 
 #if MIN_VERSION_base(4,8,0)
 
 import Numeric.Natural
+import Prelude (Integer, abs, fromInteger)
 
 #else
 
@@ -49,3 +51,6 @@
     mod = rem
 
 #endif
+
+integerToNatural :: Integer -> Natural
+integerToNatural i = fromInteger (abs i)
diff --git a/Foundation/Internal/PrimTypes.hs b/Foundation/Internal/PrimTypes.hs
--- a/Foundation/Internal/PrimTypes.hs
+++ b/Foundation/Internal/PrimTypes.hs
@@ -10,6 +10,8 @@
     ( FileSize#
     , Offset#
     , CountOf#
+    , Bool#
+    , Pinned#
     ) where
 
 import GHC.Prim
@@ -26,3 +28,9 @@
 --
 -- for code documentation purpose only, just a simple type alias on Int#
 type CountOf# = Int#
+
+-- | Lowlevel Boolean
+type Bool# = Int#
+
+-- | Pinning status
+type Pinned# = Bool#
diff --git a/Foundation/Internal/Primitive.hs b/Foundation/Internal/Primitive.hs
--- a/Foundation/Internal/Primitive.hs
+++ b/Foundation/Internal/Primitive.hs
@@ -8,9 +8,10 @@
 {-# LANGUAGE MagicHash #-}
 {-# LANGUAGE UnboxedTuples #-}
 {-# LANGUAGE CPP #-}
+{-# LANGUAGE UnliftedFFITypes #-}
 module Foundation.Internal.Primitive
     ( bool#
-    , PinnedStatus, pinned, unpinned, isPinned
+    , PinnedStatus(..), toPinnedStatus#
     , compatAndI#
     , compatQuotRemInt#
     , compatCopyAddrToByteArray#
@@ -19,6 +20,8 @@
     , compatGetSizeofMutableByteArray#
     , compatShrinkMutableByteArray#
     , compatResizeMutableByteArray#
+    , compatIsByteArrayPinned#
+    , compatIsMutableByteArrayPinned#
     , Word(..)
     ) where
 
@@ -29,6 +32,8 @@
 import           GHC.IO
 #endif
 
+import           Foundation.Internal.PrimTypes
+
 --  GHC 8.0  | Base 4.9
 --  GHC 7.10 | Base 4.8
 --  GHC 7.8  | Base 4.7
@@ -36,17 +41,12 @@
 --  GHC 7.4  | Base 4.5
 
 -- | Flag record whether a specific byte array is pinned or not
-data PinnedStatus = PinnedStatus Int#
-
-isPinned :: PinnedStatus -> Prelude.Bool
-isPinned (PinnedStatus 0#) = Prelude.False
-isPinned _                 = Prelude.True
-
-pinned :: PinnedStatus
-pinned = PinnedStatus 1#
+data PinnedStatus = Pinned | Unpinned
+    deriving (Prelude.Eq)
 
-unpinned :: PinnedStatus
-unpinned = PinnedStatus 0#
+toPinnedStatus# :: Pinned# -> PinnedStatus
+toPinnedStatus# 0# = Unpinned
+toPinnedStatus# _  = Pinned
 
 -- | turn an Int# into a Bool
 --
@@ -163,3 +163,17 @@
     !len = sizeofMutableByteArray# src
 #endif
 {-# INLINE compatResizeMutableByteArray# #-}
+
+#if __GLASGOW_HASKELL__ >= 802
+compatIsByteArrayPinned# :: ByteArray# -> Pinned#
+compatIsByteArrayPinned# ba = isByteArrayPinned# ba
+
+compatIsMutableByteArrayPinned# :: MutableByteArray# s -> Pinned#
+compatIsMutableByteArrayPinned# ba = isMutableByteArrayPinned# ba
+#else
+foreign import ccall unsafe "foundation_is_bytearray_pinned"
+    compatIsByteArrayPinned# :: ByteArray# -> Pinned#
+
+foreign import ccall unsafe "foundation_is_bytearray_pinned"
+    compatIsMutableByteArrayPinned# :: MutableByteArray# s -> Pinned#
+#endif
diff --git a/Foundation/Parser.hs b/Foundation/Parser.hs
--- a/Foundation/Parser.hs
+++ b/Foundation/Parser.hs
@@ -32,6 +32,7 @@
     , -- * Result
       Result(..)
     , ParseError(..)
+    , reportError
 
     , -- * Parser source
       ParserSource(..)
@@ -278,6 +279,19 @@
 -- ------------------------------------------------------------------------- --
 --                          Helpers                                          --
 -- ------------------------------------------------------------------------- --
+
+-- | helper function to report error when writing parsers
+--
+-- This way we can provide more detailed error when building custom
+-- parsers and still avoid to use the naughty _fail_.
+--
+-- @
+-- myParser :: Parser input Int
+-- myParser = reportError $ Satisfy (Just "this function is not implemented...")
+-- @
+--
+reportError :: ParseError input -> Parser input a
+reportError pe = Parser $ \buf off nm err _ -> err buf off nm pe
 
 -- | Get the next `Element input` from the parser
 anyElement :: ParserSource input => Parser input (Element input)
diff --git a/Foundation/Primitive/Block.hs b/Foundation/Primitive/Block.hs
--- a/Foundation/Primitive/Block.hs
+++ b/Foundation/Primitive/Block.hs
@@ -7,7 +7,7 @@
 -- very similar to an unboxed array but with the key difference:
 --
 -- * It doesn't have slicing capability (no cheap take or drop)
--- * It consume less memory: 1 Offset, 1 CountOf, 1 Pinning status trimmed
+-- * It consume less memory: 1 Offset, 1 CountOf
 -- * It's unpackable in any constructor
 -- * It uses unpinned memory by default
 --
@@ -28,6 +28,8 @@
     , copy
     -- * safer api
     , create
+    , isPinned
+    , isMutablePinned
     , singleton
     , replicate
     , index
@@ -96,6 +98,12 @@
         M.iterSet initializer mb
         unsafeFreeze mb
 
+isPinned :: Block ty -> PinnedStatus
+isPinned (Block ba) = toPinnedStatus# (compatIsByteArrayPinned# ba)
+
+isMutablePinned :: MutableBlock s ty -> PinnedStatus
+isMutablePinned (MutableBlock mba) = toPinnedStatus# (compatIsMutableByteArrayPinned# mba)
+
 singleton :: PrimType ty => ty -> Block ty
 singleton ty = create 1 (const ty)
 
@@ -108,14 +116,14 @@
 -- and its content is copied to the mutable block
 thaw :: (PrimMonad prim, PrimType ty) => Block ty -> prim (MutableBlock ty (PrimState prim))
 thaw array = do
-    ma <- M.unsafeNew unpinned (lengthBytes array)
+    ma <- M.unsafeNew Unpinned (lengthBytes array)
     M.unsafeCopyBytesRO ma 0 array 0 (lengthBytes array)
-    return ma
+    pure ma
 {-# INLINE thaw #-}
 
 freeze :: (PrimType ty, PrimMonad prim) => MutableBlock ty (PrimState prim) -> prim (Block ty)
 freeze ma = do
-    ma' <- unsafeNew unpinned len
+    ma' <- unsafeNew Unpinned len
     M.unsafeCopyBytes ma' 0 ma 0 len
     --M.copyAt ma' (Offset 0) ma (Offset 0) len
     unsafeFreeze ma'
@@ -146,21 +154,28 @@
 foldr f initialAcc vec = loop 0
   where
     !len = length vec
-    loop i
+    loop !i
         | i .==# len = initialAcc
         | otherwise  = unsafeIndex vec i `f` loop (i+1)
+{-# SPECIALIZE [2] foldr :: (Word8 -> a -> a) -> a -> Block Word8 -> a #-}
 
 foldl' :: PrimType ty => (a -> ty -> a) -> a -> Block ty -> a
 foldl' f initialAcc vec = loop 0 initialAcc
   where
     !len = length vec
-    loop i !acc
+    loop !i !acc
         | i .==# len = acc
         | otherwise  = loop (i+1) (f acc (unsafeIndex vec i))
+{-# SPECIALIZE [2] foldl' :: (a -> Word8 -> a) -> a -> Block Word8 -> a #-}
 
 foldl1' :: PrimType ty => (ty -> ty -> ty) -> NonEmpty (Block ty) -> ty
-foldl1' f arr = let (initialAcc, rest) = splitAt 1 $ getNonEmpty arr
-               in foldl' f (unsafeIndex initialAcc 0) rest
+foldl1' f (NonEmpty arr) = loop 1 (unsafeIndex arr 0)
+  where
+    !len = length arr
+    loop !i !acc
+        | i .==# len = acc
+        | otherwise  = loop (i+1) (f acc (unsafeIndex arr i))
+{-# SPECIALIZE [3] foldl1' :: (Word8 -> Word8 -> Word8) -> NonEmpty (Block Word8) -> Word8 #-}
 
 foldr1 :: PrimType ty => (ty -> ty -> ty) -> NonEmpty (Block ty) -> ty
 foldr1 f arr = let (initialAcc, rest) = revSplitAt 1 $ getNonEmpty arr
@@ -179,11 +194,11 @@
 
 snoc :: PrimType ty => Block ty -> ty -> Block ty
 snoc vec e
-    | len == CountOf 0 = singleton e
-    | otherwise     = runST $ do
+    | len == 0  = singleton e
+    | otherwise = runST $ do
         muv <- new (len + 1)
         M.unsafeCopyElementsRO muv 0 vec 0 len
-        M.unsafeWrite muv (0 `offsetPlusE` length vec) e
+        M.unsafeWrite muv (0 `offsetPlusE` len) e
         unsafeFreeze muv
   where
      !len = length vec
@@ -229,6 +244,7 @@
   where
     n    = min nbElems vlen
     vlen = length blk
+{-# SPECIALIZE [2] splitAt :: CountOf Word8 -> Block Word8 -> (Block Word8, Block Word8) #-}
 
 revSplitAt :: PrimType ty => CountOf ty -> Block ty -> (Block ty, Block ty)
 revSplitAt n blk
@@ -244,6 +260,7 @@
         | predicate (unsafeIndex blk i) = splitAt (offsetAsSize i) blk
         | otherwise                     = findBreak (i + 1)
     {-# INLINE findBreak #-}
+{-# SPECIALIZE [2] break :: (Word8 -> Bool) -> Block Word8 -> (Block Word8, Block Word8) #-}
 
 span :: PrimType ty => (ty -> Bool) -> Block ty -> (Block ty, Block ty)
 span p = break (not . p)
@@ -252,28 +269,31 @@
 elem v blk = loop 0
   where
     !len = length blk
-    loop i
+    loop !i
         | i .==# len             = False
         | unsafeIndex blk i == v = True
         | otherwise              = loop (i+1)
+{-# SPECIALIZE [2] elem :: Word8 -> Block Word8 -> Bool #-}
 
 all :: PrimType ty => (ty -> Bool) -> Block ty -> Bool
 all p blk = loop 0
   where
     !len = length blk
-    loop i
+    loop !i
         | i .==# len            = True
         | p (unsafeIndex blk i) = loop (i+1)
         | otherwise             = False
+{-# SPECIALIZE [2] all :: (Word8 -> Bool) -> Block Word8 -> Bool #-}
 
 any :: PrimType ty => (ty -> Bool) -> Block ty -> Bool
 any p blk = loop 0
   where
     !len = length blk
-    loop i
+    loop !i
         | i .==# len            = False
         | p (unsafeIndex blk i) = True
         | otherwise             = loop (i+1)
+{-# SPECIALIZE [2] any :: (Word8 -> Bool) -> Block Word8 -> Bool #-}
 
 splitOn :: PrimType ty => (ty -> Bool) -> Block ty -> [Block ty]
 splitOn predicate blk
@@ -332,7 +352,7 @@
     doSort ford ma = qsort 0 (sizeLastOffset len) >> unsafeFreeze ma
       where
         qsort lo hi
-            | lo >= hi  = return ()
+            | lo >= hi  = pure ()
             | otherwise = do
                 p <- partition lo hi
                 qsort lo (pred p)
diff --git a/Foundation/Primitive/Block/Base.hs b/Foundation/Primitive/Block/Base.hs
--- a/Foundation/Primitive/Block/Base.hs
+++ b/Foundation/Primitive/Block/Base.hs
@@ -19,6 +19,7 @@
     , length
     , lengthBytes
     -- * Other methods
+    , mutableEmpty
     , new
     , newPinned
     , touch
@@ -74,10 +75,11 @@
 
 length :: forall ty . PrimType ty => Block ty -> CountOf ty
 length (Block ba) =
-    let !(CountOf (I# szBits)) = primSizeInBytes (Proxy :: Proxy ty)
-        !elems              = quotInt# (sizeofByteArray# ba) szBits
-     in CountOf (I# elems)
+    case primShiftToBytes (Proxy :: Proxy ty) of
+        0           -> CountOf (I# (sizeofByteArray# ba))
+        (I# szBits) -> CountOf (I# (uncheckedIShiftRL# (sizeofByteArray# ba) szBits))
 {-# INLINE[1] length #-}
+{-# SPECIALIZE [2] length :: Block Word8 -> CountOf Word8 #-}
 
 lengthBytes :: Block ty -> CountOf Word8
 lengthBytes (Block ba) = CountOf (I# (sizeofByteArray# ba))
@@ -93,6 +95,11 @@
     case unsafeFreezeByteArray# mba s2 of { (# s3, ba  #) ->
         (# s3, Block ba #) }}
 
+mutableEmpty :: PrimMonad prim => prim (MutableBlock ty (PrimState prim))
+mutableEmpty = primitive $ \s1 ->
+    case newByteArray# 0# s1 of { (# s2, mba #) ->
+        (# s2, MutableBlock mba #) }
+
 -- | Return the element at a specific index from an array without bounds checking.
 --
 -- Reading from invalid memory can return unpredictable and invalid values.
@@ -143,7 +150,7 @@
 equalMemcmp :: PrimMemoryComparable ty => Block ty -> Block ty -> Bool
 equalMemcmp b1@(Block a) b2@(Block b)
     | la /= lb  = False
-    | otherwise = unsafeDupablePerformIO (sysHsMemcmpBaBa a 0 b 0 (csizeOfSize la)) == 0
+    | otherwise = unsafeDupablePerformIO (sysHsMemcmpBaBa a 0 b 0 la) == 0
   where
     la = lengthBytes b1
     lb = lengthBytes b2
@@ -175,7 +182,7 @@
   where
     la = lengthBytes b1
     lb = lengthBytes b2
-    sz = csizeOfSize $ min la lb
+    sz = min la lb
 {-# SPECIALIZE [3] compareMemcmp :: Block Word8 -> Block Word8 -> Ordering #-}
 
 -- | Append 2 blocks together by creating a new bigger block
@@ -184,7 +191,7 @@
     | la == azero = b
     | lb == azero = a
     | otherwise = runST $ do
-        r  <- unsafeNew unpinned (la+lb)
+        r  <- unsafeNew Unpinned (la+lb)
         unsafeCopyBytesRO r 0                 a 0 la
         unsafeCopyBytesRO r (sizeAsOffset la) b 0 lb
         unsafeFreeze r
@@ -199,7 +206,7 @@
         (_,[])            -> empty
         (_,[x])           -> x
         (totalLen,chunks) -> runST $ do
-            r <- unsafeNew unpinned totalLen
+            r <- unsafeNew Unpinned totalLen
             doCopy r 0 chunks
             unsafeFreeze r
   where
@@ -247,16 +254,16 @@
           => PinnedStatus
           -> CountOf Word8
           -> prim (MutableBlock ty (PrimState prim))
-unsafeNew pinStatus (CountOf (I# bytes))
-    | isPinned pinStatus = primitive $ \s1 -> case newByteArray# bytes s1 of { (# s2, mba #) -> (# s2, MutableBlock mba #) }
-    | otherwise          = primitive $ \s1 -> case newAlignedPinnedByteArray# bytes 8# s1 of { (# s2, mba #) -> (# s2, MutableBlock mba #) }
+unsafeNew pinSt (CountOf (I# bytes)) = case pinSt of
+    Unpinned -> primitive $ \s1 -> case newByteArray# bytes s1 of { (# s2, mba #) -> (# s2, MutableBlock mba #) }
+    _        -> primitive $ \s1 -> case newAlignedPinnedByteArray# bytes 8# s1 of { (# s2, mba #) -> (# s2, MutableBlock mba #) }
 
 -- | Create a new mutable block of a specific N size of 'ty' elements
 new :: forall prim ty . (PrimMonad prim, PrimType ty) => CountOf ty -> prim (MutableBlock ty (PrimState prim))
-new n = unsafeNew unpinned (sizeOfE (primSizeInBytes (Proxy :: Proxy ty)) n)
+new n = unsafeNew Unpinned (sizeOfE (primSizeInBytes (Proxy :: Proxy ty)) n)
 
 newPinned :: forall prim ty . (PrimMonad prim, PrimType ty) => CountOf ty -> prim (MutableBlock ty (PrimState prim))
-newPinned n = unsafeNew pinned (sizeOfE (primSizeInBytes (Proxy :: Proxy ty)) n)
+newPinned n = unsafeNew Pinned (sizeOfE (primSizeInBytes (Proxy :: Proxy ty)) n)
 
 -- | Copy a number of elements from an array to another array with offsets
 unsafeCopyElements :: forall prim ty . (PrimMonad prim, PrimType ty)
diff --git a/Foundation/Primitive/Block/Mutable.hs b/Foundation/Primitive/Block/Mutable.hs
--- a/Foundation/Primitive/Block/Mutable.hs
+++ b/Foundation/Primitive/Block/Mutable.hs
@@ -41,7 +41,7 @@
     , mutableGetAddr
     , new
     , newPinned
-    , isPinned
+    , mutableEmpty
     , iterSet
     , read
     , write
@@ -80,13 +80,6 @@
 mutableLengthBytes :: MutableBlock ty st -> CountOf Word8
 mutableLengthBytes (MutableBlock mba) = CountOf (I# (sizeofMutableByteArray# mba))
 {-# INLINE[1] mutableLengthBytes #-}
-
--- | Return if a Mutable Block is pinned or not
-isPinned :: MutableBlock ty st -> Bool
-isPinned (MutableBlock mba) =
-    -- TODO use the exact value where the array become pinned (LARGE_OBJECT_THRESHOLD)
-    -- in 8.2, there's a primitive to know if an array in pinned
-    I# (sizeofMutableByteArray# mba) > 3000
 
 -- | Get the address of the context of the mutable block.
 --
diff --git a/Foundation/Primitive/Endianness.hs b/Foundation/Primitive/Endianness.hs
--- a/Foundation/Primitive/Endianness.hs
+++ b/Foundation/Primitive/Endianness.hs
@@ -10,6 +10,7 @@
 --
 
 {-# LANGUAGE CPP #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
 
 module Foundation.Primitive.Endianness
     (
@@ -35,7 +36,9 @@
 import System.IO.Unsafe (unsafePerformIO)
 #endif
 
+import Data.Bits
 
+
 -- #if !defined(ARCH_IS_LITTLE_ENDIAN) && !defined(ARCH_IS_BIG_ENDIAN)
 -- import Foundation.System.Info (endianness, Endianness(..))
 -- #endif
@@ -47,13 +50,13 @@
 
 -- | Little Endian value
 newtype LE a = LE { unLE :: a }
-  deriving (Show, Eq, Typeable)
+  deriving (Show, Eq, Typeable, Bits)
 instance (ByteSwap a, Ord a) => Ord (LE a) where
     compare e1 e2 = compare (fromLE e1) (fromLE e2)
 
 -- | Big Endian value
 newtype BE a = BE { unBE :: a }
-  deriving (Show, Eq, Typeable)
+  deriving (Show, Eq, Typeable, Bits)
 instance (ByteSwap a, Ord a) => Ord (BE a) where
     compare e1 e2 = compare (fromBE e1) (fromBE e2)
 
diff --git a/Foundation/Primitive/FinalPtr.hs b/Foundation/Primitive/FinalPtr.hs
--- a/Foundation/Primitive/FinalPtr.hs
+++ b/Foundation/Primitive/FinalPtr.hs
@@ -18,6 +18,7 @@
     , castFinalPtr
     , toFinalPtr
     , toFinalPtrForeign
+    , touchFinalPtr
     , withFinalPtr
     , withUnsafeFinalPtr
     , withFinalPtrNoTouch
@@ -36,7 +37,7 @@
 data FinalPtr a = FinalPtr (Ptr a)
                 | FinalForeign (ForeignPtr a)
 instance Show (FinalPtr a) where
-    show f = runST $ withFinalPtr f (return . show)
+    show f = runST $ withFinalPtr f (pure . show)
 instance Eq (FinalPtr a) where
     (==) f1 f2 = runST (equal f1 f2)
 instance Ord (FinalPtr a) where
@@ -80,13 +81,17 @@
 withFinalPtr (FinalPtr ptr) f = do
     r <- f ptr
     primTouch ptr
-    return r
+    pure r
 withFinalPtr (FinalForeign fptr) f = do
     r <- f (unsafeForeignPtrToPtr fptr)
     unsafePrimFromIO (touchForeignPtr fptr)
-    return r
+    pure r
 {-# INLINE withFinalPtr #-}
 
+touchFinalPtr :: PrimMonad prim => FinalPtr p -> prim ()
+touchFinalPtr (FinalPtr ptr) = primTouch ptr
+touchFinalPtr (FinalForeign fptr) = unsafePrimFromIO (touchForeignPtr fptr)
+
 -- | Unsafe version of 'withFinalPtr'
 withUnsafeFinalPtr :: PrimMonad prim => FinalPtr p -> (Ptr p -> prim a) -> a
 withUnsafeFinalPtr fptr f = unsafePerformIO (unsafePrimToIO (withFinalPtr fptr f))
@@ -96,12 +101,12 @@
 equal f1 f2 =
     withFinalPtr f1 $ \ptr1 ->
     withFinalPtr f2 $ \ptr2 ->
-        return $ ptr1 == ptr2
+        pure $ ptr1 == ptr2
 {-# INLINE equal #-}
 
 compare_ :: PrimMonad prim => FinalPtr a -> FinalPtr a -> prim Ordering
 compare_ f1 f2 =
     withFinalPtr f1 $ \ptr1 ->
     withFinalPtr f2 $ \ptr2 ->
-        return $ ptr1 `compare` ptr2
+        pure $ ptr1 `compare` ptr2
 {-# INLINE compare_ #-}
diff --git a/Foundation/Primitive/IntegralConv.hs b/Foundation/Primitive/IntegralConv.hs
--- a/Foundation/Primitive/IntegralConv.hs
+++ b/Foundation/Primitive/IntegralConv.hs
@@ -9,6 +9,7 @@
     , IntegralUpsize(..)
     , IntegralCast(..)
     , intToInt64
+    , int64ToInt
     , wordToWord64
     , word64ToWord32s
     , word64ToWord
@@ -183,6 +184,16 @@
     integralDownsizeCheck = integralDownsizeBounded integralDownsize
 instance IntegralDownsize Word64 Word32 where
     integralDownsize      (W64# i) = W32# (narrow32Word# (word64ToWord# i))
+    integralDownsizeCheck = integralDownsizeBounded integralDownsize
+
+instance IntegralDownsize Word Word8 where
+    integralDownsize (W# w) = W8# (narrow8Word# w)
+    integralDownsizeCheck = integralDownsizeBounded integralDownsize
+instance IntegralDownsize Word Word16 where
+    integralDownsize (W# w) = W16# (narrow16Word# w)
+    integralDownsizeCheck = integralDownsizeBounded integralDownsize
+instance IntegralDownsize Word Word32 where
+    integralDownsize (W# w) = W32# (narrow32Word# w)
     integralDownsizeCheck = integralDownsizeBounded integralDownsize
 
 instance IntegralDownsize Word32 Word8 where
diff --git a/Foundation/Primitive/NormalForm.hs b/Foundation/Primitive/NormalForm.hs
--- a/Foundation/Primitive/NormalForm.hs
+++ b/Foundation/Primitive/NormalForm.hs
@@ -7,6 +7,7 @@
 import Foundation.Internal.Base
 import Foundation.Internal.Natural
 import Foundation.Primitive.Types.OffsetSize
+import Foundation.Primitive.Endianness
 import Foreign.C.Types
 
 -- | Data that can be fully evaluated in Normal Form
@@ -78,6 +79,10 @@
 instance (NormalForm l, NormalForm r) => NormalForm (Either l r) where
     toNormalForm (Left l)  = toNormalForm l `seq` ()
     toNormalForm (Right r) = toNormalForm r `seq` ()
+instance NormalForm a => NormalForm (LE a) where
+    toNormalForm (LE a) = toNormalForm a `seq` ()
+instance NormalForm a => NormalForm (BE a) where
+    toNormalForm (BE a) = toNormalForm a `seq` ()
 
 instance NormalForm a => NormalForm [a] where
     toNormalForm []     = ()
diff --git a/Foundation/Primitive/Runtime.hs b/Foundation/Primitive/Runtime.hs
--- a/Foundation/Primitive/Runtime.hs
+++ b/Foundation/Primitive/Runtime.hs
@@ -26,5 +26,5 @@
 unsafeUArrayUnpinnedMaxSize :: Size8
 unsafeUArrayUnpinnedMaxSize = unsafePerformIO $ do
     maxSize <- (>>= readMaybe) <$> lookupEnv "HS_FOUNDATION_UARRAY_UNPINNED_MAX"
-    return $ maybe (CountOf 1024) CountOf maxSize
+    pure $ maybe (CountOf 1024) CountOf maxSize
 {-# NOINLINE unsafeUArrayUnpinnedMaxSize #-}
diff --git a/Foundation/Primitive/Types.hs b/Foundation/Primitive/Types.hs
--- a/Foundation/Primitive/Types.hs
+++ b/Foundation/Primitive/Types.hs
@@ -25,6 +25,8 @@
     , sizeAsOffset
     , sizeInBytes
     , offsetInBytes
+    , offsetInElements
+    , offsetIsAligned
     , primWordGetByteAndShift
     , primWord64GetByteAndShift
     , primWord64GetHiLo
@@ -36,9 +38,11 @@
 import           GHC.Int
 import           GHC.Types
 import           GHC.Word
+import           Data.Bits
 import           Foreign.C.Types
 import           Foundation.Internal.Proxy
 import           Foundation.Internal.Base
+import           Foundation.Numerical.Subtractive
 import           Foundation.Primitive.Types.OffsetSize
 import           Foundation.Primitive.Endianness
 import           Foundation.Primitive.Monad
@@ -156,6 +160,9 @@
     -- | get the size in bytes of a ty element
     primSizeInBytes :: Proxy ty -> Size8
 
+    -- | get the shift size
+    primShiftToBytes :: Proxy ty -> Int
+
     -----
     -- ByteArray section
     -----
@@ -201,12 +208,17 @@
                   -> prim ()
 
 sizeInt, sizeWord :: CountOf Word8
+shiftInt, shiftWord :: Int
 #if WORD_SIZE_IN_BITS == 64
 sizeInt = CountOf 8
 sizeWord = CountOf 8
+shiftInt = 3
+shiftWord = 3
 #else
 sizeInt = CountOf 4
 sizeWord = CountOf 4
+shiftInt = 2
+shiftWord = 2
 #endif
 
 {-# SPECIALIZE [3] primBaUIndex :: ByteArray# -> Offset Word8 -> Word8 #-}
@@ -214,6 +226,8 @@
 instance PrimType Int where
     primSizeInBytes _ = sizeInt
     {-# INLINE primSizeInBytes #-}
+    primShiftToBytes _ = shiftInt
+    {-# INLINE primShiftToBytes #-}
     primBaUIndex ba (Offset (I# n)) = I# (indexIntArray# ba n)
     {-# INLINE primBaUIndex #-}
     primMbaURead mba (Offset (I# n)) = primitive $ \s1 -> let (# s2, r #) = readIntArray# mba n s1 in (# s2, I# r #)
@@ -230,6 +244,8 @@
 instance PrimType Word where
     primSizeInBytes _ = sizeWord
     {-# INLINE primSizeInBytes #-}
+    primShiftToBytes _ = shiftWord
+    {-# INLINE primShiftToBytes #-}
     primBaUIndex ba (Offset (I# n)) = W# (indexWordArray# ba n)
     {-# INLINE primBaUIndex #-}
     primMbaURead mba (Offset (I# n)) = primitive $ \s1 -> let (# s2, r #) = readWordArray# mba n s1 in (# s2, W# r #)
@@ -246,6 +262,8 @@
 instance PrimType Word8 where
     primSizeInBytes _ = CountOf 1
     {-# INLINE primSizeInBytes #-}
+    primShiftToBytes _ = 0
+    {-# INLINE primShiftToBytes #-}
     primBaUIndex ba (Offset (I# n)) = W8# (indexWord8Array# ba n)
     {-# INLINE primBaUIndex #-}
     primMbaURead mba (Offset (I# n)) = primitive $ \s1 -> let (# s2, r #) = readWord8Array# mba n s1 in (# s2, W8# r #)
@@ -262,6 +280,8 @@
 instance PrimType Word16 where
     primSizeInBytes _ = CountOf 2
     {-# INLINE primSizeInBytes #-}
+    primShiftToBytes _ = 1
+    {-# INLINE primShiftToBytes #-}
     primBaUIndex ba (Offset (I# n)) = W16# (indexWord16Array# ba n)
     {-# INLINE primBaUIndex #-}
     primMbaURead mba (Offset (I# n)) = primitive $ \s1 -> let (# s2, r #) = readWord16Array# mba n s1 in (# s2, W16# r #)
@@ -277,6 +297,8 @@
 instance PrimType Word32 where
     primSizeInBytes _ = CountOf 4
     {-# INLINE primSizeInBytes #-}
+    primShiftToBytes _ = 2
+    {-# INLINE primShiftToBytes #-}
     primBaUIndex ba (Offset (I# n)) = W32# (indexWord32Array# ba n)
     {-# INLINE primBaUIndex #-}
     primMbaURead mba (Offset (I# n)) = primitive $ \s1 -> let (# s2, r #) = readWord32Array# mba n s1 in (# s2, W32# r #)
@@ -292,6 +314,8 @@
 instance PrimType Word64 where
     primSizeInBytes _ = CountOf 8
     {-# INLINE primSizeInBytes #-}
+    primShiftToBytes _ = 3
+    {-# INLINE primShiftToBytes #-}
     primBaUIndex ba (Offset (I# n)) = W64# (indexWord64Array# ba n)
     {-# INLINE primBaUIndex #-}
     primMbaURead mba (Offset (I# n)) = primitive $ \s1 -> let (# s2, r #) = readWord64Array# mba n s1 in (# s2, W64# r #)
@@ -307,6 +331,8 @@
 instance PrimType Int8 where
     primSizeInBytes _ = CountOf 1
     {-# INLINE primSizeInBytes #-}
+    primShiftToBytes _ = 0
+    {-# INLINE primShiftToBytes #-}
     primBaUIndex ba (Offset (I# n)) = I8# (indexInt8Array# ba n)
     {-# INLINE primBaUIndex #-}
     primMbaURead mba (Offset (I# n)) = primitive $ \s1 -> let (# s2, r #) = readInt8Array# mba n s1 in (# s2, I8# r #)
@@ -322,6 +348,8 @@
 instance PrimType Int16 where
     primSizeInBytes _ = CountOf 2
     {-# INLINE primSizeInBytes #-}
+    primShiftToBytes _ = 1
+    {-# INLINE primShiftToBytes #-}
     primBaUIndex ba (Offset (I# n)) = I16# (indexInt16Array# ba n)
     {-# INLINE primBaUIndex #-}
     primMbaURead mba (Offset (I# n)) = primitive $ \s1 -> let (# s2, r #) = readInt16Array# mba n s1 in (# s2, I16# r #)
@@ -337,6 +365,8 @@
 instance PrimType Int32 where
     primSizeInBytes _ = CountOf 4
     {-# INLINE primSizeInBytes #-}
+    primShiftToBytes _ = 2
+    {-# INLINE primShiftToBytes #-}
     primBaUIndex ba (Offset (I# n)) = I32# (indexInt32Array# ba n)
     {-# INLINE primBaUIndex #-}
     primMbaURead mba (Offset (I# n)) = primitive $ \s1 -> let (# s2, r #) = readInt32Array# mba n s1 in (# s2, I32# r #)
@@ -352,6 +382,8 @@
 instance PrimType Int64 where
     primSizeInBytes _ = CountOf 8
     {-# INLINE primSizeInBytes #-}
+    primShiftToBytes _ = 3
+    {-# INLINE primShiftToBytes #-}
     primBaUIndex ba (Offset (I# n)) = I64# (indexInt64Array# ba n)
     {-# INLINE primBaUIndex #-}
     primMbaURead mba (Offset (I# n)) = primitive $ \s1 -> let (# s2, r #) = readInt64Array# mba n s1 in (# s2, I64# r #)
@@ -368,6 +400,8 @@
 instance PrimType Float where
     primSizeInBytes _ = CountOf 4
     {-# INLINE primSizeInBytes #-}
+    primShiftToBytes _ = 2
+    {-# INLINE primShiftToBytes #-}
     primBaUIndex ba (Offset (I# n)) = F# (indexFloatArray# ba n)
     {-# INLINE primBaUIndex #-}
     primMbaURead mba (Offset (I# n)) = primitive $ \s1 -> let (# s2, r #) = readFloatArray# mba n s1 in (# s2, F# r #)
@@ -383,6 +417,8 @@
 instance PrimType Double where
     primSizeInBytes _ = CountOf 8
     {-# INLINE primSizeInBytes #-}
+    primShiftToBytes _ = 3
+    {-# INLINE primShiftToBytes #-}
     primBaUIndex ba (Offset (I# n)) = D# (indexDoubleArray# ba n)
     {-# INLINE primBaUIndex #-}
     primMbaURead mba (Offset (I# n)) = primitive $ \s1 -> let (# s2, r #) = readDoubleArray# mba n s1 in (# s2, D# r #)
@@ -399,6 +435,8 @@
 instance PrimType Char where
     primSizeInBytes _ = CountOf 4
     {-# INLINE primSizeInBytes #-}
+    primShiftToBytes _ = 2
+    {-# INLINE primShiftToBytes #-}
     primBaUIndex ba (Offset (I# n)) = C# (indexWideCharArray# ba n)
     {-# INLINE primBaUIndex #-}
     primMbaURead mba (Offset (I# n)) = primitive $ \s1 -> let (# s2, r #) = readWideCharArray# mba n s1 in (# s2, C# r #)
@@ -415,6 +453,8 @@
 instance PrimType CChar where
     primSizeInBytes _ = CountOf 1
     {-# INLINE primSizeInBytes #-}
+    primShiftToBytes _ = 0
+    {-# INLINE primShiftToBytes #-}
     primBaUIndex ba (Offset n) = CChar (primBaUIndex ba (Offset n))
     {-# INLINE primBaUIndex #-}
     primMbaURead mba (Offset n) = CChar <$> primMbaURead mba (Offset n)
@@ -430,6 +470,8 @@
 instance PrimType CUChar where
     primSizeInBytes _ = CountOf 1
     {-# INLINE primSizeInBytes #-}
+    primShiftToBytes _ = 0
+    {-# INLINE primShiftToBytes #-}
     primBaUIndex ba (Offset n) = CUChar (primBaUIndex ba (Offset n :: Offset Word8))
     {-# INLINE primBaUIndex #-}
     primMbaURead mba (Offset n) = CUChar <$> primMbaURead mba (Offset n :: Offset Word8)
@@ -446,6 +488,8 @@
 instance PrimType a => PrimType (LE a) where
     primSizeInBytes _ = primSizeInBytes (Proxy :: Proxy a)
     {-# INLINE primSizeInBytes #-}
+    primShiftToBytes _ = primShiftToBytes (Proxy :: Proxy a)
+    {-# INLINE primShiftToBytes #-}
     primBaUIndex ba (Offset a) = LE $ primBaUIndex ba (Offset a)
     {-# INLINE primBaUIndex #-}
     primMbaURead ba (Offset a) = LE <$> primMbaURead ba (Offset a)
@@ -461,6 +505,8 @@
 instance PrimType a => PrimType (BE a) where
     primSizeInBytes _ = primSizeInBytes (Proxy :: Proxy a)
     {-# INLINE primSizeInBytes #-}
+    primShiftToBytes _ = primShiftToBytes (Proxy :: Proxy a)
+    {-# INLINE primShiftToBytes #-}
     primBaUIndex ba (Offset a) = BE $ primBaUIndex ba (Offset a)
     {-# INLINE primBaUIndex #-}
     primMbaURead ba (Offset a) = BE <$> primMbaURead ba (Offset a)
@@ -501,7 +547,7 @@
 -- | Cast a CountOf linked to type A (CountOf A) to a CountOf linked to type B (CountOf B)
 sizeRecast :: forall a b . (PrimType a, PrimType b) => CountOf a -> CountOf b
 sizeRecast sz = CountOf (bytes `Prelude.quot` szB)
-  where !szA          = primSizeInBytes (Proxy :: Proxy a)
+  where !szA             = primSizeInBytes (Proxy :: Proxy a)
         !(CountOf szB)   = primSizeInBytes (Proxy :: Proxy b)
         !(CountOf bytes) = sizeOfE szA sz
 {-# INLINE [1] sizeRecast #-}
@@ -516,8 +562,21 @@
 sizeInBytes sz = sizeOfE (primSizeInBytes (Proxy :: Proxy a)) sz
 
 offsetInBytes :: forall a . PrimType a => Offset a -> Offset Word8
-offsetInBytes sz = offsetOfE (primSizeInBytes (Proxy :: Proxy a)) sz
+offsetInBytes ofs = offsetShiftL (primShiftToBytes (Proxy :: Proxy a)) ofs
+{-# INLINE [2] offsetInBytes #-}
+{-# SPECIALIZE INLINE [3] offsetInBytes :: Offset Word64 -> Offset Word8 #-}
+{-# SPECIALIZE INLINE [3] offsetInBytes :: Offset Word32 -> Offset Word8 #-}
+{-# SPECIALIZE INLINE [3] offsetInBytes :: Offset Word16 -> Offset Word8 #-}
+{-# RULES "offsetInBytes Bytes" [3] forall x . offsetInBytes x = x #-}
 
+offsetInElements :: forall a . PrimType a => Offset Word8 -> Offset a
+offsetInElements ofs = offsetShiftR (primShiftToBytes (Proxy :: Proxy a)) ofs
+{-# INLINE [2] offsetInElements #-}
+{-# SPECIALIZE INLINE [3] offsetInBytes :: Offset Word64 -> Offset Word8 #-}
+{-# SPECIALIZE INLINE [3] offsetInBytes :: Offset Word32 -> Offset Word8 #-}
+{-# SPECIALIZE INLINE [3] offsetInBytes :: Offset Word16 -> Offset Word8 #-}
+{-# RULES "offsetInElements Bytes" [3] forall x . offsetInElements x = x #-}
+
 primOffsetRecast :: forall a b . (PrimType a, PrimType b) => Offset a -> Offset b
 primOffsetRecast !ofs =
     let !(Offset bytes) = offsetOfE szA ofs
@@ -528,7 +587,16 @@
 {-# INLINE [1] primOffsetRecast #-}
 {-# RULES "primOffsetRecast W8" [3] forall a . primOffsetRecast a = primOffsetRecastBytes a #-}
 
+offsetIsAligned :: forall a . PrimType a => Proxy a -> Offset Word8 -> Bool
+offsetIsAligned _ (Offset ofs) = (ofs .&. mask) == 0
+   where (CountOf sz) = primSizeInBytes (Proxy :: Proxy a)
+         mask = sz - 1
+{-# INLINE [1] offsetIsAligned #-}
+{-# SPECIALIZE [3] offsetIsAligned :: Proxy Word64 -> Offset Word8 -> Bool #-}
+{-# RULES "offsetInAligned Bytes" [3] forall (prx :: Proxy Word8) x . offsetIsAligned prx x = True #-}
+
 primOffsetRecastBytes :: forall b . PrimType b => Offset Word8 -> Offset b
+primOffsetRecastBytes (Offset 0) = Offset 0
 primOffsetRecastBytes (Offset o) = Offset (szA `Prelude.quot` o)
   where !(CountOf szA) = primSizeInBytes (Proxy :: Proxy b)
 {-# INLINE [1] primOffsetRecastBytes #-}
diff --git a/Foundation/Primitive/Types/OffsetSize.hs b/Foundation/Primitive/Types/OffsetSize.hs
--- a/Foundation/Primitive/Types/OffsetSize.hs
+++ b/Foundation/Primitive/Types/OffsetSize.hs
@@ -19,6 +19,8 @@
     , offsetRecast
     , offsetCast
     , offsetSub
+    , offsetShiftL
+    , offsetShiftR
     , sizeCast
     , sizeLastOffset
     , sizeAsOffset
@@ -43,6 +45,7 @@
 import GHC.Prim
 import Foreign.C.Types
 import System.Posix.Types (CSsize (..))
+import Data.Bits
 import Foundation.Internal.Base
 import Foundation.Internal.Proxy
 import Foundation.Numerical.Primitives
@@ -52,6 +55,7 @@
 import Foundation.Numerical.Multiplicative
 import Foundation.Primitive.IntegralConv
 import Data.List (foldl')
+import qualified Prelude
 
 #if WORD_SIZE_IN_BITS < 64
 import GHC.IntWord64
@@ -73,12 +77,8 @@
 -- considering that GHC/Haskell are mostly using this for offset.
 -- Trying to bring some sanity by a lightweight wrapping.
 newtype Offset ty = Offset Int
-    deriving (Show,Eq,Ord,Enum,Additive,Typeable)
+    deriving (Show,Eq,Ord,Enum,Additive,Typeable,Integral,Prelude.Num)
 
-instance Integral (Offset ty) where
-    fromInteger n
-        | n < 0     = error "CountOf: fromInteger: negative"
-        | otherwise = Offset . fromInteger $ n
 instance IsIntegral (Offset ty) where
     toInteger (Offset i) = toInteger i
 instance IsNatural (Offset ty) where
@@ -122,6 +122,12 @@
     let (Offset bytes) = offsetOfE szTy ofs
      in Offset (bytes `div` szTy2)
 
+offsetShiftR :: Int -> Offset ty -> Offset ty2
+offsetShiftR n (Offset o) = Offset (o `unsafeShiftR` n)
+
+offsetShiftL :: Int -> Offset ty -> Offset ty2
+offsetShiftL n (Offset o) = Offset (o `unsafeShiftL` n)
+
 offsetCast :: Proxy (a -> b) -> Offset a -> Offset b
 offsetCast _ (Offset o) = Offset o
 {-# INLINE offsetCast #-}
@@ -169,12 +175,19 @@
 --
 -- Same caveats as 'Offset' apply here.
 newtype CountOf ty = CountOf Int
-    deriving (Show,Eq,Ord,Enum,Typeable)
+    deriving (Show,Eq,Ord,Enum,Typeable,Integral)
 
-instance Integral (CountOf ty) where
-    fromInteger n
-        | n < 0     = error "CountOf: fromInteger: negative"
-        | otherwise = CountOf . fromInteger $ n
+instance Prelude.Num (CountOf ty) where
+    fromInteger a = CountOf (fromInteger a)
+    (+) (CountOf a) (CountOf b) = CountOf (a+b)
+    (-) (CountOf a) (CountOf b)
+        | b > a     = CountOf 0
+        | otherwise = CountOf (a - b)
+    (*) (CountOf a) (CountOf b) = CountOf (a*b)
+    abs a = a
+    negate _ = error "cannot negate CountOf: use Foundation Numerical hierarchy for this function to not be exposed to CountOf"
+    signum (CountOf a) = CountOf (Prelude.signum a)
+
 instance IsIntegral (CountOf ty) where
     toInteger (CountOf i) = toInteger i
 instance IsNatural (CountOf ty) where
diff --git a/Foundation/Primitive/UArray/Addr.hs b/Foundation/Primitive/UArray/Addr.hs
new file mode 100644
--- /dev/null
+++ b/Foundation/Primitive/UArray/Addr.hs
@@ -0,0 +1,101 @@
+{-# LANGUAGE BangPatterns               #-}
+{-# LANGUAGE MagicHash                  #-}
+{-# LANGUAGE TypeFamilies               #-}
+{-# LANGUAGE FlexibleContexts           #-}
+{-# LANGUAGE ExistentialQuantification  #-}
+{-# LANGUAGE CPP                        #-}
+module Foundation.Primitive.UArray.Addr
+    ( findIndexElem
+    , findIndexPredicate
+    , foldl
+    , foldr
+    , foldl1
+    , all
+    , any
+    , filter
+    , primIndex
+    ) where
+
+import           GHC.Types
+import           GHC.Prim
+import           Foundation.Internal.Base
+import           Foundation.Numerical
+import           Foundation.Primitive.Types.OffsetSize
+import           Foundation.Primitive.Types
+import           Foundation.Primitive.Monad
+
+type Immutable = Addr#
+
+primIndex :: PrimType ty => Immutable -> Offset ty -> ty
+primIndex = primAddrIndex
+
+findIndexElem :: PrimType ty => ty -> Immutable -> Offset ty -> Offset ty -> Offset ty
+findIndexElem ty ba startIndex endIndex = loop startIndex
+  where
+    loop !i
+        | i < endIndex && t /= ty = loop (i+1)
+        | otherwise               = i
+      where t = primIndex ba i
+{-# INLINE findIndexElem #-}
+
+findIndexPredicate :: PrimType ty => (ty -> Bool) -> Immutable -> Offset ty -> Offset ty -> Offset ty
+findIndexPredicate predicate ba !startIndex !endIndex = loop startIndex
+  where
+    loop !i
+        | i < endIndex && not found = loop (i+1)
+        | otherwise                 = i
+      where found = predicate (primIndex ba i)
+{-# INLINE findIndexPredicate #-}
+
+foldl :: PrimType ty => (a -> ty -> a) -> a -> Immutable -> Offset ty -> Offset ty -> a
+foldl f !initialAcc ba !startIndex !endIndex = loop startIndex initialAcc
+  where
+    loop !i !acc
+        | i == endIndex = acc
+        | otherwise     = loop (i+1) (f acc (primIndex ba i))
+{-# INLINE foldl #-}
+
+foldr :: PrimType ty => (ty -> a -> a) -> a -> Immutable -> Offset ty -> Offset ty -> a
+foldr f !initialAcc ba startIndex endIndex = loop startIndex
+  where
+    loop !i
+        | i == endIndex = initialAcc
+        | otherwise     = primIndex ba i `f` loop (i+1)
+{-# INLINE foldr #-}
+
+foldl1 :: PrimType ty => (ty -> ty -> ty) -> Immutable -> Offset ty -> Offset ty -> ty
+foldl1 f ba startIndex endIndex = loop (startIndex+1) (primIndex ba startIndex)
+  where
+    loop !i !acc
+        | i == endIndex = acc
+        | otherwise     = loop (i+1) (f acc (primIndex ba i))
+{-# INLINE foldl1 #-}
+
+filter :: (PrimMonad prim, PrimType ty)
+       => (ty -> Bool) -> MutableByteArray# (PrimState prim) -> Immutable -> Offset ty -> Offset ty -> prim (CountOf ty)
+filter predicate dst src start end = loop azero start
+  where
+    loop !d !s
+        | s == end    = pure (offsetAsSize d)
+        | predicate v = primMbaWrite dst d v >> loop (d+Offset 1) (s+Offset 1)
+        | otherwise   = loop d (s+Offset 1)
+      where
+        v = primIndex src s
+
+all :: PrimType ty => (ty -> Bool) -> Immutable -> Offset ty -> Offset ty -> Bool
+all predicate ba start end = loop start
+  where
+    loop !i
+        | i == end                   = True
+        | predicate (primIndex ba i) = loop (i+1)
+        | otherwise                  = False
+{-# INLINE all #-}
+
+any :: PrimType ty => (ty -> Bool) -> Immutable -> Offset ty -> Offset ty -> Bool
+any predicate ba start end = loop start
+  where
+    loop !i
+        | i == end                   = False
+        | predicate (primIndex ba i) = True
+        | otherwise                  = loop (i+1)
+{-# INLINE any #-}
diff --git a/Foundation/Primitive/UArray/BA.hs b/Foundation/Primitive/UArray/BA.hs
new file mode 100644
--- /dev/null
+++ b/Foundation/Primitive/UArray/BA.hs
@@ -0,0 +1,100 @@
+{-# LANGUAGE BangPatterns               #-}
+{-# LANGUAGE MagicHash                  #-}
+{-# LANGUAGE TypeFamilies               #-}
+{-# LANGUAGE FlexibleContexts           #-}
+{-# LANGUAGE CPP                        #-}
+module Foundation.Primitive.UArray.BA
+    ( findIndexElem
+    , findIndexPredicate
+    , foldl
+    , foldr
+    , foldl1
+    , all
+    , any
+    , filter
+    , primIndex
+    ) where
+
+import           GHC.Types
+import           GHC.Prim
+import           Foundation.Internal.Base
+import           Foundation.Numerical
+import           Foundation.Primitive.Types.OffsetSize
+import           Foundation.Primitive.Types
+import           Foundation.Primitive.Monad
+
+type Immutable = ByteArray#
+
+primIndex :: PrimType ty => Immutable -> Offset ty -> ty
+primIndex = primBaIndex
+
+findIndexElem :: PrimType ty => ty -> Immutable -> Offset ty -> Offset ty -> Offset ty
+findIndexElem ty ba startIndex endIndex = loop startIndex
+  where
+    loop !i
+        | i < endIndex && t /= ty = loop (i+1)
+        | otherwise               = i
+      where t = primIndex ba i
+{-# INLINE findIndexElem #-}
+
+findIndexPredicate :: PrimType ty => (ty -> Bool) -> Immutable -> Offset ty -> Offset ty -> Offset ty
+findIndexPredicate predicate ba !startIndex !endIndex = loop startIndex
+  where
+    loop !i
+        | i < endIndex && not found = loop (i+1)
+        | otherwise                 = i
+      where found = predicate (primIndex ba i)
+{-# INLINE findIndexPredicate #-}
+
+foldl :: PrimType ty => (a -> ty -> a) -> a -> Immutable -> Offset ty -> Offset ty -> a
+foldl f !initialAcc ba !startIndex !endIndex = loop startIndex initialAcc
+  where
+    loop !i !acc
+        | i == endIndex = acc
+        | otherwise     = loop (i+1) (f acc (primIndex ba i))
+{-# INLINE foldl #-}
+
+foldr :: PrimType ty => (ty -> a -> a) -> a -> Immutable -> Offset ty -> Offset ty -> a
+foldr f !initialAcc ba startIndex endIndex = loop startIndex
+  where
+    loop !i
+        | i == endIndex = initialAcc
+        | otherwise     = primIndex ba i `f` loop (i+1)
+{-# INLINE foldr #-}
+
+foldl1 :: PrimType ty => (ty -> ty -> ty) -> Immutable -> Offset ty -> Offset ty -> ty
+foldl1 f ba startIndex endIndex = loop (startIndex+1) (primIndex ba startIndex)
+  where
+    loop !i !acc
+        | i == endIndex = acc
+        | otherwise     = loop (i+1) (f acc (primIndex ba i))
+{-# INLINE foldl1 #-}
+
+filter :: (PrimMonad prim, PrimType ty)
+       => (ty -> Bool) -> MutableByteArray# (PrimState prim) -> Immutable -> Offset ty -> Offset ty -> prim (CountOf ty)
+filter predicate dst src start end = loop azero start
+  where
+    loop !d !s
+        | s == end    = pure (offsetAsSize d)
+        | predicate v = primMbaWrite dst d v >> loop (d+Offset 1) (s+Offset 1)
+        | otherwise   = loop d (s+Offset 1)
+      where
+        v = primIndex src s
+
+all :: PrimType ty => (ty -> Bool) -> Immutable -> Offset ty -> Offset ty -> Bool
+all predicate ba start end = loop start
+  where
+    loop !i
+        | i == end                   = True
+        | predicate (primIndex ba i) = loop (i+1)
+        | otherwise                  = False
+{-# INLINE all #-}
+
+any :: PrimType ty => (ty -> Bool) -> Immutable -> Offset ty -> Offset ty -> Bool
+any predicate ba start end = loop start
+  where
+    loop !i
+        | i == end                   = False
+        | predicate (primIndex ba i) = True
+        | otherwise                  = loop (i+1)
+{-# INLINE any #-}
diff --git a/Foundation/Primitive/UArray/Base.hs b/Foundation/Primitive/UArray/Base.hs
new file mode 100644
--- /dev/null
+++ b/Foundation/Primitive/UArray/Base.hs
@@ -0,0 +1,550 @@
+{-# LANGUAGE MagicHash #-}
+{-# LANGUAGE UnboxedTuples #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE ViewPatterns #-}
+module Foundation.Primitive.UArray.Base
+    ( MUArray(..)
+    , UArray(..)
+    , MUArrayBackend(..)
+    , UArrayBackend(..)
+    -- * New mutable array creation
+    , newUnpinned
+    , newPinned
+    , newNative
+    , new
+    -- * Pinning status
+    , isPinned
+    , isMutablePinned
+    -- * Mutable array accessor
+    , unsafeRead
+    , unsafeWrite
+    -- * Freezing routines
+    , unsafeFreezeShrink
+    , unsafeFreeze
+    , unsafeThaw
+    -- * Array accessor
+    , unsafeIndex
+    , unsafeIndexer
+    , onBackend
+    , onBackendPrim
+    , onMutableBackend
+    , unsafeDewrap
+    , unsafeDewrap2
+    -- * Basic lowlevel functions
+    , empty
+    , length
+    , offset
+    , ValidRange(..)
+    , offsetsValidRange
+    , equal
+    , equalMemcmp
+    , compare
+    , copyAt
+    , unsafeCopyAtRO
+    , touch
+    -- * temporary
+    , pureST
+    ) where
+
+import           GHC.Prim
+import           GHC.Types
+import           GHC.Ptr
+import           GHC.ST
+import           Foundation.Internal.Primitive
+import           Foundation.Primitive.Monad
+import           Foundation.Primitive.Types
+import           Foundation.Internal.Base
+import qualified Foundation.Primitive.Runtime as Runtime
+import           Foundation.Internal.Proxy
+import qualified Foundation.Boot.List as List
+import           Foundation.Primitive.Types.OffsetSize
+import           Foundation.Primitive.FinalPtr
+import           Foundation.Primitive.NormalForm
+import           Foundation.Primitive.Block (MutableBlock(..), Block(..))
+import qualified Foundation.Primitive.Block as BLK
+import qualified Foundation.Primitive.Block.Base as BLK (touch)
+import qualified Foundation.Primitive.Block.Mutable as MBLK
+import           Foundation.Numerical
+import           Foundation.System.Bindings.Hs
+import           Foreign.C.Types
+import           System.IO.Unsafe (unsafeDupablePerformIO)
+
+-- | A Mutable array of types built on top of GHC primitive.
+--
+-- Element in this array can be modified in place.
+data MUArray ty st = MUArray {-# UNPACK #-} !(Offset ty)
+                             {-# UNPACK #-} !(CountOf ty)
+                                            !(MUArrayBackend ty st)
+
+data MUArrayBackend ty st = MUArrayMBA (MutableBlock ty st) | MUArrayAddr (FinalPtr ty)
+
+
+-- | An array of type built on top of GHC primitive.
+--
+-- The elements need to have fixed sized and the representation is a
+-- packed contiguous array in memory that can easily be passed
+-- to foreign interface
+data UArray ty = UArray {-# UNPACK #-} !(Offset ty)
+                        {-# UNPACK #-} !(CountOf ty)
+                                       !(UArrayBackend ty)
+    deriving (Typeable)
+
+data UArrayBackend ty = UArrayBA !(Block ty) | UArrayAddr !(FinalPtr ty)
+    deriving (Typeable)
+
+instance Data ty => Data (UArray ty) where
+    dataTypeOf _ = arrayType
+    toConstr _   = error "toConstr"
+    gunfold _ _  = error "gunfold"
+
+arrayType :: DataType
+arrayType = mkNoRepType "Foundation.UArray"
+
+instance NormalForm (UArray ty) where
+    toNormalForm (UArray _ _ !_) = ()
+instance (PrimType ty, Show ty) => Show (UArray ty) where
+    show v = show (toList v)
+instance (PrimType ty, Eq ty) => Eq (UArray ty) where
+    (==) = equal
+instance (PrimType ty, Ord ty) => Ord (UArray ty) where
+    {-# SPECIALIZE instance Ord (UArray Word8) #-}
+    compare = vCompare
+
+instance PrimType ty => Monoid (UArray ty) where
+    mempty  = empty
+    mappend = append
+    mconcat = concat
+
+instance PrimType ty => IsList (UArray ty) where
+    type Item (UArray ty) = ty
+    fromList = vFromList
+    toList = vToList
+
+length :: UArray ty -> CountOf ty
+length (UArray _ len _) = len
+{-# INLINE[1] length #-}
+
+offset :: UArray ty -> Offset ty
+offset (UArray ofs _ _) = ofs
+{-# INLINE[1] offset #-}
+
+data ValidRange ty = ValidRange {-# UNPACK #-} !(Offset ty) {-# UNPACK #-} !(Offset ty)
+
+offsetsValidRange :: UArray ty -> ValidRange ty
+offsetsValidRange (UArray ofs len _) = ValidRange ofs (ofs `offsetPlusE` len)
+
+-- | Return if the array is pinned in memory
+--
+-- note that Foreign array are considered pinned
+isPinned :: UArray ty -> PinnedStatus
+isPinned (UArray _ _ (UArrayAddr {})) = Pinned
+isPinned (UArray _ _ (UArrayBA blk))  = BLK.isPinned blk
+
+-- | Return if a mutable array is pinned in memory
+isMutablePinned :: MUArray ty st -> PinnedStatus
+isMutablePinned (MUArray _ _ (MUArrayAddr {})) = Pinned
+isMutablePinned (MUArray _ _ (MUArrayMBA mb))  = BLK.isMutablePinned mb
+
+-- | Create a new pinned mutable array of size @n.
+--
+-- all the cells are uninitialized and could contains invalid values.
+--
+-- All mutable arrays are allocated on a 64 bits aligned addresses
+newPinned :: forall prim ty . (PrimMonad prim, PrimType ty) => CountOf ty -> prim (MUArray ty (PrimState prim))
+newPinned n = MUArray 0 n . MUArrayMBA <$> MBLK.newPinned n
+
+newUnpinned :: forall prim ty . (PrimMonad prim, PrimType ty) => CountOf ty -> prim (MUArray ty (PrimState prim))
+newUnpinned n = MUArray 0 n . MUArrayMBA <$> MBLK.new n
+
+newNative :: (PrimMonad prim, PrimType ty)
+          => CountOf ty
+          -> (MutableByteArray# (PrimState prim) -> prim a) -- ^ move to a MutableBlock
+          -> prim (a, MUArray ty (PrimState prim))
+newNative n f = do
+    mb@(MutableBlock mba) <- MBLK.new n
+    a <- f mba
+    pure (a, MUArray 0 n (MUArrayMBA mb))
+
+-- | Create a new mutable array of size @n.
+--
+-- When memory for a new array is allocated, we decide if that memory region
+-- should be pinned (will not be copied around by GC) or unpinned (can be
+-- moved around by GC) depending on its size.
+--
+-- You can change the threshold value used by setting the environment variable
+-- @HS_FOUNDATION_UARRAY_UNPINNED_MAX@.
+new :: (PrimMonad prim, PrimType ty) => CountOf ty -> prim (MUArray ty (PrimState prim))
+new sz
+    | sizeRecast sz <= maxSizeUnpinned = newUnpinned sz
+    | otherwise                        = newPinned sz
+  where
+    -- Safe to use here: If the value changes during runtime, this will only
+    -- have an impact on newly created arrays.
+    maxSizeUnpinned = Runtime.unsafeUArrayUnpinnedMaxSize
+{-# INLINE new #-}
+
+-- | read from a cell in a mutable array without bounds checking.
+--
+-- Reading from invalid memory can return unpredictable and invalid values.
+-- use 'read' if unsure.
+unsafeRead :: (PrimMonad prim, PrimType ty) => MUArray ty (PrimState prim) -> Offset ty -> prim ty
+unsafeRead (MUArray start _ (MUArrayMBA (MutableBlock mba))) i = primMbaRead mba (start + i)
+unsafeRead (MUArray start _ (MUArrayAddr fptr)) i = withFinalPtr fptr $ \(Ptr addr) -> primAddrRead addr (start + i)
+{-# INLINE unsafeRead #-}
+
+
+-- | write to a cell in a mutable array without bounds checking.
+--
+-- Writing with invalid bounds will corrupt memory and your program will
+-- become unreliable. use 'write' if unsure.
+unsafeWrite :: (PrimMonad prim, PrimType ty) => MUArray ty (PrimState prim) -> Offset ty -> ty -> prim ()
+unsafeWrite (MUArray start _ (MUArrayMBA mb)) i v = MBLK.unsafeWrite mb (start+i) v
+unsafeWrite (MUArray start _ (MUArrayAddr fptr)) i v = withFinalPtr fptr $ \(Ptr addr) -> primAddrWrite addr (start+i) v
+{-# INLINE unsafeWrite #-}
+
+-- | Return the element at a specific index from an array without bounds checking.
+--
+-- Reading from invalid memory can return unpredictable and invalid values.
+-- use 'index' if unsure.
+unsafeIndex :: forall ty . PrimType ty => UArray ty -> Offset ty -> ty
+unsafeIndex (UArray start _ (UArrayBA ba)) n = BLK.unsafeIndex ba (start + n)
+unsafeIndex (UArray start _ (UArrayAddr fptr)) n = withUnsafeFinalPtr fptr (\(Ptr addr) -> return (primAddrIndex addr (start+n)) :: IO ty)
+{-# INLINE unsafeIndex #-}
+
+unsafeIndexer :: (PrimMonad prim, PrimType ty) => UArray ty -> ((Offset ty -> ty) -> prim a) -> prim a
+unsafeIndexer (UArray start _ (UArrayBA ba)) f = f (\n -> BLK.unsafeIndex ba (start + n))
+unsafeIndexer (UArray start _ (UArrayAddr fptr)) f = withFinalPtr fptr $ \(Ptr addr) -> f (\n -> primAddrIndex addr (start + n))
+{-# INLINE unsafeIndexer #-}
+
+-- | Freeze a mutable array into an array.
+--
+-- the MUArray must not be changed after freezing.
+unsafeFreeze :: PrimMonad prim => MUArray ty (PrimState prim) -> prim (UArray ty)
+unsafeFreeze (MUArray start len (MUArrayMBA mba)) =
+    UArray start len . UArrayBA <$> MBLK.unsafeFreeze mba
+unsafeFreeze (MUArray start len (MUArrayAddr fptr)) =
+    pure $ UArray start len (UArrayAddr fptr)
+{-# INLINE unsafeFreeze #-}
+
+unsafeFreezeShrink :: (PrimType ty, PrimMonad prim) => MUArray ty (PrimState prim) -> CountOf ty -> prim (UArray ty)
+unsafeFreezeShrink (MUArray start _ backend) n = unsafeFreeze (MUArray start n backend)
+{-# INLINE unsafeFreezeShrink #-}
+
+-- | Thaw an immutable array.
+--
+-- The UArray must not be used after thawing.
+unsafeThaw :: (PrimType ty, PrimMonad prim) => UArray ty -> prim (MUArray ty (PrimState prim))
+unsafeThaw (UArray start len (UArrayBA blk)) = MUArray start len . MUArrayMBA <$> BLK.unsafeThaw blk
+unsafeThaw (UArray start len (UArrayAddr fptr)) = pure $ MUArray start len (MUArrayAddr fptr)
+{-# INLINE unsafeThaw #-}
+
+onBackend :: (ByteArray# -> a)
+          -> (FinalPtr ty -> Ptr ty -> ST s a)
+          -> UArray ty
+          -> a
+onBackend onBa _      (UArray _ _ (UArrayBA (Block ba))) = onBa ba
+onBackend _    onAddr (UArray _ _ (UArrayAddr fptr))     = withUnsafeFinalPtr fptr (onAddr fptr)
+{-# INLINE onBackend #-}
+
+onBackendPrim :: PrimMonad prim
+              => (ByteArray# -> prim a)
+              -> (FinalPtr ty -> prim a)
+              -> UArray ty
+              -> prim a
+onBackendPrim onBa _      (UArray _ _ (UArrayBA (Block ba))) = onBa ba
+onBackendPrim _    onAddr (UArray _ _ (UArrayAddr fptr))     = onAddr fptr
+{-# INLINE onBackendPrim #-}
+
+onMutableBackend :: PrimMonad prim
+                 => (MutableByteArray# (PrimState prim) -> prim a)
+                 -> (FinalPtr ty -> prim a)
+                 -> MUArray ty (PrimState prim)
+                 -> prim a
+onMutableBackend onMba _      (MUArray _ _ (MUArrayMBA (MutableBlock mba)))   = onMba mba
+onMutableBackend _     onAddr (MUArray _ _ (MUArrayAddr fptr)) = onAddr fptr
+{-# INLINE onMutableBackend #-}
+
+
+unsafeDewrap :: (ByteArray# -> Offset ty -> a)
+             -> (Ptr ty -> Offset ty -> ST s a)
+             -> UArray ty
+             -> a
+unsafeDewrap _ g (UArray start _ (UArrayAddr fptr))     = withUnsafeFinalPtr fptr $ \ptr -> g ptr start
+unsafeDewrap f _ (UArray start _ (UArrayBA (Block ba))) = f ba start
+{-# INLINE unsafeDewrap #-}
+
+unsafeDewrap2 :: (ByteArray# -> ByteArray# -> a)
+              -> (Ptr ty -> Ptr ty -> ST s a)
+              -> (ByteArray# -> Ptr ty -> ST s a)
+              -> (Ptr ty -> ByteArray# -> ST s a)
+              -> UArray ty
+              -> UArray ty
+              -> a
+unsafeDewrap2 f g h i (UArray _ _ back1) (UArray _ _ back2) =
+    case (back1, back2) of
+        (UArrayBA (Block ba1), UArrayBA (Block ba2)) -> f ba1 ba2
+        (UArrayAddr fptr1, UArrayAddr fptr2)         -> withUnsafeFinalPtr fptr1 $ \ptr1 -> withFinalPtr fptr2 $ \ptr2 -> g ptr1 ptr2
+        (UArrayBA (Block ba1), UArrayAddr fptr2)     -> withUnsafeFinalPtr fptr2 $ \ptr2 -> h ba1 ptr2
+        (UArrayAddr fptr1, UArrayBA (Block ba2))     -> withUnsafeFinalPtr fptr1 $ \ptr1 -> i ptr1 ba2
+{-# INLINE [2] unsafeDewrap2 #-}
+
+pureST :: a -> ST s a
+pureST = pure
+
+-- | make an array from a list of elements.
+vFromList :: PrimType ty => [ty] -> UArray ty
+vFromList l = runST $ do
+    ma <- new (CountOf len)
+    iter azero l $ \i x -> unsafeWrite ma i x
+    unsafeFreeze ma
+  where len = List.length l
+        iter _  []     _ = return ()
+        iter !i (x:xs) z = z i x >> iter (i+1) xs z
+
+-- | transform an array to a list.
+vToList :: forall ty . PrimType ty => UArray ty -> [ty]
+vToList a
+    | len == 0  = []
+    | otherwise = unsafeDewrap goBa goPtr a
+  where
+    !len = length a
+    goBa ba start = loop start
+      where
+        !end = start `offsetPlusE` len
+        loop !i | i == end  = []
+                | otherwise = primBaIndex ba i : loop (i+1)
+    goPtr (Ptr addr) start = pureST (loop start)
+      where
+        !end = start `offsetPlusE` len
+        loop !i | i == end  = []
+                | otherwise = primAddrIndex addr i : loop (i+1)
+
+-- | Check if two vectors are identical
+equal :: (PrimType ty, Eq ty) => UArray ty -> UArray ty -> Bool
+equal a b
+    | la /= lb  = False
+    | otherwise = unsafeDewrap2 goBaBa goPtrPtr goBaPtr goPtrBa a b
+  where
+    !start1 = offset a
+    !start2 = offset b
+    !end = start1 `offsetPlusE` la
+    !la = length a
+    !lb = length b
+    goBaBa ba1 ba2 = loop start1 start2
+      where
+        loop !i !o | i == end  = True
+                   | otherwise = primBaIndex ba1 i == primBaIndex ba2 o && loop (i+o1) (o+o1)
+    goPtrPtr (Ptr addr1) (Ptr addr2) = pureST (loop start1 start2)
+      where
+        loop !i !o | i == end  = True
+                   | otherwise = primAddrIndex addr1 i == primAddrIndex addr2 o && loop (i+o1) (o+o1)
+    goBaPtr ba1 (Ptr addr2) = pureST (loop start1 start2)
+      where
+        loop !i !o | i == end  = True
+                   | otherwise = primBaIndex ba1 i == primAddrIndex addr2 o && loop (i+o1) (o+o1)
+    goPtrBa (Ptr addr1) ba2 = pureST (loop start1 start2)
+      where
+        loop !i !o | i == end  = True
+                   | otherwise = primAddrIndex addr1 i == primBaIndex ba2 o && loop (i+o1) (o+o1)
+
+    o1 = Offset (I# 1#)
+{-# RULES "UArray/Eq/Word8" [3] equal = equalBytes #-}
+{-# INLINEABLE [2] equal #-}
+
+equalBytes :: UArray Word8 -> UArray Word8 -> Bool
+equalBytes a b
+    | la /= lb  = False
+    | otherwise = memcmp a b (sizeInBytes la) == 0
+  where
+    !la = length a
+    !lb = length b
+
+equalMemcmp :: PrimType ty => UArray ty -> UArray ty -> Bool
+equalMemcmp a b
+    | la /= lb  = False
+    | otherwise = memcmp a b (sizeInBytes la) == 0
+  where
+    !la = length a
+    !lb = length b
+
+-- | Compare 2 vectors
+vCompare :: (Ord ty, PrimType ty) => UArray ty -> UArray ty -> Ordering
+vCompare a@(UArray start1 la _) b@(UArray start2 lb _) = unsafeDewrap2 goBaBa goPtrPtr goBaPtr goPtrBa a b
+  where
+    !end = start1 `offsetPlusE` min la lb
+    o1 = Offset (I# 1#)
+    goBaBa ba1 ba2 = loop start1 start2
+      where
+        loop !i !o | i == end   = la `compare` lb
+                   | v1 == v2   = loop (i + o1) (o + o1)
+                   | otherwise  = v1 `compare` v2
+          where v1 = primBaIndex ba1 i
+                v2 = primBaIndex ba2 o
+    goPtrPtr (Ptr addr1) (Ptr addr2) = pureST (loop start1 start2)
+      where
+        loop !i !o | i == end   = la `compare` lb
+                   | v1 == v2   = loop (i + o1) (o + o1)
+                   | otherwise  = v1 `compare` v2
+          where v1 = primAddrIndex addr1 i
+                v2 = primAddrIndex addr2 o
+    goBaPtr ba1 (Ptr addr2) = pureST (loop start1 start2)
+      where
+        loop !i !o | i == end   = la `compare` lb
+                   | v1 == v2   = loop (i + o1) (o + o1)
+                   | otherwise  = v1 `compare` v2
+          where v1 = primBaIndex ba1 i
+                v2 = primAddrIndex addr2 o
+    goPtrBa (Ptr addr1) ba2 = pureST (loop start1 start2)
+      where
+        loop !i !o | i == end   = la `compare` lb
+                   | v1 == v2   = loop (i + o1) (o + o1)
+                   | otherwise  = v1 `compare` v2
+          where v1 = primAddrIndex addr1 i
+                v2 = primBaIndex ba2 o
+-- {-# SPECIALIZE [3] vCompare :: UArray Word8 -> UArray Word8 -> Ordering = vCompareBytes #-}
+{-# RULES "UArray/Ord/Word8" [3] vCompare = vCompareBytes #-}
+{-# INLINEABLE [2] vCompare #-}
+
+vCompareBytes :: UArray Word8 -> UArray Word8 -> Ordering
+vCompareBytes = vCompareMemcmp
+
+vCompareMemcmp :: (Ord ty, PrimType ty) => UArray ty -> UArray ty -> Ordering
+vCompareMemcmp a b = cintToOrdering $ memcmp a b sz
+  where
+    la = length a
+    lb = length b
+    sz = sizeInBytes $ min la lb
+    cintToOrdering :: CInt -> Ordering
+    cintToOrdering 0 = la `compare` lb
+    cintToOrdering r | r < 0     = LT
+                     | otherwise = GT
+{-# SPECIALIZE [3] vCompareMemcmp :: UArray Word8 -> UArray Word8 -> Ordering #-}
+
+memcmp :: PrimType ty => UArray ty -> UArray ty -> CountOf Word8 -> CInt
+memcmp a@(UArray (offsetInBytes -> o1) _ _) b@(UArray (offsetInBytes -> o2) _ _) sz = unsafeDewrap2
+    (\s1 s2 -> unsafeDupablePerformIO $ sysHsMemcmpBaBa s1 o1 s2 o2 sz)
+    (\s1 s2 -> unsafePrimToST $ sysHsMemcmpPtrPtr s1 o1 s2 o2 sz)
+    (\s1 s2 -> unsafePrimToST $ sysHsMemcmpBaPtr s1 o1 s2 o2 sz)
+    (\s1 s2 -> unsafePrimToST $ sysHsMemcmpPtrBa s1 o1 s2 o2 sz)
+    a b
+{-# SPECIALIZE [3] memcmp :: UArray Word8 -> UArray Word8 -> CountOf Word8 -> CInt #-}
+
+-- | Copy a number of elements from an array to another array with offsets
+copyAt :: forall prim ty . (PrimMonad prim, PrimType ty)
+       => MUArray ty (PrimState prim) -- ^ destination array
+       -> Offset ty                  -- ^ offset at destination
+       -> MUArray ty (PrimState prim) -- ^ source array
+       -> Offset ty                  -- ^ offset at source
+       -> CountOf ty                    -- ^ number of elements to copy
+       -> prim ()
+copyAt (MUArray dstStart _ (MUArrayMBA (MutableBlock dstMba))) ed (MUArray srcStart _ (MUArrayMBA (MutableBlock srcBa))) es n =
+    primitive $ \st -> (# copyMutableByteArray# srcBa os dstMba od nBytes st, () #)
+  where
+    !sz                 = primSizeInBytes (Proxy :: Proxy ty)
+    !(Offset (I# os))   = offsetOfE sz (srcStart + es)
+    !(Offset (I# od))   = offsetOfE sz (dstStart + ed)
+    !(CountOf (I# nBytes)) = sizeOfE sz n
+copyAt (MUArray dstStart _ (MUArrayMBA (MutableBlock dstMba))) ed (MUArray srcStart _ (MUArrayAddr srcFptr)) es n =
+    withFinalPtr srcFptr $ \srcPtr ->
+        let !(Ptr srcAddr) = srcPtr `plusPtr` os
+         in primitive $ \s -> (# compatCopyAddrToByteArray# srcAddr dstMba od nBytes s, () #)
+  where
+    !sz                 = primSizeInBytes (Proxy :: Proxy ty)
+    !(Offset os)        = offsetOfE sz (srcStart + es)
+    !(Offset (I# od))   = offsetOfE sz (dstStart + ed)
+    !(CountOf (I# nBytes)) = sizeOfE sz n
+copyAt dst od src os n = loop od os
+  where
+    !endIndex = os `offsetPlusE` n
+    loop !d !i
+        | i == endIndex = return ()
+        | otherwise     = unsafeRead src i >>= unsafeWrite dst d >> loop (d+1) (i+1)
+
+-- TODO Optimise with copyByteArray#
+-- | Copy @n@ sequential elements from the specified offset in a source array
+--   to the specified position in a destination array.
+--
+--   This function does not check bounds. Accessing invalid memory can return
+--   unpredictable and invalid values.
+unsafeCopyAtRO :: forall prim ty . (PrimMonad prim, PrimType ty)
+               => MUArray ty (PrimState prim) -- ^ destination array
+               -> Offset ty                   -- ^ offset at destination
+               -> UArray ty                   -- ^ source array
+               -> Offset ty                   -- ^ offset at source
+               -> CountOf ty                     -- ^ number of elements to copy
+               -> prim ()
+unsafeCopyAtRO (MUArray dstStart _ (MUArrayMBA (MutableBlock dstMba))) ed (UArray srcStart _ (UArrayBA (Block srcBa))) es n =
+    primitive $ \st -> (# copyByteArray# srcBa os dstMba od nBytes st, () #)
+  where
+    sz = primSizeInBytes (Proxy :: Proxy ty)
+    !(Offset (I# os))   = offsetOfE sz (srcStart+es)
+    !(Offset (I# od))   = offsetOfE sz (dstStart+ed)
+    !(CountOf (I# nBytes)) = sizeOfE sz n
+unsafeCopyAtRO (MUArray dstStart _ (MUArrayMBA (MutableBlock dstMba))) ed (UArray srcStart _ (UArrayAddr srcFptr)) es n =
+    withFinalPtr srcFptr $ \srcPtr ->
+        let !(Ptr srcAddr) = srcPtr `plusPtr` os
+         in primitive $ \s -> (# compatCopyAddrToByteArray# srcAddr dstMba od nBytes s, () #)
+  where
+    sz  = primSizeInBytes (Proxy :: Proxy ty)
+    !(Offset os)        = offsetOfE sz (srcStart+es)
+    !(Offset (I# od))   = offsetOfE sz (dstStart+ed)
+    !(CountOf (I# nBytes)) = sizeOfE sz n
+unsafeCopyAtRO dst od src os n = loop od os
+  where
+    !endIndex = os `offsetPlusE` n
+    loop d i
+        | i == endIndex = return ()
+        | otherwise     = unsafeWrite dst d (unsafeIndex src i) >> loop (d+1) (i+1)
+
+empty_ :: Block ()
+empty_ = runST $ primitive $ \s1 ->
+    case newByteArray# 0# s1           of { (# s2, mba #) ->
+    case unsafeFreezeByteArray# mba s2 of { (# s3, ba  #) ->
+        (# s3, Block ba #) }}
+
+empty :: UArray ty
+empty = UArray 0 0 (UArrayBA $ Block ba) where !(Block ba) = empty_
+
+-- | Append 2 arrays together by creating a new bigger array
+append :: PrimType ty => UArray ty -> UArray ty -> UArray ty
+append a b
+    | la == azero = b
+    | lb == azero = a
+    | otherwise = runST $ do
+        r  <- new (la+lb)
+        ma <- unsafeThaw a
+        mb <- unsafeThaw b
+        copyAt r (Offset 0) ma (Offset 0) la
+        copyAt r (sizeAsOffset la) mb (Offset 0) lb
+        unsafeFreeze r
+  where
+    !la = length a
+    !lb = length b
+
+concat :: PrimType ty => [UArray ty] -> UArray ty
+concat [] = empty
+concat l  =
+    case filterAndSum (CountOf 0) [] l of
+        (_,[])            -> empty
+        (_,[x])           -> x
+        (totalLen,chunks) -> runST $ do
+            r <- new totalLen
+            doCopy r (Offset 0) chunks
+            unsafeFreeze r
+  where
+    -- TODO would go faster not to reverse but pack from the end instead
+    filterAndSum !totalLen acc []     = (totalLen, List.reverse acc)
+    filterAndSum !totalLen acc (x:xs)
+        | len == CountOf 0 = filterAndSum totalLen acc xs
+        | otherwise      = filterAndSum (len+totalLen) (x:acc) xs
+      where len = length x
+
+    doCopy _ _ []     = return ()
+    doCopy r i (x:xs) = do
+        unsafeCopyAtRO r i x (Offset 0) lx
+        doCopy r (i `offsetPlusE` lx) xs
+      where lx = length x
+
+touch :: PrimMonad prim => UArray ty -> prim ()
+touch (UArray _ _ (UArrayBA blk))    = BLK.touch blk
+touch (UArray _ _ (UArrayAddr fptr)) = touchFinalPtr fptr
diff --git a/Foundation/Primitive/UTF8/Addr.hs b/Foundation/Primitive/UTF8/Addr.hs
--- a/Foundation/Primitive/UTF8/Addr.hs
+++ b/Foundation/Primitive/UTF8/Addr.hs
@@ -1,7 +1,6 @@
 {-# LANGUAGE BangPatterns               #-}
 {-# LANGUAGE MagicHash                  #-}
 {-# LANGUAGE TypeFamilies               #-}
-{-# LANGUAGE UnboxedTuples              #-}
 {-# LANGUAGE FlexibleContexts           #-}
 {-# LANGUAGE CPP                        #-}
 module Foundation.Primitive.UTF8.Addr
@@ -15,8 +14,14 @@
     , prev
     , prevSkip
     , write
+    , toList
+    , all
+    , any
+    , foldr
+    , length
     -- temporary
     , primIndex
+    , primIndex64
     , primRead
     , primWrite
     ) where
@@ -25,15 +30,17 @@
 import           GHC.Types
 import           GHC.Word
 import           GHC.Prim
-import           Foundation.Internal.Base
+import           Data.Bits
+import           Foundation.Internal.Base hiding (toList)
 import           Foundation.Internal.Primitive
+import           Foundation.Internal.Proxy
 import           Foundation.Numerical
 import           Foundation.Primitive.Types.OffsetSize
 import           Foundation.Primitive.Monad
 import           Foundation.Primitive.Types
 import           Foundation.Primitive.UTF8.Helper
 import           Foundation.Primitive.UTF8.Table
-import           Foundation.Bits
+import           Foundation.Primitive.UTF8.Types
 
 type Immutable = Addr#
 type Mutable (prim :: * -> *) = Addr#
@@ -47,33 +54,34 @@
 primIndex :: Immutable -> Offset Word8 -> Word8
 primIndex = primAddrIndex
 
+primIndex64 :: Immutable -> Offset Word64 -> Word64
+primIndex64 = primAddrIndex
 
-nextAscii :: Immutable -> Offset Word8 -> (# Word8, Bool #)
-nextAscii ba n = (# w, not (testBit w 7) #)
+nextAscii :: Immutable -> Offset Word8 -> StepASCII
+nextAscii ba n = StepASCII w
   where
     !w = primIndex ba n
 {-# INLINE nextAscii #-}
 
 -- | nextAsciiBa specialized to get a digit between 0 and 9 (included)
-nextAsciiDigit :: Immutable -> Offset Word8 -> (# Word8, Bool #)
-nextAsciiDigit ba n = (# d, d < 0xa #)
-  where !d = primIndex ba n - 0x30
+nextAsciiDigit :: Immutable -> Offset Word8 -> StepDigit
+nextAsciiDigit ba n = StepDigit (primIndex ba n - 0x30)
 {-# INLINE nextAsciiDigit #-}
 
 expectAscii :: Immutable -> Offset Word8 -> Word8 -> Bool
 expectAscii ba n v = primIndex ba n == v
 {-# INLINE expectAscii #-}
 
-next :: Immutable -> Offset8 -> (# Char, Offset8 #)
+next :: Immutable -> Offset8 -> Step
 next ba n =
     case getNbBytes h of
-        0 -> (# toChar1 h, n + Offset 1 #)
-        1 -> (# toChar2 h (primIndex ba (n + Offset 1)) , n + Offset 2 #)
-        2 -> (# toChar3 h (primIndex ba (n + Offset 1))
-                          (primIndex ba (n + Offset 2)) , n + Offset 3 #)
-        3 -> (# toChar4 h (primIndex ba (n + Offset 1))
-                          (primIndex ba (n + Offset 2))
-                          (primIndex ba (n + Offset 3)) , n + Offset 4 #)
+        0 -> Step (toChar1 h) (n + Offset 1)
+        1 -> Step (toChar2 h (primIndex ba (n + Offset 1))) (n + Offset 2)
+        2 -> Step (toChar3 h (primIndex ba (n + Offset 1))
+                             (primIndex ba (n + Offset 2))) (n + Offset 3)
+        3 -> Step (toChar4 h (primIndex ba (n + Offset 1))
+                             (primIndex ba (n + Offset 2))
+                             (primIndex ba (n + Offset 3))) (n + Offset 4)
         r -> error ("next: internal error: invalid input: offset=" <> show n <> " table=" <> show r <> " h=" <> show h)
   where
     !h = primIndex ba n
@@ -81,11 +89,11 @@
 
 -- Given a non null offset, give the previous character and the offset of this character
 -- will fail bad if apply at the beginning of string or an empty string.
-prev :: Immutable -> Offset Word8 -> (# Char, Offset8 #)
+prev :: Immutable -> Offset Word8 -> StepBack
 prev ba offset =
     case primIndex ba prevOfs1 of
         (W8# v1) | isContinuation# v1 -> atLeast2 (maskContinuation# v1)
-                 | otherwise          -> (# toChar# v1, prevOfs1 #)
+                 | otherwise          -> StepBack (toChar# v1) prevOfs1
   where
     sz1 = CountOf 1
     !prevOfs1 = offset `offsetMinusE` sz1
@@ -95,14 +103,14 @@
     atLeast2 !v  =
         case primIndex ba prevOfs2 of
             (W8# v2) | isContinuation# v2 -> atLeast3 (or# (uncheckedShiftL# (maskContinuation# v2) 6#) v)
-                     | otherwise          -> (# toChar# (or# (uncheckedShiftL# (maskHeader2# v2) 6#) v), prevOfs2 #)
+                     | otherwise          -> StepBack (toChar# (or# (uncheckedShiftL# (maskHeader2# v2) 6#) v)) prevOfs2
     atLeast3 !v =
         case primIndex ba prevOfs3 of
             (W8# v3) | isContinuation# v3 -> atLeast4 (or# (uncheckedShiftL# (maskContinuation# v3) 12#) v)
-                     | otherwise          -> (# toChar# (or# (uncheckedShiftL# (maskHeader3# v3) 12#) v), prevOfs3 #)
+                     | otherwise          -> StepBack (toChar# (or# (uncheckedShiftL# (maskHeader3# v3) 12#) v)) prevOfs3
     atLeast4 !v =
         case primIndex ba prevOfs4 of
-            (W8# v4) -> (# toChar# (or# (uncheckedShiftL# (maskHeader4# v4) 18#) v), prevOfs4 #)
+            (W8# v4) -> StepBack (toChar# (or# (uncheckedShiftL# (maskHeader4# v4) 18#) v)) prevOfs4
 
 prevSkip :: Immutable -> Offset Word8 -> Offset Word8
 prevSkip ba offset = loop (offset `offsetMinusE` sz1)
@@ -153,3 +161,84 @@
     toContinuation :: Word# -> Word#
     toContinuation w = or# (and# w 0x3f##) 0x80##
 {-# INLINE write #-}
+
+toList :: Immutable -> Offset Word8 -> Offset Word8 -> [Char]
+toList ba !start !end = loop start
+  where
+    loop !idx
+        | idx == end = []
+        | otherwise  = c : loop idx'
+      where (Step c idx') = next ba idx
+
+all :: (Char -> Bool) -> Immutable -> Offset Word8 -> Offset Word8 -> Bool
+all predicate ba start end = loop start
+  where
+    loop !idx
+        | idx == end  = True
+        | predicate c = loop idx'
+        | otherwise   = False
+      where (Step c idx') = next ba idx
+{-# INLINE all #-}
+
+any :: (Char -> Bool) -> Immutable -> Offset Word8 -> Offset Word8 -> Bool
+any predicate ba start end = loop start
+  where
+    loop !idx
+        | idx == end  = False
+        | predicate c = True
+        | otherwise   = loop idx'
+      where (Step c idx') = next ba idx
+{-# INLINE any #-}
+
+foldr :: Immutable -> Offset Word8 -> Offset Word8 -> (Char -> a -> a) -> a -> a
+foldr dat start end f acc = loop start
+  where
+    loop !i
+        | i == end  = acc
+        | otherwise =
+            let (Step c i') = next dat i
+             in c `f` loop i'
+{-# INLINE foldr #-}
+
+length :: Immutable -> Offset Word8 -> Offset Word8 -> CountOf Char
+length dat start end
+    | start == end = 0
+    | otherwise    = processStart 0 start
+  where
+    end64 :: Offset Word64
+    end64 = offsetInElements end
+
+    prx64 :: Proxy Word64
+    prx64 = Proxy
+
+    mask64_80 :: Word64
+    mask64_80 = 0x8080808080808080
+
+    processStart :: CountOf Char -> Offset Word8 -> CountOf Char
+    processStart !c !i
+        | i == end                = c
+        | offsetIsAligned prx64 i = processAligned c (offsetInElements i)
+        | otherwise               =
+            let h    = primIndex dat i
+                cont = (h .&. 0xc0) == 0x80
+                c'   = if cont then c else c+1
+             in processStart c' (i+1)
+    processAligned :: CountOf Char -> Offset Word64 -> CountOf Char
+    processAligned !c !i
+        | i >= end64 = processEnd c (offsetInBytes i)
+        | otherwise  =
+            let !h   = primIndex64 dat i
+                !h80 = h .&. mask64_80
+             in if h80 == 0
+                 then processAligned (c+8) (i+1)
+                 else let !nbAscii = if h80 == mask64_80 then 0 else CountOf (8 - popCount h80)
+                          !nbHigh  = CountOf $ popCount (h .&. (h80 `unsafeShiftR` 1))
+                       in processAligned (c + nbAscii + nbHigh) (i+1)
+    processEnd !c !i
+        | i == end  = c
+        | otherwise =
+            let h    = primIndex dat i
+                cont = (h .&. 0xc0) == 0x80
+                c'   = if cont then c else c+1
+             in processStart c' (i+1)
+{-# INLINE length #-}
diff --git a/Foundation/Primitive/UTF8/BA.hs b/Foundation/Primitive/UTF8/BA.hs
--- a/Foundation/Primitive/UTF8/BA.hs
+++ b/Foundation/Primitive/UTF8/BA.hs
@@ -1,7 +1,6 @@
 {-# LANGUAGE BangPatterns               #-}
 {-# LANGUAGE MagicHash                  #-}
 {-# LANGUAGE TypeFamilies               #-}
-{-# LANGUAGE UnboxedTuples              #-}
 {-# LANGUAGE FlexibleContexts           #-}
 {-# LANGUAGE CPP                        #-}
 module Foundation.Primitive.UTF8.BA
@@ -15,8 +14,14 @@
     , prev
     , prevSkip
     , write
+    , toList
+    , all
+    , any
+    , foldr
+    , length
     -- temporary
     , primIndex
+    , primIndex64
     , primRead
     , primWrite
     ) where
@@ -25,15 +30,17 @@
 import           GHC.Types
 import           GHC.Word
 import           GHC.Prim
-import           Foundation.Internal.Base
+import           Data.Bits
+import           Foundation.Internal.Base hiding (toList)
 import           Foundation.Internal.Primitive
+import           Foundation.Internal.Proxy
 import           Foundation.Numerical
 import           Foundation.Primitive.Types.OffsetSize
 import           Foundation.Primitive.Monad
 import           Foundation.Primitive.Types
 import           Foundation.Primitive.UTF8.Helper
 import           Foundation.Primitive.UTF8.Table
-import           Foundation.Bits
+import           Foundation.Primitive.UTF8.Types
 
 type Immutable = ByteArray#
 type Mutable prim = MutableByteArray# (PrimState prim)
@@ -47,33 +54,34 @@
 primIndex :: Immutable -> Offset Word8 -> Word8
 primIndex = primBaIndex
 
+primIndex64 :: Immutable -> Offset Word64 -> Word64
+primIndex64 = primBaIndex
 
-nextAscii :: Immutable -> Offset Word8 -> (# Word8, Bool #)
-nextAscii ba n = (# w, not (testBit w 7) #)
+nextAscii :: Immutable -> Offset Word8 -> StepASCII
+nextAscii ba n = StepASCII w
   where
     !w = primIndex ba n
 {-# INLINE nextAscii #-}
 
 -- | nextAsciiBa specialized to get a digit between 0 and 9 (included)
-nextAsciiDigit :: Immutable -> Offset Word8 -> (# Word8, Bool #)
-nextAsciiDigit ba n = (# d, d < 0xa #)
-  where !d = primIndex ba n - 0x30
+nextAsciiDigit :: Immutable -> Offset Word8 -> StepDigit
+nextAsciiDigit ba n = StepDigit (primIndex ba n - 0x30)
 {-# INLINE nextAsciiDigit #-}
 
 expectAscii :: Immutable -> Offset Word8 -> Word8 -> Bool
 expectAscii ba n v = primIndex ba n == v
 {-# INLINE expectAscii #-}
 
-next :: Immutable -> Offset8 -> (# Char, Offset8 #)
+next :: Immutable -> Offset8 -> Step
 next ba n =
     case getNbBytes h of
-        0 -> (# toChar1 h, n + Offset 1 #)
-        1 -> (# toChar2 h (primIndex ba (n + Offset 1)) , n + Offset 2 #)
-        2 -> (# toChar3 h (primIndex ba (n + Offset 1))
-                          (primIndex ba (n + Offset 2)) , n + Offset 3 #)
-        3 -> (# toChar4 h (primIndex ba (n + Offset 1))
-                          (primIndex ba (n + Offset 2))
-                          (primIndex ba (n + Offset 3)) , n + Offset 4 #)
+        0 -> Step (toChar1 h) (n + Offset 1)
+        1 -> Step (toChar2 h (primIndex ba (n + Offset 1))) (n + Offset 2)
+        2 -> Step (toChar3 h (primIndex ba (n + Offset 1))
+                             (primIndex ba (n + Offset 2))) (n + Offset 3)
+        3 -> Step (toChar4 h (primIndex ba (n + Offset 1))
+                             (primIndex ba (n + Offset 2))
+                             (primIndex ba (n + Offset 3))) (n + Offset 4)
         r -> error ("next: internal error: invalid input: offset=" <> show n <> " table=" <> show r <> " h=" <> show h)
   where
     !h = primIndex ba n
@@ -81,11 +89,11 @@
 
 -- Given a non null offset, give the previous character and the offset of this character
 -- will fail bad if apply at the beginning of string or an empty string.
-prev :: Immutable -> Offset Word8 -> (# Char, Offset8 #)
+prev :: Immutable -> Offset Word8 -> StepBack
 prev ba offset =
     case primIndex ba prevOfs1 of
         (W8# v1) | isContinuation# v1 -> atLeast2 (maskContinuation# v1)
-                 | otherwise          -> (# toChar# v1, prevOfs1 #)
+                 | otherwise          -> StepBack (toChar# v1) prevOfs1
   where
     sz1 = CountOf 1
     !prevOfs1 = offset `offsetMinusE` sz1
@@ -95,14 +103,14 @@
     atLeast2 !v  =
         case primIndex ba prevOfs2 of
             (W8# v2) | isContinuation# v2 -> atLeast3 (or# (uncheckedShiftL# (maskContinuation# v2) 6#) v)
-                     | otherwise          -> (# toChar# (or# (uncheckedShiftL# (maskHeader2# v2) 6#) v), prevOfs2 #)
+                     | otherwise          -> StepBack (toChar# (or# (uncheckedShiftL# (maskHeader2# v2) 6#) v)) prevOfs2
     atLeast3 !v =
         case primIndex ba prevOfs3 of
             (W8# v3) | isContinuation# v3 -> atLeast4 (or# (uncheckedShiftL# (maskContinuation# v3) 12#) v)
-                     | otherwise          -> (# toChar# (or# (uncheckedShiftL# (maskHeader3# v3) 12#) v), prevOfs3 #)
+                     | otherwise          -> StepBack (toChar# (or# (uncheckedShiftL# (maskHeader3# v3) 12#) v)) prevOfs3
     atLeast4 !v =
         case primIndex ba prevOfs4 of
-            (W8# v4) -> (# toChar# (or# (uncheckedShiftL# (maskHeader4# v4) 18#) v), prevOfs4 #)
+            (W8# v4) -> StepBack (toChar# (or# (uncheckedShiftL# (maskHeader4# v4) 18#) v)) prevOfs4
 
 prevSkip :: Immutable -> Offset Word8 -> Offset Word8
 prevSkip ba offset = loop (offset `offsetMinusE` sz1)
@@ -153,3 +161,84 @@
     toContinuation :: Word# -> Word#
     toContinuation w = or# (and# w 0x3f##) 0x80##
 {-# INLINE write #-}
+
+toList :: Immutable -> Offset Word8 -> Offset Word8 -> [Char]
+toList ba !start !end = loop start
+  where
+    loop !idx
+        | idx == end = []
+        | otherwise  = c : loop idx'
+      where (Step c idx') = next ba idx
+
+all :: (Char -> Bool) -> Immutable -> Offset Word8 -> Offset Word8 -> Bool
+all predicate ba start end = loop start
+  where
+    loop !idx
+        | idx == end  = True
+        | predicate c = loop idx'
+        | otherwise   = False
+      where (Step c idx') = next ba idx
+{-# INLINE all #-}
+
+any :: (Char -> Bool) -> Immutable -> Offset Word8 -> Offset Word8 -> Bool
+any predicate ba start end = loop start
+  where
+    loop !idx
+        | idx == end  = False
+        | predicate c = True
+        | otherwise   = loop idx'
+      where (Step c idx') = next ba idx
+{-# INLINE any #-}
+
+foldr :: Immutable -> Offset Word8 -> Offset Word8 -> (Char -> a -> a) -> a -> a
+foldr dat start end f acc = loop start
+  where
+    loop !i
+        | i == end  = acc
+        | otherwise =
+            let (Step c i') = next dat i
+             in c `f` loop i'
+{-# INLINE foldr #-}
+
+length :: Immutable -> Offset Word8 -> Offset Word8 -> CountOf Char
+length dat start end
+    | start == end = 0
+    | otherwise    = processStart 0 start
+  where
+    end64 :: Offset Word64
+    end64 = offsetInElements end
+
+    prx64 :: Proxy Word64
+    prx64 = Proxy
+
+    mask64_80 :: Word64
+    mask64_80 = 0x8080808080808080
+
+    processStart :: CountOf Char -> Offset Word8 -> CountOf Char
+    processStart !c !i
+        | i == end                = c
+        | offsetIsAligned prx64 i = processAligned c (offsetInElements i)
+        | otherwise               =
+            let h    = primIndex dat i
+                cont = (h .&. 0xc0) == 0x80
+                c'   = if cont then c else c+1
+             in processStart c' (i+1)
+    processAligned :: CountOf Char -> Offset Word64 -> CountOf Char
+    processAligned !c !i
+        | i >= end64 = processEnd c (offsetInBytes i)
+        | otherwise  =
+            let !h   = primIndex64 dat i
+                !h80 = h .&. mask64_80
+             in if h80 == 0
+                 then processAligned (c+8) (i+1)
+                 else let !nbAscii = if h80 == mask64_80 then 0 else CountOf (8 - popCount h80)
+                          !nbHigh  = CountOf $ popCount (h .&. (h80 `unsafeShiftR` 1))
+                       in processAligned (c + nbAscii + nbHigh) (i+1)
+    processEnd !c !i
+        | i == end  = c
+        | otherwise =
+            let h    = primIndex dat i
+                cont = (h .&. 0xc0) == 0x80
+                c'   = if cont then c else c+1
+             in processStart c' (i+1)
+{-# INLINE length #-}
diff --git a/Foundation/Primitive/UTF8/Base.hs b/Foundation/Primitive/UTF8/Base.hs
--- a/Foundation/Primitive/UTF8/Base.hs
+++ b/Foundation/Primitive/UTF8/Base.hs
@@ -10,7 +10,6 @@
 {-# LANGUAGE GeneralizedNewtypeDeriving #-}
 {-# LANGUAGE MagicHash                  #-}
 {-# LANGUAGE TypeFamilies               #-}
-{-# LANGUAGE UnboxedTuples              #-}
 {-# LANGUAGE FlexibleContexts           #-}
 {-# LANGUAGE CPP                        #-}
 module Foundation.Primitive.UTF8.Base
@@ -22,13 +21,13 @@
 import           GHC.Prim
 import           Foundation.Internal.Base
 import           Foundation.Numerical
-import           Foundation.Bits
 import           Foundation.Class.Bifunctor
 import           Foundation.Primitive.NormalForm
 import           Foundation.Primitive.Types.OffsetSize
 import           Foundation.Primitive.Monad
 import           Foundation.Primitive.FinalPtr
 import           Foundation.Primitive.UTF8.Helper
+import           Foundation.Primitive.UTF8.Types
 import qualified Foundation.Primitive.UTF8.BA       as PrimBA
 import qualified Foundation.Primitive.UTF8.Addr     as PrimAddr
 import           Foundation.Array.Unboxed           (UArray)
@@ -36,6 +35,7 @@
 import qualified Foundation.Array.Unboxed           as C
 import           Foundation.Array.Unboxed.ByteArray (MutableByteArray)
 import qualified Foundation.Array.Unboxed.Mutable   as MVec
+import           Foundation.Primitive.UArray.Base   as Vec (offset, pureST, onBackend)
 import           Foundation.String.ModifiedUTF8     (fromModified)
 import           GHC.CString                        (unpackCString#, unpackCStringUtf8#)
 
@@ -90,7 +90,7 @@
     loop idx
         | idx .==# nbBytes = []
         | otherwise        =
-            let (# c , idx' #) = next s idx in c : loop idx'
+            let !(Step c idx') = next s idx in c : loop idx'
 
 {-# RULES
 "String sFromList" forall s .
@@ -119,35 +119,26 @@
         loop idx (c:xs) = write ms idx c >>= \idx' -> loop idx' xs
 {-# INLINE [0] sFromList #-}
 
-next :: String -> Offset8 -> (# Char, Offset8 #)
-next (String array) n =
-    case array of
-        Vec.UVecBA start _ _ ba   -> let (# c, o #) = PrimBA.next ba (start + n)
-                                      in (# c, o `offsetSub` start #)
-        Vec.UVecAddr start _ fptr -> unt2 $ withUnsafeFinalPtr fptr $ \(Ptr ptr) -> pureST $ t2 start (PrimAddr.next ptr (start + n))
+next :: String -> Offset8 -> Step
+next (String array) !n = Vec.onBackend nextNative nextAddr array
   where
-    pureST :: a -> ST s a
-    pureST = pure
-    unt2 (a,b) = (# a, b #)
-    t2 x (# a, b #) = (a, b `offsetSub` x)
+    !start = Vec.offset array
+    reoffset (Step a ofs) = Step a (ofs `offsetSub` start)
+    nextNative ba        = reoffset (PrimBA.next ba (start + n))
+    nextAddr _ (Ptr ptr) = pureST $ reoffset (PrimAddr.next ptr (start + n))
 
-prev :: String -> Offset8 -> (# Char, Offset8 #)
-prev (String array) n =
-    case array of
-        Vec.UVecBA start _ _ ba   -> let (# c, o #) = PrimBA.prev ba (start + n)
-                                      in (# c, o `offsetSub` start #)
-        Vec.UVecAddr start _ fptr -> unt2 $ withUnsafeFinalPtr fptr $ \(Ptr ptr) -> pureST $ t2 start (PrimAddr.prev ptr (start + n))
+prev :: String -> Offset8 -> StepBack
+prev (String array) !n = Vec.onBackend prevNative prevAddr array
   where
-    pureST :: a -> ST s a
-    pureST = pure
-    unt2 (a,b) = (# a, b #)
-    t2 x (# a, b #) = (a, b `offsetSub` x)
+    !start = Vec.offset array
+    reoffset (StepBack a ofs) = StepBack a (ofs `offsetSub` start)
+    prevNative ba        = reoffset (PrimBA.prev ba (start + n))
+    prevAddr _ (Ptr ptr) = pureST $ reoffset (PrimAddr.prev ptr (start + n))
 
 -- A variant of 'next' when you want the next character
--- to be ASCII only. if Bool is False, then it's not ascii,
--- otherwise it is and the return Word8 is valid.
-nextAscii :: String -> Offset8 -> (# Word8, Bool #)
-nextAscii (String ba) n = (# w, not (testBit w 7) #)
+-- to be ASCII only.
+nextAscii :: String -> Offset8 -> StepASCII
+nextAscii (String ba) n = StepASCII w
   where
     !w = Vec.unsafeIndex ba n
 
@@ -157,9 +148,10 @@
 
 write :: PrimMonad prim => MutableString (PrimState prim) -> Offset8 -> Char -> prim Offset8
 write (MutableString marray) ofs c =
-    case marray of
-        MVec.MUVecMA start _ _ mba  -> PrimBA.write mba (start + ofs) c
-        MVec.MUVecAddr start _ fptr -> withFinalPtr fptr $ \(Ptr ptr) -> PrimAddr.write ptr (start + ofs) c
+    MVec.onMutableBackend (\mba -> PrimBA.write mba (start + ofs) c)
+                          (\fptr -> withFinalPtr fptr $ \(Ptr ptr) -> PrimAddr.write ptr (start + ofs) c)
+                          marray
+  where start = MVec.mutableOffset marray
 
 -- | Allocate a MutableString of a specific size in bytes.
 new :: PrimMonad prim
diff --git a/Foundation/Primitive/UTF8/Helper.hs b/Foundation/Primitive/UTF8/Helper.hs
--- a/Foundation/Primitive/UTF8/Helper.hs
+++ b/Foundation/Primitive/UTF8/Helper.hs
@@ -23,15 +23,6 @@
 import           GHC.Types
 import           GHC.Word
 
--- | Possible failure related to validating bytes of UTF8 sequences.
-data ValidationFailure = InvalidHeader
-                       | InvalidContinuation
-                       | MissingByte
-                       | BuildingFailure
-                       deriving (Show,Eq,Typeable)
-
-instance Exception ValidationFailure
-
 -- mask an UTF8 continuation byte (stripping the leading 10 and returning 6 valid bits)
 maskContinuation# :: Word# -> Word#
 maskContinuation# v = and# v 0x3f##
diff --git a/Foundation/Primitive/UTF8/Types.hs b/Foundation/Primitive/UTF8/Types.hs
new file mode 100644
--- /dev/null
+++ b/Foundation/Primitive/UTF8/Types.hs
@@ -0,0 +1,50 @@
+module Foundation.Primitive.UTF8.Types
+    (
+    -- * Stepper
+      Step(..)
+    , StepBack(..)
+    , StepASCII(..)
+    , StepDigit(..)
+    , isValidStepASCII
+    , isValidStepDigit
+    -- * Unicode Errors
+    , ValidationFailure(..)
+    ) where
+
+import           Foundation.Internal.Base
+import           Foundation.Primitive.Types.OffsetSize
+
+-- | Step when walking a String
+--
+-- this is a return value composed of :
+-- * the unicode code point read (Char) which need to be
+--   between 0 and 0x10ffff (inclusive)
+-- * The next offset to start reading the next unicode code point (or end)
+data Step = Step {-# UNPACK #-} !Char {-# UNPACK #-} !(Offset Word8)
+
+-- | Similar to Step but used when processing the string from the end.
+--
+-- The stepper is thus the previous character, and the offset of
+-- the beginning of the previous character
+data StepBack = StepBack {-# UNPACK #-} !Char {-# UNPACK #-} !(Offset Word8)
+
+-- | Step when processing digits. the value is between 0 and 9 to be valid
+newtype StepDigit = StepDigit Word8
+
+-- | Step when processing ASCII character
+newtype StepASCII = StepASCII Word8
+
+isValidStepASCII :: StepASCII -> Bool
+isValidStepASCII (StepASCII w) = w < 0x80
+
+isValidStepDigit :: StepDigit -> Bool
+isValidStepDigit (StepDigit w) = w < 0xa
+
+-- | Possible failure related to validating bytes of UTF8 sequences.
+data ValidationFailure = InvalidHeader
+                       | InvalidContinuation
+                       | MissingByte
+                       | BuildingFailure
+                       deriving (Show,Eq,Typeable)
+
+instance Exception ValidationFailure
diff --git a/Foundation/Random.hs b/Foundation/Random.hs
--- a/Foundation/Random.hs
+++ b/Foundation/Random.hs
@@ -21,12 +21,13 @@
     ( MonadRandom(..)
     , MonadRandomState(..)
     , RandomGen(..)
-    , getRandomPrimType
+    -- , getRandomPrimType
     , withRandomGenerator
     , RNG
     , RNGv1
     ) where
 
+import           Foundation.Class.Storable (peek)
 import           Foundation.Internal.Base
 import           Foundation.Primitive.Types.OffsetSize
 import           Foundation.Internal.Proxy
@@ -37,13 +38,23 @@
 import qualified Foundation.Array.Unboxed.Mutable as A
 import           GHC.ST
 import qualified Prelude
+import qualified Foreign.Marshal.Alloc (alloca)
 
 -- | A monad constraint that allows to generate random bytes
 class (Functor m, Applicative m, Monad m) => MonadRandom m where
     getRandomBytes :: CountOf Word8 -> m (UArray Word8)
+    getRandomWord64 :: m Word64
+    getRandomF32 :: m Float
+    getRandomF64 :: m Double
 
 instance MonadRandom IO where
-    getRandomBytes = getEntropy
+    getRandomBytes  = getEntropy
+    getRandomWord64 = flip A.index 0 . A.unsafeRecast
+                  <$> getRandomBytes (A.primSizeInBytes (Proxy :: Proxy Word64))
+    getRandomF32 = flip A.index 0 . A.unsafeRecast
+                  <$> getRandomBytes (A.primSizeInBytes (Proxy :: Proxy Word64))
+    getRandomF64 = flip A.index 0 . A.unsafeRecast
+                  <$> getRandomBytes (A.primSizeInBytes (Proxy :: Proxy Word64))
 
 -- | A Deterministic Random Generator (DRG) class
 class RandomGen gen where
@@ -59,6 +70,13 @@
     -- | Generate N bytes of randomness from a DRG
     randomGenerate :: CountOf Word8 -> gen -> (UArray Word8, gen)
 
+    -- | Generate a Word64 from a DRG
+    randomGenerateWord64 :: gen -> (Word64, gen)
+
+    randomGenerateF32 :: gen -> (Float, gen)
+
+    randomGenerateF64 :: gen -> (Double, gen)
+
 -- | A simple Monad class very similar to a State Monad
 -- with the state being a RandomGenerator.
 newtype MonadRandomState gen a = MonadRandomState { runRandomState :: gen -> (a, gen) }
@@ -82,10 +100,10 @@
 
 instance RandomGen gen => MonadRandom (MonadRandomState gen) where
     getRandomBytes n = MonadRandomState (randomGenerate n)
+    getRandomWord64  = MonadRandomState randomGenerateWord64
+    getRandomF32  = MonadRandomState randomGenerateF32
+    getRandomF64  = MonadRandomState randomGenerateF64
 
-getRandomPrimType :: forall randomly ty . (PrimType ty, MonadRandom randomly) => randomly ty
-getRandomPrimType =
-    flip A.index 0 . A.unsafeRecast <$> getRandomBytes (A.primSizeInBytes (Proxy :: Proxy ty))
 
 -- | Run a pure computation with a Random Generator in the 'MonadRandomState'
 withRandomGenerator :: RandomGen gen
@@ -114,6 +132,9 @@
         | A.length bs == 32 = Just $ RNGv1 bs
         | otherwise         = Nothing
     randomGenerate = rngv1Generate
+    randomGenerateWord64 = rngv1GenerateWord64
+    randomGenerateF32 = rngv1GenerateF32
+    randomGenerateF64 = rngv1GenerateF64
 
 rngv1KeySize :: CountOf Word8
 rngv1KeySize = 32
@@ -130,6 +151,33 @@
     (,) <$> A.unsafeFreeze dst
         <*> (RNGv1 <$> A.unsafeFreeze newKey)
 
+rngv1GenerateWord64 :: RNGv1 -> (Word64, RNGv1)
+rngv1GenerateWord64 (RNGv1 key) = runST $ unsafePrimFromIO $
+    Foreign.Marshal.Alloc.alloca $ \dst -> do
+        newKey <- A.newPinned rngv1KeySize
+        A.withMutablePtr newKey $ \newKeyP ->
+          A.withPtr key           $ \keyP  ->
+            c_rngv1_generate_word64 newKeyP dst keyP *> return ()
+        (,) <$> peek dst <*> (RNGv1 <$> A.unsafeFreeze newKey)
+
+rngv1GenerateF32 :: RNGv1 -> (Float, RNGv1)
+rngv1GenerateF32 (RNGv1 key) = runST $ unsafePrimFromIO $
+    Foreign.Marshal.Alloc.alloca $ \dst -> do
+        newKey <- A.newPinned rngv1KeySize
+        A.withMutablePtr newKey $ \newKeyP ->
+          A.withPtr key           $ \keyP  ->
+            c_rngv1_generate_f32 newKeyP dst keyP *> return ()
+        (,) <$> peek dst <*> (RNGv1 <$> A.unsafeFreeze newKey)
+
+rngv1GenerateF64 :: RNGv1 -> (Double, RNGv1)
+rngv1GenerateF64 (RNGv1 key) = runST $ unsafePrimFromIO $
+    Foreign.Marshal.Alloc.alloca $ \dst -> do
+        newKey <- A.newPinned rngv1KeySize
+        A.withMutablePtr newKey $ \newKeyP ->
+          A.withPtr key           $ \keyP  ->
+            c_rngv1_generate_f64 newKeyP dst keyP *> return ()
+        (,) <$> peek dst <*> (RNGv1 <$> A.unsafeFreeze newKey)
+
 -- return 0 on success, !0 for failure
 foreign import ccall unsafe "foundation_rngV1_generate"
    c_rngv1_generate :: Ptr Word8 -- new key
@@ -137,3 +185,21 @@
                     -> Ptr Word8 -- current key
                     -> Word32    -- number of bytes to generate
                     -> IO Word32
+
+foreign import ccall unsafe "foundation_rngV1_generate_word64"
+   c_rngv1_generate_word64 :: Ptr Word8  -- new key
+                           -> Ptr Word64 -- destination
+                           -> Ptr Word8  -- current key
+                           -> IO Word32
+
+foreign import ccall unsafe "foundation_rngV1_generate_f32"
+   c_rngv1_generate_f32 :: Ptr Word8  -- new key
+                        -> Ptr Float -- destination
+                        -> Ptr Word8  -- current key
+                        -> IO Word32
+
+foreign import ccall unsafe "foundation_rngV1_generate_f64"
+   c_rngv1_generate_f64 :: Ptr Word8  -- new key
+                        -> Ptr Double -- destination
+                        -> Ptr Word8  -- current key
+                        -> IO Word32
diff --git a/Foundation/String.hs b/Foundation/String.hs
--- a/Foundation/String.hs
+++ b/Foundation/String.hs
@@ -37,6 +37,7 @@
     , toBase64
     , toBase64URL
     , toBase64OpenBSD
+    , breakLine
     ) where
 
 import Foundation.String.UTF8
diff --git a/Foundation/String/ASCII.hs b/Foundation/String/ASCII.hs
--- a/Foundation/String/ASCII.hs
+++ b/Foundation/String/ASCII.hs
@@ -190,7 +190,7 @@
 
 breakElem :: CUChar -> AsciiString -> (AsciiString, AsciiString)
 breakElem !el (AsciiString ba) =
-    let (# v1,v2 #) = Vec.splitElem el ba in (AsciiString v1, AsciiString v2)
+    bimap AsciiString AsciiString $ Vec.breakElem el ba
 {-# INLINE breakElem #-}
 
 intersperse :: CUChar -> AsciiString -> AsciiString
diff --git a/Foundation/String/ModifiedUTF8.hs b/Foundation/String/ModifiedUTF8.hs
--- a/Foundation/String/ModifiedUTF8.hs
+++ b/Foundation/String/ModifiedUTF8.hs
@@ -27,6 +27,7 @@
 import           Foundation.Internal.Base
 import           Foundation.Primitive.Types.OffsetSize
 import qualified Foundation.Array.Unboxed as Vec
+import qualified Foundation.Primitive.UArray.Base as Vec
 import           Foundation.Array.Unboxed (UArray)
 import           Foundation.Numerical
 import           Foundation.Primitive.FinalPtr
@@ -46,7 +47,7 @@
         | otherwise      = getAtIdx off : loop (off + 1)
 
 buildByteArray :: Addr# -> ST st (UArray Word8)
-buildByteArray addr = Vec.UVecAddr (Offset 0) (CountOf 100000) `fmap`
+buildByteArray addr = Vec.UArray (Offset 0) (CountOf 100000) . Vec.UArrayAddr <$>
     toFinalPtr (Ptr addr) (\_ -> return ())
 
 -- | assuming the given ByteArray is a valid modified UTF-8 sequence of bytes
diff --git a/Foundation/String/UTF8.hs b/Foundation/String/UTF8.hs
--- a/Foundation/String/UTF8.hs
+++ b/Foundation/String/UTF8.hs
@@ -52,6 +52,7 @@
     , span
     , break
     , breakElem
+    , breakLine
     , dropWhile
     , singleton
     , charMap
@@ -79,6 +80,10 @@
     , isPrefixOf
     , isSuffixOf
     , isInfixOf
+    , stripPrefix
+    , stripSuffix
+    , all
+    , any
     -- * Legacy utility
     , lines
     , words
@@ -108,6 +113,8 @@
 import           Foundation.Primitive.UTF8.Table
 import           Foundation.Primitive.UTF8.Helper
 import           Foundation.Primitive.UTF8.Base
+import           Foundation.Primitive.UTF8.Types
+import           Foundation.Primitive.UArray.Base as C (onBackendPrim, onBackend, offset, ValidRange(..), offsetsValidRange)
 import qualified Foundation.Primitive.UTF8.BA as PrimBA
 import qualified Foundation.Primitive.UTF8.Addr as PrimAddr
 import qualified Foundation.String.UTF8.BA as BackendBA
@@ -411,7 +418,7 @@
     loop prevIdx idx
         | idx == end = [sub s prevIdx idx]
         | otherwise =
-            let (# c, idx' #) = next s idx
+            let !(Step c idx') = next s idx
              in if predicate c
                     then sub s prevIdx idx : loop idx' idx'
                     else loop prevIdx idx'
@@ -464,7 +471,7 @@
     | sz == 0   = (mempty, mempty)
     | otherwise =
         case asUTF8Char el of
-            UTF8_1 w -> let (# v1,v2 #) = Vec.splitElem w ba in (String v1, String v2)
+            UTF8_1 w -> let !(v1,v2) = Vec.breakElem w ba in (String v1, String v2)
             _        -> runST $ Vec.unsafeIndexer ba go
   where
     sz = size s
@@ -482,6 +489,15 @@
                     True  -> return $ splitIndex idx s
                     False -> loop idx'
 
+-- | Same as break but cut on a line feed with an optional carriage return.
+--
+-- This is the same operation as 'breakElem LF' dropping the last character of the
+-- string if it's a CR.
+--
+-- Also for efficiency reason (streaming), it returns if the last character was a CR character.
+breakLine :: String -> Either Bool (String, String)
+breakLine (String arr) = bimap String String <$> Vec.breakLine arr
+
 -- | Apply a @predicate@ to the string to return the longest prefix that satisfy the predicate and
 -- the remaining
 span :: (Char -> Bool) -> String -> (String, String)
@@ -540,7 +556,7 @@
             nextDstIdx' <- write dst nextDstIdx sep'
             return (nextSrcIdx, nextDstIdx')
       where
-        (# c, nextSrcIdx #) = next src' srcIdx
+        !(Step c nextSrcIdx) = next src' srcIdx
 
 -- | Allocate a new @String@ with a fill function that has access to the characters of
 --   the source @String@.
@@ -562,25 +578,13 @@
 --
 -- this size is available in o(n)
 length :: String -> CountOf Char
-length (String ba)
-    | C.null ba = CountOf 0
-    | otherwise = Vec.unsafeDewrap goVec goAddr ba
+length (String arr)
+    | start == end = 0
+    | otherwise    = C.onBackend goVec (\_ -> pure . goAddr) arr
   where
-    goVec ma start = loop start (CountOf 0)
-      where
-        !end = start `offsetPlusE` Vec.length ba
-        loop !idx !i
-            | idx >= end = i
-            | otherwise  = loop (idx `offsetPlusE` d) (i + CountOf 1)
-          where d = skipNextHeaderValue (primBaIndex ma idx)
-
-    goAddr (Ptr ptr) start = return $ loop start (CountOf 0)
-      where
-        !end = start `offsetPlusE` Vec.length ba
-        loop !idx !i
-            | idx >= end = i
-            | otherwise  = loop (idx `offsetPlusE` d) (i + CountOf 1)
-          where d = skipNextHeaderValue (primAddrIndex ptr idx)
+    (C.ValidRange !start !end) = offsetsValidRange arr
+    goVec ma = PrimBA.length ma start end
+    goAddr (Ptr ptr) = PrimAddr.length ptr start end
 
 -- | Replicate a character @c@ @n@ times to create a string of length @n@
 replicate :: CountOf Char -> Char -> String
@@ -672,7 +676,7 @@
             | srcIdx == srcEnd = return (offsetAsSize dstIdx, srcIdx)
             | dstIdx == endDst = return (offsetAsSize dstIdx, srcIdx)
             | otherwise        =
-                let (# c, srcIdx' #) = next src srcIdx
+                let !(Step c srcIdx') = next src srcIdx
                     c' = f c -- the mapped char
                     !nbBytes = charToBytes (fromEnum c')
                  in -- check if we have room in the destination buffer
@@ -721,7 +725,7 @@
 unsnoc s@(String arr)
     | sz == 0   = Nothing
     | otherwise =
-        let (# c, idx #) = prev s (sizeAsOffset sz)
+        let !(StepBack c idx) = prev s (sizeAsOffset sz)
          in Just (String $ Vec.take (offsetAsSize idx) arr, c)
   where
     sz = size s
@@ -733,7 +737,7 @@
 uncons s@(String ba)
     | null s    = Nothing
     | otherwise =
-        let (# c, idx #) = next s azero
+        let !(Step c idx) = next s azero
          in Just (c, String $ Vec.drop (offsetAsSize idx) ba)
 
 -- | Look for a predicate in the String and return the matched character, if any.
@@ -745,7 +749,7 @@
     loop idx
         | idx == end = Nothing
         | otherwise =
-            let (# c, idx' #) = next s idx
+            let !(Step c idx') = next s idx
              in case predicate c of
                     True  -> Just c
                     False -> loop idx'
@@ -760,12 +764,13 @@
 filter :: (Char -> Bool) -> String -> String
 filter predicate (String arr) = runST $ do
     (finalSize, dst) <- newNative sz $ \mba ->
-        case arr of
-            C.UVecBA start _ _ ba -> BackendBA.copyFilter predicate sz mba ba start
-            C.UVecAddr start _ fptr -> withFinalPtr fptr $ \(Ptr addr) -> BackendAddr.copyFilter predicate sz mba addr start
+        C.onBackendPrim (\ba -> BackendBA.copyFilter predicate sz mba ba start)
+                        (\fptr -> withFinalPtr fptr $ \(Ptr addr) -> BackendAddr.copyFilter predicate sz mba addr start)
+                        arr
     freezeShrink finalSize dst
   where
-    !sz = C.length arr
+    !sz    = C.length arr
+    !start = C.offset arr
 
 -- | Reverse a string
 reverse :: String -> String
@@ -818,7 +823,7 @@
 index s n
     | ofs >= end = Nothing
     | otherwise  =
-        let (# c, _ #) = next s ofs
+        let (Step !c _) = next s ofs
          in Just c
   where
     !nbBytes = size s
@@ -835,7 +840,7 @@
     loop ofs idx
         | idx .==# sz = Nothing
         | otherwise   =
-            let (# c, idx' #) = next s idx
+            let !(Step c idx') = next s idx
              in case predicate c of
                     True  -> Just ofs
                     False -> loop (ofs+1) idx'
@@ -982,9 +987,15 @@
 toBytes UTF16      (String bytes) = toEncoderBytes Encoder.UTF16      bytes
 toBytes UTF32      (String bytes) = toEncoderBytes Encoder.UTF32      bytes
 
--- | Split lines in a string using newline as separation
+-- | Split lines in a string using newline as separation.
+--
+-- Note that carriage return preceding a newline are also strip for
+-- maximum compatibility between Windows and Unix system.
 lines :: String -> [String]
-lines = fmap fromList . Prelude.lines . toList
+lines s =
+    case breakLine s of
+        Left _         -> [s]
+        Right (line,r) -> line : lines r
 
 -- | Split words in a string using spaces as separation
 --
@@ -1052,7 +1063,7 @@
 readIntegral :: (HasNegation i, IntegralUpsize Word8 i, Additive i, Multiplicative i, IsIntegral i) => String -> Maybe i
 readIntegral str
     | sz == 0   = Nothing
-    | otherwise = stringDewrap withBa withPtr str
+    | otherwise = stringDewrap withBa (\(Ptr ptr) -> pure . withPtr ptr) str
   where
     !sz = size str
     withBa ba ofs =
@@ -1062,10 +1073,10 @@
                 (# acc, True, endOfs' #) | endOfs' > startOfs -> Just $! if negativeSign then negate acc else acc
                 _                                             -> Nothing
       where !endOfs = ofs `offsetPlusE` sz
-    withPtr (Ptr ptr) ofs = return $
-        let negativeSign = PrimAddr.expectAscii ptr ofs 0x2d
+    withPtr addr ofs =
+        let negativeSign = PrimAddr.expectAscii addr ofs 0x2d
             startOfs     = if negativeSign then succ ofs else ofs
-         in case decimalDigitsPtr 0 ptr endOfs startOfs of
+         in case decimalDigitsPtr 0 addr endOfs startOfs of
                 (# acc, True, endOfs' #) | endOfs' > startOfs -> Just $! if negativeSign then negate acc else acc
                 _                                             -> Nothing
       where !endOfs = ofs `offsetPlusE` sz
@@ -1080,13 +1091,20 @@
 -- Consume many digits until end of string.
 readNatural :: String -> Maybe Natural
 readNatural str
-    | sz == 0  = Nothing
-    | otherwise =
-        case decimalDigits 0 str 0 of
-            (# acc, True, endOfs #) | endOfs > 0 -> Just acc
-            _                                    -> Nothing
+    | sz == 0   = Nothing
+    | otherwise = stringDewrap withBa (\(Ptr ptr) -> pure . withPtr ptr) str
   where
     !sz = size str
+    withBa ba stringStart =
+        case decimalDigitsBA 0 ba eofs stringStart of
+            (# acc, True, endOfs #) | endOfs > stringStart -> Just acc
+            _                                              -> Nothing
+      where eofs = stringStart `offsetPlusE` sz
+    withPtr addr stringStart =
+        case decimalDigitsPtr 0 addr eofs stringStart of
+            (# acc, True, endOfs #) | endOfs > stringStart -> Just acc
+            _                                              -> Nothing
+      where eofs = stringStart `offsetPlusE` sz
 
 -- | Try to read a Double
 readDouble :: String -> Maybe Double
@@ -1182,9 +1200,9 @@
             | otherwise        =
                 -- consume 'E' or 'e'
                 case PrimBA.nextAscii ba startOfs of
-                    (# 0x45, True #) -> consumeExponantSign (startOfs+1)
-                    (# 0x65, True #) -> consumeExponantSign (startOfs+1)
-                    (# _   , _    #) -> Nothing
+                    StepASCII 0x45 -> consumeExponantSign (startOfs+1)
+                    StepASCII 0x65 -> consumeExponantSign (startOfs+1)
+                    _              -> Nothing
           where
             consumeExponantSign ofs
                 | ofs == eofs = Nothing
@@ -1195,7 +1213,7 @@
                 case decimalDigitsBA 0 ba eofs ofs of
                     (# acc, True, endOfs #) | endOfs > ofs -> f isNegative integral floatingDigits (Just $! if exponentNegative then negate acc else acc)
                     _                                      -> Nothing
-    withPtr (Ptr ptr) stringStart = return $
+    withPtr (Ptr ptr) stringStart = pure $
         let !isNegative = PrimAddr.expectAscii ptr stringStart 0x2d
          in consumeIntegral isNegative (if isNegative then stringStart+1 else stringStart)
       where
@@ -1222,9 +1240,9 @@
             | otherwise        =
                 -- consume 'E' or 'e'
                 case PrimAddr.nextAscii ptr startOfs of
-                    (# 0x45, True #) -> consumeExponantSign (startOfs+1)
-                    (# 0x65, True #) -> consumeExponantSign (startOfs+1)
-                    (# _   , _    #) -> Nothing
+                    StepASCII 0x45 -> consumeExponantSign (startOfs+1)
+                    StepASCII 0x65 -> consumeExponantSign (startOfs+1)
+                    _              -> Nothing
           where
             consumeExponantSign ofs
                 | ofs == eofs = Nothing
@@ -1258,26 +1276,6 @@
 --
 -- If end offset == start offset then no digits have been consumed by
 -- this function
-decimalDigits :: (IntegralUpsize Word8 acc, Additive acc)
-              => acc
-              -> String
-              -> Offset Word8
-              -> (# acc, Bool, Offset Word8 #)
-decimalDigits startAcc str startOfs = loop startAcc startOfs
-  where
-    !sz = size str
-    loop acc ofs
-        | ofs .==# sz = (# acc, True, ofs #)
-        | otherwise   =
-            case nextAscii str ofs of
-                (# d, True #) | isDigit d -> loop (scale (10::Word) acc + fromDigit d) (ofs+1)
-                (# _, _ #)                -> (# acc, False, ofs #)
-    ascii0 = 0x30 -- use pattern synonym when we support >= 8.0
-    ascii9 = 0x39
-    isDigit c = c >= ascii0 && c <= ascii9
-    fromDigit c = integralUpsize (c - ascii0)
-
--- | same as decimalDigitsBA for a bytearray#
 decimalDigitsBA :: (IntegralUpsize Word8 acc, Additive acc, Multiplicative acc, Integral acc)
                 => acc
                 -> ByteArray#
@@ -1290,8 +1288,8 @@
         | ofs == endOfs = (# acc, True, ofs #)
         | otherwise     =
             case PrimBA.nextAsciiDigit ba ofs of
-                (# d, True #) -> loop (10 * acc + integralUpsize d) (succ ofs)
-                (# _, _ #)    -> (# acc, False, ofs #)
+                sg@(StepDigit d) | isValidStepDigit sg -> loop (10 * acc + integralUpsize d) (succ ofs)
+                                 | otherwise           -> (# acc, False, ofs #)
 {-# SPECIALIZE decimalDigitsBA :: Integer -> ByteArray# -> Offset Word8 -> Offset Word8 -> (# Integer, Bool, Offset Word8 #) #-}
 {-# SPECIALIZE decimalDigitsBA :: Natural -> ByteArray# -> Offset Word8 -> Offset Word8 -> (# Natural, Bool, Offset Word8 #) #-}
 {-# SPECIALIZE decimalDigitsBA :: Int -> ByteArray# -> Offset Word8 -> Offset Word8 -> (# Int, Bool, Offset Word8 #) #-}
@@ -1310,8 +1308,8 @@
         | ofs == endOfs = (# acc, True, ofs #)
         | otherwise     =
             case PrimAddr.nextAsciiDigit ptr ofs of
-                (# d, True #) -> loop (10 * acc + integralUpsize d) (succ ofs)
-                (# _, _ #)    -> (# acc, False, ofs #)
+                sg@(StepDigit d) | isValidStepDigit sg -> loop (10 * acc + integralUpsize d) (succ ofs)
+                                 | otherwise           -> (# acc, False, ofs #)
 {-# SPECIALIZE decimalDigitsPtr :: Integer -> Addr# -> Offset Word8 -> Offset Word8 -> (# Integer, Bool, Offset Word8 #) #-}
 {-# SPECIALIZE decimalDigitsPtr :: Natural -> Addr# -> Offset Word8 -> Offset Word8 -> (# Natural, Bool, Offset Word8 #) #-}
 {-# SPECIALIZE decimalDigitsPtr :: Int -> Addr# -> Offset Word8 -> Offset Word8 -> (# Int, Bool, Offset Word8 #) #-}
@@ -1329,12 +1327,7 @@
 
 -- | Check whether the first string is a prefix of the second string.
 isPrefixOf :: String -> String -> Bool
-isPrefixOf (String needle) (String haystack)
-    | needleLen > hayLen = False
-    | otherwise          = needle == C.take needleLen haystack
-  where
-    needleLen = C.length needle
-    hayLen    = C.length haystack
+isPrefixOf (String needle) (String haystack) = C.isPrefixOf needle haystack
 
 -- | Check whether the first string is a suffix of the second string.
 isSuffixOf :: String -> String -> Bool
@@ -1362,6 +1355,38 @@
         | needle == haystackSub = True
         | otherwise             = loop (i+1)
       where haystackSub = C.take needleLen $ C.drop i haystack
+
+-- | Try to strip a prefix from the start of a String.
+--
+-- If the prefix is not starting the string, then Nothing is returned,
+-- otherwise the striped string is returned
+stripPrefix :: String -> String -> Maybe String
+stripPrefix (String suffix) (String arr)
+    | C.isPrefixOf suffix arr = Just $ String $ C.drop (C.length suffix) arr
+    | otherwise               = Nothing
+
+-- | Try to strip a suffix from the end of a String.
+--
+-- If the suffix is not ending the string, then Nothing is returned,
+-- otherwise the striped string is returned
+stripSuffix :: String -> String -> Maybe String
+stripSuffix (String prefix) (String arr)
+    | C.isSuffixOf prefix arr = Just $ String $ C.revDrop (C.length prefix) arr
+    | otherwise               = Nothing
+
+all :: (Char -> Bool) -> String -> Bool
+all predicate (String arr) = C.onBackend goNative (\_ -> pure . goAddr) arr
+  where
+    !(C.ValidRange start end) = C.offsetsValidRange arr
+    goNative ba = PrimBA.all predicate ba start end
+    goAddr (Ptr addr) = PrimAddr.all predicate addr start end
+
+any :: (Char -> Bool) -> String -> Bool
+any predicate (String arr) = C.onBackend goNative (\_ -> pure . goAddr) arr
+  where
+    !(C.ValidRange start end) = C.offsetsValidRange arr
+    goNative ba = PrimBA.any predicate ba start end
+    goAddr (Ptr addr) = PrimAddr.any predicate addr start end
 
 -- | Transform string @src@ to base64 binary representation.
 toBase64 :: String -> String
diff --git a/Foundation/String/UTF8/Addr.hs b/Foundation/String/UTF8/Addr.hs
--- a/Foundation/String/UTF8/Addr.hs
+++ b/Foundation/String/UTF8/Addr.hs
@@ -2,7 +2,6 @@
 {-# LANGUAGE MagicHash                  #-}
 {-# LANGUAGE NoImplicitPrelude          #-}
 {-# LANGUAGE TypeFamilies               #-}
-{-# LANGUAGE UnboxedTuples              #-}
 {-# LANGUAGE FlexibleContexts           #-}
 {-# LANGUAGE CPP                        #-}
 module Foundation.String.UTF8.Addr
@@ -20,6 +19,7 @@
 import qualified Foundation.Primitive.UTF8.Addr as PrimBackend
 import           Foundation.Primitive.UTF8.Helper
 import           Foundation.Primitive.UTF8.Table
+import           Foundation.Primitive.UTF8.Types
 
 copyFilter :: (Char -> Bool)
            -> CountOf Word8
@@ -39,8 +39,8 @@
                          | otherwise             -> loop d (s + Offset 1)
                     False ->
                         case PrimBackend.next src s of
-                            (# c, s' #) | predicate c -> PrimBA.write dst d c >>= \d' -> loop d' s'
-                                        | otherwise   -> loop d s'
+                            Step c s' | predicate c -> PrimBA.write dst d c >>= \d' -> loop d' s'
+                                      | otherwise   -> loop d s'
 
 validate :: Offset Word8
          -> PrimBackend.Immutable
diff --git a/Foundation/String/UTF8/BA.hs b/Foundation/String/UTF8/BA.hs
--- a/Foundation/String/UTF8/BA.hs
+++ b/Foundation/String/UTF8/BA.hs
@@ -2,7 +2,6 @@
 {-# LANGUAGE MagicHash                  #-}
 {-# LANGUAGE NoImplicitPrelude          #-}
 {-# LANGUAGE TypeFamilies               #-}
-{-# LANGUAGE UnboxedTuples              #-}
 {-# LANGUAGE FlexibleContexts           #-}
 {-# LANGUAGE CPP                        #-}
 module Foundation.String.UTF8.BA
@@ -20,6 +19,7 @@
 import qualified Foundation.Primitive.UTF8.BA as PrimBackend
 import           Foundation.Primitive.UTF8.Helper
 import           Foundation.Primitive.UTF8.Table
+import           Foundation.Primitive.UTF8.Types
 
 copyFilter :: (Char -> Bool)
            -> CountOf Word8
@@ -39,8 +39,8 @@
                          | otherwise             -> loop d (s + Offset 1)
                     False ->
                         case PrimBackend.next src s of
-                            (# c, s' #) | predicate c -> PrimBA.write dst d c >>= \d' -> loop d' s'
-                                        | otherwise   -> loop d s'
+                            Step c s' | predicate c -> PrimBA.write dst d c >>= \d' -> loop d' s'
+                                      | otherwise   -> loop d s'
 
 validate :: Offset Word8
          -> PrimBackend.Immutable
diff --git a/Foundation/System/Bindings/Hs.hs b/Foundation/System/Bindings/Hs.hs
--- a/Foundation/System/Bindings/Hs.hs
+++ b/Foundation/System/Bindings/Hs.hs
@@ -6,19 +6,33 @@
 
 import GHC.IO
 import GHC.Prim
+import GHC.Word
 import Foreign.C.Types
 import Foreign.Ptr
+import Foundation.Primitive.Types.OffsetSize
 
 foreign import ccall unsafe "HsBase.h __hscore_get_errno" sysHsCoreGetErrno :: IO CInt
 
 foreign import ccall unsafe "_foundation_memcmp" sysHsMemcmpBaBa ::
-    ByteArray# -> CSize -> ByteArray# -> CSize -> CSize -> IO CInt
+    ByteArray# -> Offset Word8 -> ByteArray# -> Offset Word8 -> CountOf Word8 -> IO CInt
 
 foreign import ccall unsafe "_foundation_memcmp" sysHsMemcmpBaPtr ::
-    ByteArray# -> CSize -> Ptr a -> CSize -> CSize -> IO CInt
+    ByteArray# -> Offset Word8 -> Ptr a -> Offset Word8 -> CountOf Word8 -> IO CInt
 
 foreign import ccall unsafe "_foundation_memcmp" sysHsMemcmpPtrBa ::
-    Ptr a -> CSize -> ByteArray# -> CSize -> CSize -> IO CInt
+    Ptr a -> Offset Word8 -> ByteArray# -> Offset Word8 -> CountOf Word8 -> IO CInt
 
 foreign import ccall unsafe "_foundation_memcmp" sysHsMemcmpPtrPtr ::
-    Ptr a -> CSize -> Ptr b -> CSize -> CSize -> IO CInt
+    Ptr a -> Offset Word8 -> Ptr b -> Offset Word8 -> CountOf Word8 -> IO CInt
+
+foreign import ccall unsafe "_foundation_mem_findbyte" sysHsMemFindByteBa ::
+    ByteArray# -> Offset Word8 -> Offset Word8 -> Word8 -> Offset Word8
+
+foreign import ccall unsafe "_foundation_mem_findbyte" sysHsMemFindByteAddr ::
+    Addr# -> Offset Word8 -> Offset Word8 -> Word8 -> Offset Word8
+
+--foreign import ccall unsafe "foundation_utf8_length" sysHsUTF8LengthBa ::
+--    ByteArray# -> Offset Word8 -> Offset Word8 -> CountOf Char
+
+--foreign import ccall unsafe "foundation_utf8_length" sysHsUTF8LengthAddr ::
+--    Addr# -> Offset Word8 -> Offset Word8 -> CountOf Char
diff --git a/Foundation/Time/Types.hs b/Foundation/Time/Types.hs
--- a/Foundation/Time/Types.hs
+++ b/Foundation/Time/Types.hs
@@ -23,6 +23,7 @@
 
 instance PrimType NanoSeconds where
     primSizeInBytes _        = primSizeInBytes (Proxy :: Proxy Word64)
+    primShiftToBytes _       = primShiftToBytes (Proxy :: Proxy Word64)
     primBaUIndex ba ofs      = primBaUIndex ba (coerce ofs)
     primMbaURead mba ofs     = primMbaURead mba (coerce ofs)
     primMbaUWrite mba ofs v  = primMbaUWrite mba (coerce ofs) (coerce v :: Word64)
@@ -36,6 +37,7 @@
 
 instance PrimType Seconds where
     primSizeInBytes _        = primSizeInBytes (Proxy :: Proxy Word64)
+    primShiftToBytes _       = primShiftToBytes (Proxy :: Proxy Word64)
     primBaUIndex ba ofs      = primBaUIndex ba (coerce ofs)
     primMbaURead mba ofs     = primMbaURead mba (coerce ofs)
     primMbaUWrite mba ofs v  = primMbaUWrite mba (coerce ofs) (coerce v :: Word64)
diff --git a/Foundation/UUID.hs b/Foundation/UUID.hs
--- a/Foundation/UUID.hs
+++ b/Foundation/UUID.hs
@@ -1,18 +1,31 @@
-{-# LANGUAGE UnboxedTuples #-}
+{-# LANGUAGE UnboxedTuples    #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE OverloadedStrings #-}
+
 module Foundation.UUID
     ( UUID(..)
+    , newUUID
     , nil
     , fromBinary
+    , uuidParser
     ) where
 
+import Control.Monad (unless)
+import Data.Maybe (fromMaybe)
+
 import           Foundation.Internal.Base
+import           Foundation.Collection (Element, Sequential, foldl')
 import           Foundation.Class.Storable
 import           Foundation.Hashing.Hashable
 import           Foundation.Bits
+import           Foundation.Parser
+import           Foundation.Numerical
 import           Foundation.Primitive
 import           Foundation.Primitive.Base16
 import           Foundation.Primitive.IntegralConv
+import           Foundation.Primitive.Types.OffsetSize
 import qualified Foundation.Array.Unboxed as UA
+import           Foundation.Random (MonadRandom, getRandomBytes)
 
 data UUID = UUID {-# UNPACK #-} !Word64 {-# UNPACK #-} !Word64
     deriving (Eq,Ord,Typeable)
@@ -59,6 +72,11 @@
 nil :: UUID
 nil = UUID 0 0
 
+newUUID :: MonadRandom randomly => randomly UUID
+newUUID = fromMaybe (error "Foundation.UUID.newUUID: the impossible happned")
+        . fromBinary
+        <$> getRandomBytes 16
+
 fromBinary :: UA.UArray Word8 -> Maybe UUID
 fromBinary ba
     | UA.length ba /= 16 = Nothing
@@ -85,3 +103,55 @@
     b13 = integralUpsize (UA.unsafeIndex ba 13)
     b14 = integralUpsize (UA.unsafeIndex ba 14)
     b15 = integralUpsize (UA.unsafeIndex ba 15)
+
+uuidParser :: ( ParserSource input, Element input ~ Char
+              , Sequential (Chunk input), Element input ~ Element (Chunk input)
+              )
+           => Parser input UUID
+uuidParser = do
+    hex1 <- parseHex (CountOf 8) <* element '-'
+    hex2 <- parseHex (CountOf 4) <* element '-'
+    hex3 <- parseHex (CountOf 4) <* element '-'
+    hex4 <- parseHex (CountOf 4) <* element '-'
+    hex5 <- parseHex (CountOf 12)
+    return $ UUID (hex1 .<<. 32 .|. hex2 .<<. 16 .|. hex3)
+                  (hex4 .<<. 48 .|. hex5)
+
+
+parseHex :: ( ParserSource input, Element input ~ Char
+            , Sequential (Chunk input), Element input ~ Element (Chunk input)
+            )
+         => CountOf Char -> Parser input Word64
+parseHex count = do
+    r <- toList <$> take count
+    unless (and $ isValidHexa <$> r) $
+        reportError $ Satisfy $ Just $ "expecting hexadecimal character only: "
+                                    <> fromList (show r)
+    return $ listToHex 0 r
+  where
+    listToHex = foldl' (\acc' x -> acc' * 16 + fromHex x)
+    isValidHexa :: Char -> Bool
+    isValidHexa c = ('0' <= c && c <= '9') || ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F')
+    fromHex '0' = 0
+    fromHex '1' = 1
+    fromHex '2' = 2
+    fromHex '3' = 3
+    fromHex '4' = 4
+    fromHex '5' = 5
+    fromHex '6' = 6
+    fromHex '7' = 7
+    fromHex '8' = 8
+    fromHex '9' = 9
+    fromHex 'a' = 10
+    fromHex 'b' = 11
+    fromHex 'c' = 12
+    fromHex 'd' = 13
+    fromHex 'e' = 14
+    fromHex 'f' = 15
+    fromHex 'A' = 10
+    fromHex 'B' = 11
+    fromHex 'C' = 12
+    fromHex 'D' = 13
+    fromHex 'E' = 14
+    fromHex 'F' = 15
+    fromHex _   = error "Foundation.UUID.parseUUID: the impossible happened"
diff --git a/benchs/Fake/ByteString.hs b/benchs/Fake/ByteString.hs
--- a/benchs/Fake/ByteString.hs
+++ b/benchs/Fake/ByteString.hs
@@ -4,14 +4,23 @@
     , length
     , splitAt
     , take
+    , takeWhile
     , break
     , reverse
     , filter
+    , foldl'
+    , foldl1'
+    , foldr
+    , and
+    , all
+    , any
     , readInt
     , readInteger
+    , unpack
     ) where
 
 import Prelude (undefined, Maybe(..))
+import Data.Word
 
 data ByteString = ByteString
 
@@ -20,8 +29,20 @@
 splitAt _ _ = (undefined, undefined)
 take        = undefined
 break   _ _ = (undefined, undefined)
+takeWhile _ _ = undefined
 reverse     = undefined
 filter _    = undefined
+foldl' :: (Word8 -> a -> a) -> a -> ByteString -> a
+foldl' _ _ _ = undefined
+foldl1' :: (Word8 -> Word8 -> Word8) -> ByteString -> a
+foldl1' _ _ = undefined
+foldr :: (a -> Word8 -> a) -> a -> ByteString -> a
+foldr _ _ _ = undefined
+and _ _ = undefined
+all _ _ = undefined
+any _ _ = undefined
+unpack :: ByteString -> [Word8]
+unpack = undefined
 
 readInt :: ByteString -> Maybe (a,b)
 readInt _    = undefined
diff --git a/benchs/Fake/Text.hs b/benchs/Fake/Text.hs
--- a/benchs/Fake/Text.hs
+++ b/benchs/Fake/Text.hs
@@ -1,6 +1,7 @@
 module Fake.Text
     ( Text
     , pack
+    , unpack
     , length
     , splitAt
     , take
@@ -12,11 +13,13 @@
     , decodeUtf8
     ) where
 
-import Prelude (undefined, Either(..))
+import Prelude (undefined, Either(..), Char)
 
 data Text = Text
 
 pack _      = Text
+unpack :: Text -> [Char]
+unpack _ = undefined
 length      = undefined
 splitAt _ _ = (undefined, undefined)
 take        = undefined
diff --git a/benchs/Fake/Vector.hs b/benchs/Fake/Vector.hs
new file mode 100644
--- /dev/null
+++ b/benchs/Fake/Vector.hs
@@ -0,0 +1,42 @@
+module Fake.Vector
+    ( Vector
+    , fromList
+    , toList
+    , length
+    , splitAt
+    , take
+    , takeWhile
+    , break
+    , reverse
+    , filter
+    , foldl'
+    , foldl1'
+    , foldr
+    , and
+    , all
+    , any
+    ) where
+
+import Prelude (undefined)
+
+data Vector ty = Vector
+
+fromList _  = Vector
+toList :: Vector ty -> [ty]
+toList _ = undefined
+length      = undefined
+splitAt _ _ = (undefined, undefined)
+take        = undefined
+break   _ _ = (undefined, undefined)
+takeWhile _ _ = undefined
+reverse     = undefined
+filter _    = undefined
+foldl' :: (ty -> a -> a) -> a -> Vector ty -> a
+foldl' _ _ _ = undefined
+foldl1' :: (ty -> ty -> ty) -> Vector ty -> a
+foldl1' _ _ = undefined
+foldr :: (a -> ty -> a) -> a -> Vector ty -> a
+foldr _ _ _ = undefined
+and _ _ = undefined
+all _ _ = undefined
+any _ _ = undefined
diff --git a/benchs/Main.hs b/benchs/Main.hs
--- a/benchs/Main.hs
+++ b/benchs/Main.hs
@@ -8,6 +8,7 @@
 
 import Foundation
 import Foundation.Collection
+import Foundation.Primitive.Block (Block)
 import Foundation.String.Read
 import Foundation.String
 import BenchUtil.Common
@@ -21,15 +22,18 @@
 import qualified Data.Text as Text
 import qualified Data.Text.Read as Text
 import qualified Data.Text.Encoding as Text
+import qualified Data.Vector.Unboxed as Vector
 #else
 import qualified Fake.ByteString as ByteString
 import qualified Fake.Text as Text
+import qualified Fake.Vector as Vector
 #endif
 
 --------------------------------------------------------------------------
 
 benchsString = bgroup "String"
     [ benchLength
+    , benchUnpack
     , benchElem
     , benchTake
     , benchSplitAt
@@ -97,6 +101,9 @@
     benchLength = bgroup "Length" $
         fmap (\(n, dat) -> bgroup n $ diffTextString length Text.length dat)
             allDat
+    benchUnpack = bgroup "Unpack" $
+        fmap (\(n, dat) -> bgroup n $ diffTextString (length . toList) (length . Text.unpack) dat)
+            allDat
     benchElem = bgroup "Elem" $
         fmap (\(n, dat) -> bgroup n $ diffTextString (elem '.') (Text.any (== '.')) dat)
             allDat
@@ -160,25 +167,36 @@
 benchsByteArray = bgroup "ByteArray"
     [ benchLength
     , benchTake
+    , benchSplitAt
     , benchBreakElem
+    , benchTakeWhile
+    , benchFoldl
+    , benchFoldl1
+    , benchFoldr
     , benchReverse
     , benchFilter
-    --, benchSplitAt
+    , benchAll
     ]
   where
-    diffByteString :: (UArray Word8 -> a)
-                   -> (ByteString.ByteString -> b)
+    diffByteArray :: (UArray Word8 -> a)
+                   -> (Block Word8 -> b)
+                   -> (ByteString.ByteString -> c)
+                   -> (Vector.Vector Word8 -> d)
                    -> [Word8]
                    -> [Benchmark]
-    diffByteString foundationBench textBench dat =
-        [ bench "UArray_W8" $ whnf foundationBench s
+    diffByteArray uarrayBench blockBench bsBench vectorBench dat =
+        [ bench "UArray_W8" $ whnf uarrayBench s
+        , bench "Block_W8" $ whnf blockBench s'
 #ifdef BENCH_ALL
-        , bench "ByteString" $ whnf textBench t
+        , bench "ByteString" $ whnf bsBench t
+        , bench "Vector_W8" $ whnf vectorBench v
 #endif
         ]
       where
         s = fromList dat
+        s' = fromList dat
         t = ByteString.pack dat
+        v = Vector.fromList dat
 
     allDat =
         [ ("bs20", rdBytes20)
@@ -188,23 +206,63 @@
     allDatSuffix s = fmap (first (\x -> x <> "-" <> s)) allDat
 
     benchLength = bgroup "Length" $
-        fmap (\(n, dat) -> bgroup n $ diffByteString length ByteString.length dat) allDat
+        fmap (\(n, dat) -> bgroup n $ diffByteArray length length ByteString.length Vector.length dat) allDat
 
     benchTake = bgroup "Take" $ mconcat $ fmap (\p ->
-        fmap (\(n, dat) -> bgroup n $ diffByteString (take (CountOf p)) (ByteString.take p) dat)
+        fmap (\(n, dat) -> bgroup n $ diffByteArray (take (CountOf p)) (take (CountOf p))
+                                                    (ByteString.take p) (Vector.take p) dat)
             $ allDatSuffix (show p)
         ) [ 0, 10, 100 ]
 
+    benchSplitAt = bgroup "SplitAt" $ mconcat $ fmap (\p ->
+        fmap (\(n, dat) -> bgroup n $ diffByteArray (fst . splitAt (CountOf p)) (fst . splitAt (CountOf p))
+                                                    (fst . ByteString.splitAt p) (fst . Vector.splitAt p) dat)
+                $ allDatSuffix (show p)
+        ) [ 19, 199, 0 ]
+
     benchBreakElem = bgroup "BreakElem" $ mconcat $ fmap (\p ->
-        fmap (\(n, dat) -> bgroup n $ diffByteString (fst . breakElem p) (fst . ByteString.break (== p)) dat)
+        fmap (\(n, dat) -> bgroup n $ diffByteArray (fst . breakElem p) (fst . breakElem p)
+                                                    (fst . ByteString.break (== p)) (fst . Vector.break (== p)) dat)
                 $ allDatSuffix (show p)
         ) [ 19, 199, 0 ]
 
+    benchTakeWhile = bgroup "TakeWhile" $ fmap (\(n, dat) ->
+            bgroup n $ diffByteArray (takeWhile (< 0x80)) (takeWhile (< 0x80))
+                                     (ByteString.takeWhile (< 0x80)) (Vector.takeWhile (< 0x80)) dat)
+                $ allDat
+
+    benchFoldl = bgroup "Foldl" $ fmap (\(n, dat) ->
+            bgroup n $ diffByteArray (foldl' (+) 0) (foldl' (+) 0)
+                                     (ByteString.foldl' (+) 0) (Vector.foldl' (+) 0) dat)
+                $ allDat
+
+    benchFoldl1 = bgroup "Foldl1" $ fmap (\(n, dat) ->
+            bgroup n $ diffByteArray (foldl1' (+) . nonEmpty_) (foldl1' (+) . nonEmpty_)
+                                     (ByteString.foldl1' (+)) (Vector.foldl1' (+)) dat)
+                $ allDat
+
+    benchFoldr = bgroup "Foldr" $ fmap (\(n, dat) ->
+            bgroup n $ diffByteArray (foldr (+) 1) (foldr (+) 1)
+                                     (ByteString.foldr (+) 1) (Vector.foldr (+) 1) dat)
+                $ allDat
+
+    benchAll = bgroup "All" $ fmap (\(n, dat) ->
+            bgroup n $ diffByteArray (all (> 0)) (all (> 0))
+                                     (ByteString.all (> 0)) (Vector.all (> 0)) dat)
+                $ allDat
+
+    benchAny = bgroup "Any" $ fmap (\(n, dat) ->
+            bgroup n $ diffByteArray (any (== 80)) (any (== 80))
+                                     (ByteString.any (== 80)) (Vector.any (== 80)) dat)
+                $ allDat
+
     benchReverse = bgroup "Reverse" $
-        fmap (\(n, dat) -> bgroup n $ diffByteString reverse ByteString.reverse dat) allDat
+        fmap (\(n, dat) -> bgroup n $ diffByteArray reverse reverse ByteString.reverse Vector.reverse dat) allDat
 
     benchFilter = bgroup "Filter" $
-        fmap (\(n, dat) -> bgroup n $ diffByteString (filter (> 100)) (ByteString.filter (> 100)) dat) allDat
+        fmap (\(n, dat) -> bgroup n $ diffByteArray (filter (> 100)) (filter (> 100))
+                                                    (ByteString.filter (> 100))
+                                                    (Vector.filter (> 100)) dat) allDat
 
 --------------------------------------------------------------------------
 
diff --git a/benchs/Sys.hs b/benchs/Sys.hs
--- a/benchs/Sys.hs
+++ b/benchs/Sys.hs
@@ -19,6 +19,9 @@
     randomNew        = return NullRandom
     randomNewFrom    = error "no randomNewFrom"
     randomGenerate (CountOf n) r = (fromList (Prelude.replicate n 0), r)
+    randomGenerateWord64 r = (0, r)
+    randomGenerateF32 r = (0.0, r)
+    randomGenerateF64 r = (0.0, r)
 
 benchSys =
     [ bgroup "Random"
diff --git a/cbits/foundation_mem.c b/cbits/foundation_mem.c
--- a/cbits/foundation_mem.c
+++ b/cbits/foundation_mem.c
@@ -1,6 +1,14 @@
 #include <string.h>
+#include <stdint.h>
+#include "foundation_prim.h"
 
-int _foundation_memcmp(const void *s1, size_t off1, const void *s2, size_t off2, size_t n)
+int _foundation_memcmp(const void *s1, FsOffset off1, const void *s2, FsOffset off2, FsCountOf n)
 {
 	return memcmp(s1 + off1, s2 + off2, n);
+}
+
+FsOffset _foundation_mem_findbyte(uint8_t * const arr, FsOffset startofs, FsOffset endofs, uint8_t ty)
+{
+    uint8_t *r = memchr(arr + startofs, ty, endofs - startofs);
+    return ((r == NULL) ? endofs : r - arr);
 }
diff --git a/cbits/foundation_prim.h b/cbits/foundation_prim.h
new file mode 100644
--- /dev/null
+++ b/cbits/foundation_prim.h
@@ -0,0 +1,8 @@
+#ifndef FOUNDATION_PRIM_H
+#define FOUNDATION_PRIM_H
+#include "Rts.h"
+
+typedef StgInt FsOffset;
+typedef StgInt FsCountOf;
+
+#endif
diff --git a/cbits/foundation_random.c b/cbits/foundation_random.c
--- a/cbits/foundation_random.c
+++ b/cbits/foundation_random.c
@@ -143,3 +143,34 @@
 	return 0;
 }
 
+int foundation_rngV1_generate_word32(uint8_t newkey[CHACHA_KEY_SIZE], uint32_t *dst_w, uint8_t key[CHACHA_KEY_SIZE])
+{
+	return foundation_rngV1_generate(newkey, (uint8_t*)dst_w, key, sizeof(uint32_t));
+}
+
+int foundation_rngV1_generate_word64(uint8_t newkey[CHACHA_KEY_SIZE], uint64_t *dst_w, uint8_t key[CHACHA_KEY_SIZE])
+{
+	return foundation_rngV1_generate(newkey, (uint8_t*)dst_w, key, sizeof(uint64_t));
+}
+
+int foundation_rngV1_generate_f32(uint8_t newkey[CHACHA_KEY_SIZE], float *dst_w, uint8_t key[CHACHA_KEY_SIZE])
+{
+	uint32_t const UPPER_MASK = 0x3F800000UL;
+	uint32_t const LOWER_MASK = 0x007FFFFFUL;
+	uint32_t tmp32;
+	int r = foundation_rngV1_generate_word32(newkey, &tmp32, key);
+	tmp32 = UPPER_MASK | (tmp32 & LOWER_MASK);
+	*dst_w = (float)tmp32 - 1.0;
+	return r;
+}
+
+int foundation_rngV1_generate_f64(uint8_t newkey[CHACHA_KEY_SIZE], double *dst_w, uint8_t key[CHACHA_KEY_SIZE])
+{
+	uint64_t const UPPER_MASK = 0x3FF0000000000000ULL;
+	uint64_t const LOWER_MASK = 0x000FFFFFFFFFFFFFULL;
+	uint64_t tmp64;
+	int r = foundation_rngV1_generate_word64(newkey, &tmp64, key);
+	tmp64 = UPPER_MASK | (tmp64 & LOWER_MASK);
+	*dst_w = (double)tmp64 - 1.0;
+	return r;
+}
diff --git a/cbits/foundation_rts.c b/cbits/foundation_rts.c
new file mode 100644
--- /dev/null
+++ b/cbits/foundation_rts.c
@@ -0,0 +1,8 @@
+#include "Rts.h"
+
+#if __GLASGOW_HASKELL__ < 802
+int foundation_is_bytearray_pinned(void *p)
+{
+    return Bdescr((StgPtr) p)->flags & BF_PINNED;
+}
+#endif
diff --git a/cbits/foundation_utf8.c b/cbits/foundation_utf8.c
new file mode 100644
--- /dev/null
+++ b/cbits/foundation_utf8.c
@@ -0,0 +1,85 @@
+#include <stdint.h>
+#include <stdlib.h>
+#include "foundation_prim.h"
+
+#if 0
+static const uint64_t utf8_mask_80 = 0x8080808080808080ULL;
+static const uint64_t utf8_mask_40 = 0x4040404040404040ULL;
+
+typedef unsigned long pu;
+#define POPCOUNT(x) __builtin_popcountl(x)
+#define ALIGNED8(p) ((((uintptr_t) (p)) & (sizeof(pu)-1)) == 0)
+
+FsCountOf foundation_utf8_length(uint8_t *p8, const FsOffset start_offset, const FsOffset end_offset)
+{
+    const uint8_t *end = p8 + end_offset;
+    FsCountOf n = 0;
+
+    p8 += start_offset;
+
+    while (!ALIGNED8(p8) && p8 < end) {
+        if ((*p8++ & 0xc0) != 0x80) { n++; }
+    }
+
+    /* process 8 bytes */
+    for (; (p8 + sizeof(pu)) <= end; p8 += sizeof(pu)) {
+        pu h   = *((pu *) p8);
+        pu h80 = h & utf8_mask_80;
+
+        /* only ASCII */
+        if (h80 == 0) {
+            n += sizeof(pu);
+            continue;
+        }
+
+        int nb_ascii = (h80 == utf8_mask_80) ? 0 : (8 - __builtin_popcountl(h80));
+        int nb_high = __builtin_popcountl( h & (h80 >> 1));
+        n += nb_ascii + nb_high;
+    }
+
+    while (p8 < end) {
+        if ((*p8++ & 0xc0) != 0x80) { n++; }
+    }
+
+    return n;
+}
+
+#define IS_CONT(x) ((x & 0xc0) == 0x80)
+
+int foundation_utf8_validate(const uint8_t *c, size_t offset, size_t end)
+{
+    while (offset < end) {
+        uint8_t h = c[offset];
+        if (!(h & 0x80)) {
+            offset++;
+            continue;
+        }
+
+        /* continuation */
+        if      (h < 0xC0) { goto fail1; }
+        /* 2 bytes */
+        else if (h < 0xE0) { if      (offset + 1 >= end) { goto fail2; }
+            else if (IS_CONT(c[offset+1])) { offset += 2; }
+            else { goto fail1; }
+        }
+        /* 3 bytes */
+        else if (h < 0xF0) { if      (offset + 2 >= end) { goto fail2; }
+            else if (IS_CONT(c[offset+1]) && IS_CONT(c[offset+2])) { offset += 3; }
+            else { goto fail1; }
+        }
+
+        /* 4 bytes */
+        else if (h < 0xFE) { if      (offset + 3 >= end) { goto fail2; }
+            else if (IS_CONT(c[offset+1]) && IS_CONT(c[offset+2]) && IS_CONT(c[offset+3])) { offset += 4; }
+            else { goto fail1; }
+        }
+        /* invalid > 4 bytes */
+        else               { goto fail1; }
+    }
+    return 0;
+fail1:
+    return 1;
+fail2:
+    return 2;
+}
+#endif
diff --git a/foundation.cabal b/foundation.cabal
--- a/foundation.cabal
+++ b/foundation.cabal
@@ -1,5 +1,5 @@
 name:                foundation
-version:             0.0.12
+version:             0.0.13
 synopsis:            Alternative prelude with batteries and no dependencies
 description:
     A custom prelude with no dependencies apart from base.
@@ -192,6 +192,10 @@
                      Foundation.Primitive.UTF8.Base
                      Foundation.Primitive.UTF8.BA
                      Foundation.Primitive.UTF8.Addr
+                     Foundation.Primitive.UTF8.Types
+                     Foundation.Primitive.UArray.Base
+                     Foundation.Primitive.UArray.BA
+                     Foundation.Primitive.UArray.Addr
                      Foundation.Primitive.Runtime
                      Foundation.Primitive.Imports
                      Foundation.Monad.MonadIO
@@ -220,6 +224,8 @@
                      cbits/foundation_network.c
                      cbits/foundation_mem.c
                      cbits/foundation_time.c
+                     cbits/foundation_utf8.c
+                     cbits/foundation_rts.c
 
   if flag(experimental)
     exposed-modules: Foundation.Network.HostName
@@ -353,6 +359,7 @@
                      Sys
                      Fake.ByteString
                      Fake.Text
+                     Fake.Vector
   hs-source-dirs:    benchs
   default-language:  Haskell2010
   type:              exitcode-stdio-1.0
diff --git a/tests/Checks.hs b/tests/Checks.hs
--- a/tests/Checks.hs
+++ b/tests/Checks.hs
@@ -75,13 +75,13 @@
 readFloatingExact' str = readFloatingExact str (\s x y z -> Just (s,x,y,z))
 
 doubleEqualApprox :: Double -> Double -> PropertyCheck
-doubleEqualApprox d1 d2 = (propertyCompare pName1 (<) (negate lim) d) `propertyAnd` (propertyCompare pName2 (<) d lim)
+doubleEqualApprox d1 d2 = propertyCompare name (<) (abs d) lim
   where
         d = d2 - d1
 
-        pName1 = show (negate lim) <> " < " <> show d2 <> " - " <> show d1 <> " (== " <> show d <> " )"
-        pName2 = show d1 <> " - " <> show d2 <> " (== " <> show d <> " )" <> " < " <> show lim
-        lim = 1.0e-8
+        name = show d1 <> " - " <> show d2 <> " (differential=" <> show (abs d) <> " )" <> " < " <> show lim
+
+        lim = min d1 d2 * (10^^(-15 :: Int))
 
 main = defaultMain $ Group "foundation"
     [ Group "Numerical"
diff --git a/tests/Test/Foundation/Misc.hs b/tests/Test/Foundation/Misc.hs
--- a/tests/Test/Foundation/Misc.hs
+++ b/tests/Test/Foundation/Misc.hs
@@ -14,7 +14,11 @@
 import Test.Foundation.Collection (fromListP, toListP)
 
 import qualified Foundation.UUID as UUID
+import           Foundation.Parser
 
+instance Arbitrary UUID.UUID where
+    arbitrary = UUID.UUID <$> arbitrary <*> arbitrary
+
 hex :: [Word8] -> [Word8]
 hex = loop
   where
@@ -45,4 +49,6 @@
 testUUID = testGroup "UUID"
     [ testProperty "show" $ show UUID.nil === "00000000-0000-0000-0000-000000000000"
     , testProperty "show-bin" $ fmap show (UUID.fromBinary (fromList [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16])) === Just "100f0e0d-0c0b-0a09-0807-060504030201"
+    , testProperty "parser . show = id" $ \uuid ->
+        (either (error . show) id $ parseOnly UUID.uuidParser (show uuid)) === uuid
     ]
diff --git a/tests/Test/Foundation/String.hs b/tests/Test/Foundation/String.hs
--- a/tests/Test/Foundation/String.hs
+++ b/tests/Test/Foundation/String.hs
@@ -96,6 +96,22 @@
             , testCase "30 31 E2 82 0C" $ expectFromBytesErr UTF8 ("01", Just InvalidContinuation, 2) (fromList [0x30,0x31,0xE2,0x82,0x0c])
             ]
         ]
+    , testGroup "Lines"
+        [ testCase "Hello<LF>Foundation" $
+            (breakLine "Hello\nFoundation" @?= Right ("Hello", "Foundation"))
+        , testCase "Hello<CRLF>Foundation" $
+            (breakLine "Hello\r\nFoundation" @?= Right ("Hello", "Foundation"))
+        , testCase "Hello<LF>Foundation" $
+            (breakLine (drop 5 "Hello\nFoundation\nSomething") @?= Right ("", "Foundation\nSomething"))
+        , testCase "Hello<CR>" $
+            (breakLine "Hello\r" @?= Left True)
+        , testCase "CR" $
+            (breakLine "\r" @?= Left True)
+        , testCase "LF" $
+            (breakLine "\n" @?= Right ("", ""))
+        , testCase "empty" $
+            (breakLine "" @?= Left False)
+        ]
     ]
 
 testAsciiStringCases :: [TestTree]
