packages feed

bytestring-ft-0.1.0.0: src/Data/ByteString/FingerTree/Internal.hs

{-# LANGUAGE ImportQualifiedPost #-}
{-# LANGUAGE BlockArguments, LambdaCase #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE PatternSynonyms #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE ViewPatterns, BangPatterns #-}
{-# OPTIONS_GHC -Wall -fno-warn-tabs #-}

module Data.ByteString.FingerTree.Internal (

	-- * BYTE STRING

	ByteString(..), pattern Empty,
	pattern (:<), pattern (:>),
	pattern (:<|), pattern (:|>),

	-- * INTRODUCING AND ELIMINATING

	empty, singleton, pack, unpack, fromStrict, toStrict,

	-- * BASIC INTERFACE

	cons, snoc, append, uncons, unsnoc, null, length,

	-- * GENERATING

	replicate, unfoldr,

	-- * BREAKING

	splitAt',

	-- * FingerTree

	FingerTree(..)

) where

import Prelude hiding (concat, null, length, replicate)
import Prelude qualified as P
import Data.Foldable (foldr')
import Data.String
import Data.Bool
import Data.Word
import Data.ByteString qualified as BS
import Data.ByteString.Char8 qualified as BSC

import GHC.Generics

import Data.MonoTraversable

infixr 5 `consTree`
infixl 5 `snocTree`
infixr 5 `appendTree0`

newtype ByteString = ByteString { unByteString :: FingerTree BS.ByteString }

instance IsString ByteString where
	{-# INLINE fromString #-}
	fromString = packChars

instance Semigroup ByteString where
	(<>) = append

instance Monoid ByteString where
	mempty = Empty
	mappend = (<>)
	mconcat = concat

instance Read ByteString where
	readsPrec p str = [ (packChars x, y) | (x, y) <- readsPrec p str ]

instance Show ByteString where
	showsPrec p ps r = showsPrec p (unpackChars ps) r

instance Eq ByteString where (==) = eq
instance Ord ByteString where compare = compareBytes

empty :: ByteString
empty = Empty

singleton :: Word8 -> ByteString
singleton = ByteString . Single . BS.singleton

pack :: [Word8] -> ByteString
pack = \case
	[] -> ByteString EmptyT
	bs -> ByteString . Single $ BS.pack bs

unpack :: ByteString -> [Word8]
unpack (ByteString t) = unpackTree t

unpackTree :: FingerTree BS.ByteString -> [Word8]
unpackTree EmptyT = []
unpackTree (bs :<|| t) = BS.unpack bs ++ unpackTree t

fromStrict :: BS.ByteString -> ByteString
fromStrict bs = bool (ByteString $ Single bs) Empty (BS.null bs)

toStrict :: ByteString -> BS.ByteString
toStrict (ByteString t) = toStrictTree t

toStrictTree :: FingerTree BS.ByteString -> BS.ByteString
toStrictTree = BS.concat . toList

cons :: Word8 -> ByteString -> ByteString
b `cons` ByteString bs = ByteString $ BS.singleton b `consTree` bs

snoc :: ByteString -> Word8 -> ByteString
ByteString bs `snoc` b = ByteString $ bs `snocTree` BS.singleton b

append :: ByteString -> ByteString -> ByteString
append = (><)

uncons :: ByteString -> Maybe (Word8, ByteString)
uncons (ByteString t) = case t of
	EmptyT -> Nothing
	bs :<|| t' -> case BS.uncons bs of
		Nothing -> error "unnormalized ByteString"
		Just (b, bs') -> Just (
			b,
			bool	(ByteString $ bs' :<|| t')
				(ByteString t')
				(BS.null bs') )

unsnoc :: ByteString -> Maybe (ByteString, Word8)
unsnoc (ByteString t) = case t of
	EmptyT -> Nothing
	t' :||> bs -> case BS.unsnoc bs of
		Nothing -> error "unnormalized ByteString"
		Just (bs', b) -> Just (
			bool	(ByteString $ t' :||> bs')
				(ByteString t')
				(BS.null bs'),
			b )

null :: ByteString -> Bool
null = (<= 0) . size . unByteString

length :: ByteString -> Int
length = size . unByteString

concat :: [ByteString] -> ByteString
concat = foldr append Empty

replicate :: Int -> Word8 -> ByteString
replicate 0 = const $ Empty
replicate n = ByteString . Single . BS.replicate n

unfoldr :: (a -> Maybe (Word8, a)) -> a -> ByteString
unfoldr f = concat . (fromStrict <$>) . unfoldChunk 32 64
	where unfoldChunk n  n' x =
		case BS.unfoldrN n f x of
			(s, Nothing) -> [s]
			(s, Just x') -> s : unfoldChunk n' (n + n') x'

splitAt' :: Int -> ByteString -> Maybe (ByteString, ByteString)
splitAt' n (ByteString t) = case search (\l _ -> l >= n) t of
	Position l x r -> let (xl, xr) = BS.splitAt (n - size l) x in
		Just (	ByteString $ bool (`snocTree` xl) id (BS.null xl) l,
			ByteString $ bool (xr `consTree`) id (BS.null xr) r )
	_ -> Nothing

eq :: ByteString -> ByteString -> Bool
eq Empty Empty = True
eq Empty _ = False
eq _ Empty = False
eq aa@(a :< as) ba@(b :< bs)
	| length aa /= length ba = False
	| otherwise = a == b && as `eq` bs

compareBytes :: ByteString -> ByteString -> Ordering
compareBytes Empty Empty = EQ
compareBytes Empty _ = LT
compareBytes _ Empty = GT
compareBytes (a :< as) (b :< bs)
	| a < b = LT
	| a > b = GT
	| otherwise = compareBytes as bs

packChars :: [Char] -> ByteString
packChars cs
	| P.null cs = ByteString EmptyT
	| otherwise = ByteString . Single $ BSC.pack cs

unpackChars :: ByteString -> [Char]
unpackChars (ByteString t) = unpackCharsTree t

unpackCharsTree :: FingerTree BS.ByteString -> [Char]
unpackCharsTree EmptyT = []
unpackCharsTree (bs :<|| t) = BSC.unpack bs ++ unpackCharsTree t

pattern Empty :: ByteString
pattern Empty = ByteString EmptyT

{-# COMPLETE (:<|), Empty #-}

pattern (:<|) :: BS.ByteString -> ByteString -> ByteString
pattern b :<| bs <- (unByteString -> b :<|| (ByteString -> bs)) where
	b :<| bs = ByteString $ bool (b :<|| unByteString bs) EmptyT (BS.null b)

{-# COMPLETE (:|>), Empty #-}

pattern (:|>) :: ByteString -> BS.ByteString -> ByteString
pattern bs :|> b <- (unByteString -> (ByteString -> bs) :||> b) where
	bs :|> b = ByteString $ bool (unByteString bs :||> b) EmptyT (BS.null b)

{-# COMPLETE (:<), Empty #-}

pattern (:<) :: Word8 -> ByteString -> ByteString
pattern b :< bs <- (uncons -> Just (b, bs)) where
	b :< bs = cons b bs

{-# COMPLETE (:>), Empty #-}

pattern (:>) :: ByteString -> Word8 -> ByteString
pattern bs :> b <- (unsnoc -> Just (bs, b)) where
	bs :> b = snoc bs b

{-# COMPLETE (:<||), EmptyT #-}

pattern (:<||) :: Sized a => a -> FingerTree a -> FingerTree a
pattern x :<|| xs <- (viewl -> x :<. xs) where 
	x :<|| xs = x `consTree` xs

{-# COMPLETE (:||>), EmptyT #-}

pattern (:||>) :: Sized a => FingerTree a -> a -> FingerTree a
pattern xs :||> x <- (viewr -> xs :>. x) where
	xs :||> x = xs `snocTree` x

(><) :: ByteString -> ByteString -> ByteString
ByteString xs >< ByteString ys = ByteString $ xs `appendTree0` ys

data SearchResult a
	= Position !(FingerTree a) a !(FingerTree a)
	| OnLeft
	| OnRight
	| Nowhere
	deriving (Eq, Ord, Show, Generic)

search :: Sized a =>
	(Int -> Int -> Bool) -> FingerTree a -> SearchResult a
search p t
	| p_left && p_right = OnLeft
	| not p_left && p_right = case searchTree p 0 t 0 of
		Split l x r -> Position l x r
	| not p_left && not p_right = OnRight
	| otherwise = Nowhere
	where
	p_left = p 0 vt
	p_right = p vt 0
	vt = size t

data Split t a = Split !t a !t

searchTree :: Sized a =>
	(Int -> Int -> Bool) -> Int -> FingerTree a -> Int -> Split (FingerTree a) a
searchTree _ _ EmptyT _ = error "EmptyT"
searchTree _ _ (Single x) _ = Split EmptyT x EmptyT
searchTree p vl (Deep _ pr m sf) vr
	| p vlp vmsr = case searchDigit p vl pr vmsr of
		Split l x r -> Split (maybe EmptyT digitToTree l) x (deepL r m sf)
	| p vlpm vsr = case searchTree p vlp m vsr of
		Split ml xs mr -> case searchNode p (vlp + size ml) xs (size mr + vsr) of
			Split l x r -> Split (deepR pr ml l) x (deepL r mr sf)
	| otherwise = case searchDigit p vlpm sf vr of
		Split l x r -> Split (deepR pr m l) x (maybe EmptyT digitToTree r)
	where
	vlp = vl + size pr
	vlpm = vlp + vm
	vmsr = vm + vsr
	vsr = size sf + vr
	vm = size m

searchNode :: Sized a =>
	(Int -> Int -> Bool) -> Int -> Node a -> Int -> Split (Maybe (Digit a)) a
searchNode p vl (Node2 _ a b) vr
	| p va vb = Split Nothing a (Just (One b))
	| otherwise = Split (Just (One a)) b Nothing
	where
	va = vl + size a
	vb = size b + vr
searchNode p vl (Node3 _ a b c) vr
	| p va vbc = Split Nothing a (Just (Two b c))
	| p vab vc = Split (Just (One a)) b (Just (One c))
	| otherwise = Split (Just (Two a b)) c Nothing
	where
	va = vl + size a
	vab = va + size b
	vc = size c + vr
	vbc = size b + vc

searchDigit :: Sized a =>
	(Int -> Int -> Bool) -> Int -> Digit a -> Int -> Split (Maybe (Digit a)) a
searchDigit _ vl (One a) vr = vl `seq` vr `seq` Split Nothing a Nothing
searchDigit p vl (Two a b) vr
	| p va vb = Split Nothing a (Just (One b))
	| otherwise = Split (Just (One a)) b Nothing
	where
	va = vl + size a
	vb = size b + vr
searchDigit p vl (Three a b c) vr
	| p va vbc = Split Nothing a (Just (Two b c))
	| p vab vc = Split (Just (One a)) b (Just (One c))
	| otherwise = Split (Just (Two a b)) c Nothing
	where
	va = vl + size a
	vab = va + size b
	vbc = size b + vc
	vc = size c + vr

searchDigit p vl (Four a b c d) vr
	| p va vbcd = Split Nothing a (Just (Three b c d))
	| p vab vcd = Split (Just (One a)) b (Just (Two c d))
	| p vabc vd = Split (Just (Two a b)) c (Just (One d))
	| otherwise = Split (Just (Three a b c)) d Nothing
	where
	va = vl + size a
	vab = va + size b
	vabc = vab + size c
	vbcd = size b + vcd
	vcd = size c + vd
	vd = size d + vr

data FingerTree a
	= EmptyT
	| Single a
	| Deep {-# UNPACK #-} !Int !(Digit a) (FingerTree (Node a)) !(Digit a)
	deriving (Show, Eq, Ord)

toList :: Sized a => FingerTree a -> [a]
toList EmptyT = []
toList (x :<|| xs) = x : toList xs

instance Sized a => Sized (FingerTree a) where
	{-# SPECIALIZE instance Sized (FingerTree BS.ByteString) #-}
	{-# SPECIALIZE instance Sized (FingerTree (Node a)) #-}
	size EmptyT = 0
	size (Single x) = size x
	size (Deep v _ _ _) = v

{-# SPECIALIZE consTree :: BS.ByteString -> FingerTree BS.ByteString -> FingerTree BS.ByteString #-}
{-# SPECIALIZE consTree :: Node a -> FingerTree (Node a) -> FingerTree (Node a) #-}
consTree :: Sized a => a -> FingerTree a -> FingerTree a
consTree a EmptyT = Single a
consTree a (Single b) = deep (One a) EmptyT (One b)
consTree a (Deep s (Four b c d e) m sf) = m `seq`
	Deep (size a + s) (Two a b) (node3 c d e `consTree` m) sf
consTree a (Deep s (Three b c d) m sf) = Deep (size a + s) (Four a b c d) m sf
consTree a (Deep s (Two b c) m sf) = Deep (size a + s) (Three a b c) m sf
consTree a (Deep s (One b) m sf) = Deep (size a + s) (Two a b) m sf

{-# SPECIALIZE snocTree :: FingerTree BS.ByteString -> BS.ByteString -> FingerTree BS.ByteString #-}
{-# SPECIALIZE snocTree :: FingerTree (Node a) -> Node a -> FingerTree (Node a) #-}
snocTree :: Sized a => FingerTree a -> a -> FingerTree a
snocTree EmptyT a = Single a
snocTree (Single a) b = deep (One a) EmptyT (One b)
snocTree (Deep s pr m (Four a b c d)) e = m `seq`
	Deep (s + size e) pr (m `snocTree` node3 a b c) (Two d e)
snocTree (Deep s pr m (Three a b c)) d = Deep (s + size d) pr m (Four a b c d)
snocTree (Deep s pr m (Two a b)) c = Deep (s + size c) pr m (Three a b c)
snocTree (Deep s pr m (One a)) b = Deep (s + size b) pr m (Two a b)

data Digit a
	= One a
	| Two a a
	| Three a a a
	| Four a a a a
	deriving (Show, Eq, Ord)

foldDigit :: (b -> b -> b) -> (a -> b) -> Digit a -> b
foldDigit (<+>) f = \case
	One a -> f a
	Two a b -> f a <+> f b
	Three a b c -> f a <+> f b <+> f c
	Four a b c d -> f a <+> f b <+> f c <+> f d

instance Foldable Digit where
	foldMap = foldDigit mappend

	foldr f z = \case
		One a -> a `f` z
		Two a b -> a `f` (b `f` z)
		Three a b c -> a `f` (b `f` (c `f` z))
		Four a b c d -> a `f` (b `f` (c `f` (d `f` z)))
	{-# INLINE foldr #-}

	foldl f z = \case
		One a -> z `f` a
		Two a b -> (z `f` a) `f` b
		Three a b c -> ((z `f` a) `f` b) `f` c
		Four a b c d -> (((z `f` a) `f` b) `f` c) `f` d
	{-# INLINE foldl #-}

	foldr' f !z = \case
		One a -> f a z
		Two a b -> f a $! f b z
		Three a b c -> f a $! f b $! f c z
		Four a b c d -> f a $! f b $! f c $! f d z
	{-# INLINE foldr' #-}

	foldl' f !z = \case
		One a -> f z a
		Two a b -> (f $! f z a) b
		Three a b c -> (f $! (f $! f z a) b) c
		Four a b c d -> (f $! (f $! (f $! f z a) b) c) d
	{-# INLINE foldl' #-}

	foldr1 f = \case
		One a -> a
		Two a b -> a `f` b
		Three a b c -> a `f` (b `f` c)
		Four a b c d -> a `f` (b `f` (c `f` d))

	foldl1 f = \case
		One a -> a
		Two a b -> a `f` b
		Three a b c -> (a `f` b) `f` c
		Four a b c d -> ((a `f` b) `f` c) `f` d

instance Functor Digit where
	{-# INLINE fmap #-}
	fmap f = \case 
		One a -> One $ f a
		Two a b -> Two (f a) (f b)
		Three a b c -> Three (f a) (f b) (f c)
		Four a b c d -> Four (f a) (f b) (f c) (f d)

instance Sized a => Sized (Digit a) where
	{-# INLINE size #-}
	size = foldl1 (+) . fmap size

data Node a
	= Node2 {-# UNPACK #-} !Int a a
	| Node3 {-# UNPACK #-} !Int a a a
	deriving (Show, Eq, Ord)

foldNode :: (b -> b -> b) -> (a -> b) -> Node a -> b
foldNode (<+>) f (Node2 _ a b) = f a <+> f b
foldNode (<+>) f (Node3 _ a b c) = f a <+> f b <+> f c

instance Foldable Node where
	foldMap = foldNode mappend

	foldr f z = \case
		Node2 _ a b -> a `f` (b `f` z)
		Node3 _ a b c -> a `f` (b `f` (c `f` z))
	{-# INLINE foldr #-}

	foldl f z = \case
		Node2 _ a b -> (z `f` a) `f` b
		Node3 _ a b c -> ((z `f` a) `f` b) `f` c
	{-# INLINE foldl #-}

	foldr' f !z = \case
		Node2 _ a b -> f a $! f b z
		Node3 _ a b c -> f a $! f b $! f c z
	{-# INLINE foldr' #-}

	foldl' f !z = \case
		Node2 _ a b -> (f $! f z a) b
		Node3 _ a b c -> (f $! (f $! f z a) b) c

instance Functor Node where
	{-# INLINE fmap #-}
	fmap f = \case
		Node2 v a b -> Node2 v (f a) (f b)
		Node3 v a b c -> Node3 v (f a) (f b) (f c)

instance Sized (Node a) where
	size = \case Node2 v _ _ -> v; Node3 v _ _ _ -> v

{-# INLINE node2 #-}
node2 :: Sized a => a -> a -> Node a
node2 a b = Node2 (size a + size b) a b

{-# INLINE node3 #-}
node3 :: Sized a => a -> a -> a -> Node a
node3 a b c = Node3 (size a + size b + size c) a b c

{-# INLINE deep #-}

deep :: Sized a => Digit a -> FingerTree (Node a) -> Digit a -> FingerTree a
deep pr m sf = Deep (size pr + size m + size sf) pr m sf

deepL :: Sized a =>
	Maybe (Digit a) -> FingerTree (Node a) -> Digit a -> FingerTree a
deepL Nothing m sf = rotL m sf
deepL (Just pr) m sf = deep pr m sf

rotL :: Sized a => FingerTree (Node a) -> Digit a -> FingerTree a
rotL m sf = case viewl m of
	EmptyL -> digitToTree sf
	a :<. m' -> Deep (size m + size sf) (nodeToDigit a) m' sf

data ViewL s a = EmptyL | a :<. s a deriving (Eq, Ord, Show, Read, Generic)

viewl :: Sized a => FingerTree a -> ViewL FingerTree a
viewl EmptyT = EmptyL
viewl (Single x) = x :<. EmptyT
viewl (Deep _ (One x) m sf) = x :<. rotL m sf
viewl (Deep _ pr m sf) = lheadDigit pr :<. deep (ltailDigit pr) m sf

lheadDigit :: Digit a -> a
lheadDigit (One a) = a
lheadDigit (Two a _) = a
lheadDigit (Three a _ _) = a
lheadDigit (Four a _ _ _) = a

ltailDigit :: Digit a -> Digit a
ltailDigit (One _) = error "bad"
ltailDigit (Two _ b) = One b
ltailDigit (Three _ b c) = Two b c
ltailDigit (Four _ b c d) = Three b c d

deepR :: Sized a =>
	Digit a -> FingerTree (Node a) -> Maybe (Digit a) -> FingerTree a
deepR pr m Nothing = rotR pr m
deepR pr m (Just sf) = deep pr m sf

rotR :: Sized a => Digit a -> FingerTree (Node a) -> FingerTree a
rotR pr m = case viewr m of
	EmptyR -> digitToTree pr
	m' :>. a -> Deep (size pr + size m) pr m' (nodeToDigit a)

data ViewR s a = EmptyR | s a :>. a deriving (Eq, Ord, Show, Read, Generic)

viewr :: Sized a => FingerTree a -> ViewR FingerTree a
viewr EmptyT = EmptyR
viewr (Single x) = EmptyT :>. x
viewr (Deep _ pr m (One x)) = rotR pr m :>. x
viewr (Deep _ pr m sf) = deep pr m (rtailDigit sf) :>. rheadDigit sf

rheadDigit :: Digit a -> a
rheadDigit (One a) = a
rheadDigit (Two _ b) = b
rheadDigit (Three _ _ c) = c
rheadDigit (Four _ _ _ d) = d

rtailDigit :: Digit a -> Digit a
rtailDigit (One _) = error "bad"
rtailDigit (Two a _) = One a
rtailDigit (Three a b _) = Two a b
rtailDigit (Four a b c _) = Three a b c

nodeToDigit :: Node a -> Digit a
nodeToDigit (Node2 _ a b) = Two a b
nodeToDigit (Node3 _ a b c) = Three a b c

digitToTree :: Sized a => Digit a -> FingerTree a
digitToTree (One a) = Single a
digitToTree (Two a b) = deep (One a) EmptyT (One b)
digitToTree (Three a b c) = deep (Two a b) EmptyT (One c)
digitToTree (Four a b c d) = deep (Two a b) EmptyT (Two c d)

class Sized a where size :: a -> Int

instance Sized BS.ByteString where size = BS.length

-- The appendTree/addDigits gunk below was originally machine generated via mkappend.hs
-- but has since been manually edited to include strictness annotations.

appendTree0 :: FingerTree (BS.ByteString) -> FingerTree (BS.ByteString) -> FingerTree (BS.ByteString)
appendTree0 EmptyT xs =
     xs
appendTree0 xs EmptyT =
     xs
appendTree0 (Single x) xs =
     x `consTree` xs
appendTree0 xs (Single x) =
     xs `snocTree` x
appendTree0 (Deep s1 pr1 m1 sf1) (Deep s2 pr2 m2 sf2) =
     Deep (s1 + s2) pr1 m sf2
     where !m = addDigits0 m1 sf1 pr2 m2

addDigits0 :: FingerTree (Node (BS.ByteString)) -> Digit (BS.ByteString) -> Digit (BS.ByteString) -> FingerTree (Node (BS.ByteString)) -> FingerTree (Node (BS.ByteString))
addDigits0 m1 (One a) (One b) m2 =
    appendTree1 m1 (node2 a b) m2
addDigits0 m1 (One a) (Two b c) m2 =
    appendTree1 m1 (node3 a b c) m2
addDigits0 m1 (One a) (Three b c d) m2 =
    appendTree2 m1 (node2 a b) (node2 c d) m2
addDigits0 m1 (One a) (Four b c d e) m2 =
    appendTree2 m1 (node3 a b c) (node2 d e) m2
addDigits0 m1 (Two a b) (One c) m2 =
    appendTree1 m1 (node3 a b c) m2
addDigits0 m1 (Two a b) (Two c d) m2 =
    appendTree2 m1 (node2 a b) (node2 c d) m2
addDigits0 m1 (Two a b) (Three c d e) m2 =
    appendTree2 m1 (node3 a b c) (node2 d e) m2
addDigits0 m1 (Two a b) (Four c d e f) m2 =
    appendTree2 m1 (node3 a b c) (node3 d e f) m2
addDigits0 m1 (Three a b c) (One d) m2 =
    appendTree2 m1 (node2 a b) (node2 c d) m2
addDigits0 m1 (Three a b c) (Two d e) m2 =
    appendTree2 m1 (node3 a b c) (node2 d e) m2
addDigits0 m1 (Three a b c) (Three d e f) m2 =
    appendTree2 m1 (node3 a b c) (node3 d e f) m2
addDigits0 m1 (Three a b c) (Four d e f g) m2 =
    appendTree3 m1 (node3 a b c) (node2 d e) (node2 f g) m2
addDigits0 m1 (Four a b c d) (One e) m2 =
    appendTree2 m1 (node3 a b c) (node2 d e) m2
addDigits0 m1 (Four a b c d) (Two e f) m2 =
    appendTree2 m1 (node3 a b c) (node3 d e f) m2
addDigits0 m1 (Four a b c d) (Three e f g) m2 =
    appendTree3 m1 (node3 a b c) (node2 d e) (node2 f g) m2
addDigits0 m1 (Four a b c d) (Four e f g h) m2 =
    appendTree3 m1 (node3 a b c) (node3 d e f) (node2 g h) m2

appendTree1 :: FingerTree (Node a) -> Node a -> FingerTree (Node a) -> FingerTree (Node a)
appendTree1 EmptyT !a xs =
     a `consTree` xs
appendTree1 xs !a EmptyT =
     xs `snocTree` a
appendTree1 (Single x) !a xs =
     x `consTree` a `consTree` xs
appendTree1 xs !a (Single x) =
     xs `snocTree` a `snocTree` x
appendTree1 (Deep s1 pr1 m1 sf1) a (Deep s2 pr2 m2 sf2) =
     Deep (s1 + size a + s2) pr1 m sf2
     where !m = addDigits1 m1 sf1 a pr2 m2

addDigits1 :: FingerTree (Node (Node a)) -> Digit (Node a) -> Node a -> Digit (Node a) -> FingerTree (Node (Node a)) -> FingerTree (Node (Node a))
addDigits1 m1 (One a) b (One c) m2 =
    appendTree1 m1 (node3 a b c) m2
addDigits1 m1 (One a) b (Two c d) m2 =
    appendTree2 m1 (node2 a b) (node2 c d) m2
addDigits1 m1 (One a) b (Three c d e) m2 =
    appendTree2 m1 (node3 a b c) (node2 d e) m2
addDigits1 m1 (One a) b (Four c d e f) m2 =
    appendTree2 m1 (node3 a b c) (node3 d e f) m2
addDigits1 m1 (Two a b) c (One d) m2 =
    appendTree2 m1 (node2 a b) (node2 c d) m2
addDigits1 m1 (Two a b) c (Two d e) m2 =
    appendTree2 m1 (node3 a b c) (node2 d e) m2
addDigits1 m1 (Two a b) c (Three d e f) m2 =
    appendTree2 m1 (node3 a b c) (node3 d e f) m2
addDigits1 m1 (Two a b) c (Four d e f g) m2 =
    appendTree3 m1 (node3 a b c) (node2 d e) (node2 f g) m2
addDigits1 m1 (Three a b c) d (One e) m2 =
    appendTree2 m1 (node3 a b c) (node2 d e) m2
addDigits1 m1 (Three a b c) d (Two e f) m2 =
    appendTree2 m1 (node3 a b c) (node3 d e f) m2
addDigits1 m1 (Three a b c) d (Three e f g) m2 =
    appendTree3 m1 (node3 a b c) (node2 d e) (node2 f g) m2
addDigits1 m1 (Three a b c) d (Four e f g h) m2 =
    appendTree3 m1 (node3 a b c) (node3 d e f) (node2 g h) m2
addDigits1 m1 (Four a b c d) e (One f) m2 =
    appendTree2 m1 (node3 a b c) (node3 d e f) m2
addDigits1 m1 (Four a b c d) e (Two f g) m2 =
    appendTree3 m1 (node3 a b c) (node2 d e) (node2 f g) m2
addDigits1 m1 (Four a b c d) e (Three f g h) m2 =
    appendTree3 m1 (node3 a b c) (node3 d e f) (node2 g h) m2
addDigits1 m1 (Four a b c d) e (Four f g h i) m2 =
    appendTree3 m1 (node3 a b c) (node3 d e f) (node3 g h i) m2

appendTree2 :: FingerTree (Node a) -> Node a -> Node a -> FingerTree (Node a) -> FingerTree (Node a)
appendTree2 EmptyT !a !b xs =
     a `consTree` b `consTree` xs
appendTree2 xs !a !b EmptyT =
     xs `snocTree` a `snocTree` b
appendTree2 (Single x) a b xs =
     x `consTree` a `consTree` b `consTree` xs
appendTree2 xs a b (Single x) =
     xs `snocTree` a `snocTree` b `snocTree` x
appendTree2 (Deep s1 pr1 m1 sf1) a b (Deep s2 pr2 m2 sf2) =
     Deep (s1 + size a + size b + s2) pr1 m sf2
     where !m = addDigits2 m1 sf1 a b pr2 m2

addDigits2 :: FingerTree (Node (Node a)) -> Digit (Node a) -> Node a -> Node a -> Digit (Node a) -> FingerTree (Node (Node a)) -> FingerTree (Node (Node a))
addDigits2 m1 (One a) b c (One d) m2 =
    appendTree2 m1 (node2 a b) (node2 c d) m2
addDigits2 m1 (One a) b c (Two d e) m2 =
    appendTree2 m1 (node3 a b c) (node2 d e) m2
addDigits2 m1 (One a) b c (Three d e f) m2 =
    appendTree2 m1 (node3 a b c) (node3 d e f) m2
addDigits2 m1 (One a) b c (Four d e f g) m2 =
    appendTree3 m1 (node3 a b c) (node2 d e) (node2 f g) m2
addDigits2 m1 (Two a b) c d (One e) m2 =
    appendTree2 m1 (node3 a b c) (node2 d e) m2
addDigits2 m1 (Two a b) c d (Two e f) m2 =
    appendTree2 m1 (node3 a b c) (node3 d e f) m2
addDigits2 m1 (Two a b) c d (Three e f g) m2 =
    appendTree3 m1 (node3 a b c) (node2 d e) (node2 f g) m2
addDigits2 m1 (Two a b) c d (Four e f g h) m2 =
    appendTree3 m1 (node3 a b c) (node3 d e f) (node2 g h) m2
addDigits2 m1 (Three a b c) d e (One f) m2 =
    appendTree2 m1 (node3 a b c) (node3 d e f) m2
addDigits2 m1 (Three a b c) d e (Two f g) m2 =
    appendTree3 m1 (node3 a b c) (node2 d e) (node2 f g) m2
addDigits2 m1 (Three a b c) d e (Three f g h) m2 =
    appendTree3 m1 (node3 a b c) (node3 d e f) (node2 g h) m2
addDigits2 m1 (Three a b c) d e (Four f g h i) m2 =
    appendTree3 m1 (node3 a b c) (node3 d e f) (node3 g h i) m2
addDigits2 m1 (Four a b c d) e f (One g) m2 =
    appendTree3 m1 (node3 a b c) (node2 d e) (node2 f g) m2
addDigits2 m1 (Four a b c d) e f (Two g h) m2 =
    appendTree3 m1 (node3 a b c) (node3 d e f) (node2 g h) m2
addDigits2 m1 (Four a b c d) e f (Three g h i) m2 =
    appendTree3 m1 (node3 a b c) (node3 d e f) (node3 g h i) m2
addDigits2 m1 (Four a b c d) e f (Four g h i j) m2 =
    appendTree4 m1 (node3 a b c) (node3 d e f) (node2 g h) (node2 i j) m2

appendTree3 :: FingerTree (Node a) -> Node a -> Node a -> Node a -> FingerTree (Node a) -> FingerTree (Node a)
appendTree3 EmptyT !a !b !c xs =
     a `consTree` b `consTree` c `consTree` xs
appendTree3 xs !a !b !c EmptyT =
     xs `snocTree` a `snocTree` b `snocTree` c
appendTree3 (Single x) a b c xs =
     x `consTree` a `consTree` b `consTree` c `consTree` xs
appendTree3 xs a b c (Single x) =
     xs `snocTree` a `snocTree` b `snocTree` c `snocTree` x
appendTree3 (Deep s1 pr1 m1 sf1) a b c (Deep s2 pr2 m2 sf2) =
     Deep (s1 + size a + size b + size c + s2) pr1 m sf2
     where !m = addDigits3 m1 sf1 a b c pr2 m2

addDigits3 :: FingerTree (Node (Node a)) -> Digit (Node a) -> Node a -> Node a -> Node a -> Digit (Node a) -> FingerTree (Node (Node a)) -> FingerTree (Node (Node a))
addDigits3 m1 (One a) b c d (One e) m2 =
    appendTree2 m1 (node3 a b c) (node2 d e) m2
addDigits3 m1 (One a) b c d (Two e f) m2 =
    appendTree2 m1 (node3 a b c) (node3 d e f) m2
addDigits3 m1 (One a) b c d (Three e f g) m2 =
    appendTree3 m1 (node3 a b c) (node2 d e) (node2 f g) m2
addDigits3 m1 (One a) b c d (Four e f g h) m2 =
    appendTree3 m1 (node3 a b c) (node3 d e f) (node2 g h) m2
addDigits3 m1 (Two a b) c d e (One f) m2 =
    appendTree2 m1 (node3 a b c) (node3 d e f) m2
addDigits3 m1 (Two a b) c d e (Two f g) m2 =
    appendTree3 m1 (node3 a b c) (node2 d e) (node2 f g) m2
addDigits3 m1 (Two a b) c d e (Three f g h) m2 =
    appendTree3 m1 (node3 a b c) (node3 d e f) (node2 g h) m2
addDigits3 m1 (Two a b) c d e (Four f g h i) m2 =
    appendTree3 m1 (node3 a b c) (node3 d e f) (node3 g h i) m2
addDigits3 m1 (Three a b c) d e f (One g) m2 =
    appendTree3 m1 (node3 a b c) (node2 d e) (node2 f g) m2
addDigits3 m1 (Three a b c) d e f (Two g h) m2 =
    appendTree3 m1 (node3 a b c) (node3 d e f) (node2 g h) m2
addDigits3 m1 (Three a b c) d e f (Three g h i) m2 =
    appendTree3 m1 (node3 a b c) (node3 d e f) (node3 g h i) m2
addDigits3 m1 (Three a b c) d e f (Four g h i j) m2 =
    appendTree4 m1 (node3 a b c) (node3 d e f) (node2 g h) (node2 i j) m2
addDigits3 m1 (Four a b c d) e f g (One h) m2 =
    appendTree3 m1 (node3 a b c) (node3 d e f) (node2 g h) m2
addDigits3 m1 (Four a b c d) e f g (Two h i) m2 =
    appendTree3 m1 (node3 a b c) (node3 d e f) (node3 g h i) m2
addDigits3 m1 (Four a b c d) e f g (Three h i j) m2 =
    appendTree4 m1 (node3 a b c) (node3 d e f) (node2 g h) (node2 i j) m2
addDigits3 m1 (Four a b c d) e f g (Four h i j k) m2 =
    appendTree4 m1 (node3 a b c) (node3 d e f) (node3 g h i) (node2 j k) m2

appendTree4 :: FingerTree (Node a) -> Node a -> Node a -> Node a -> Node a -> FingerTree (Node a) -> FingerTree (Node a)
appendTree4 EmptyT !a !b !c !d xs =
     a `consTree` b `consTree` c `consTree` d `consTree` xs
appendTree4 xs !a !b !c !d EmptyT =
     xs `snocTree` a `snocTree` b `snocTree` c `snocTree` d
appendTree4 (Single x) a b c d xs =
     x `consTree` a `consTree` b `consTree` c `consTree` d `consTree` xs
appendTree4 xs a b c d (Single x) =
     xs `snocTree` a `snocTree` b `snocTree` c `snocTree` d `snocTree` x
appendTree4 (Deep s1 pr1 m1 sf1) a b c d (Deep s2 pr2 m2 sf2) =
     Deep (s1 + size a + size b + size c + size d + s2) pr1 m sf2
     where !m = addDigits4 m1 sf1 a b c d pr2 m2

addDigits4 :: FingerTree (Node (Node a)) -> Digit (Node a) -> Node a -> Node a -> Node a -> Node a -> Digit (Node a) -> FingerTree (Node (Node a)) -> FingerTree (Node (Node a))
addDigits4 m1 (One a) b c d e (One f) m2 =
    appendTree2 m1 (node3 a b c) (node3 d e f) m2
addDigits4 m1 (One a) b c d e (Two f g) m2 =
    appendTree3 m1 (node3 a b c) (node2 d e) (node2 f g) m2
addDigits4 m1 (One a) b c d e (Three f g h) m2 =
    appendTree3 m1 (node3 a b c) (node3 d e f) (node2 g h) m2
addDigits4 m1 (One a) b c d e (Four f g h i) m2 =
    appendTree3 m1 (node3 a b c) (node3 d e f) (node3 g h i) m2
addDigits4 m1 (Two a b) c d e f (One g) m2 =
    appendTree3 m1 (node3 a b c) (node2 d e) (node2 f g) m2
addDigits4 m1 (Two a b) c d e f (Two g h) m2 =
    appendTree3 m1 (node3 a b c) (node3 d e f) (node2 g h) m2
addDigits4 m1 (Two a b) c d e f (Three g h i) m2 =
    appendTree3 m1 (node3 a b c) (node3 d e f) (node3 g h i) m2
addDigits4 m1 (Two a b) c d e f (Four g h i j) m2 =
    appendTree4 m1 (node3 a b c) (node3 d e f) (node2 g h) (node2 i j) m2
addDigits4 m1 (Three a b c) d e f g (One h) m2 =
    appendTree3 m1 (node3 a b c) (node3 d e f) (node2 g h) m2
addDigits4 m1 (Three a b c) d e f g (Two h i) m2 =
    appendTree3 m1 (node3 a b c) (node3 d e f) (node3 g h i) m2
addDigits4 m1 (Three a b c) d e f g (Three h i j) m2 =
    appendTree4 m1 (node3 a b c) (node3 d e f) (node2 g h) (node2 i j) m2
addDigits4 m1 (Three a b c) d e f g (Four h i j k) m2 =
    appendTree4 m1 (node3 a b c) (node3 d e f) (node3 g h i) (node2 j k) m2
addDigits4 m1 (Four a b c d) e f g h (One i) m2 =
    appendTree3 m1 (node3 a b c) (node3 d e f) (node3 g h i) m2
addDigits4 m1 (Four a b c d) e f g h (Two i j) m2 =
    appendTree4 m1 (node3 a b c) (node3 d e f) (node2 g h) (node2 i j) m2
addDigits4 m1 (Four a b c d) e f g h (Three i j k) m2 =
    appendTree4 m1 (node3 a b c) (node3 d e f) (node3 g h i) (node2 j k) m2
addDigits4 m1 (Four a b c d) e f g h (Four i j k l) m2 =
    appendTree4 m1 (node3 a b c) (node3 d e f) (node3 g h i) (node3 j k l) m2

type instance Element ByteString = Word8

instance MonoFunctor ByteString where
	omap f = \case
		Empty -> Empty
		bs :<| bss -> (f `BS.map` bs) :<| (f `omap` bss)

instance MonoFoldable ByteString where
	ofoldMap c = \case
		Empty -> mempty
		b :< bs -> c b `mappend` (c `ofoldMap` bs)
	ofoldr op v = \case
		Empty -> v
		b :< bs -> b `op` ofoldr op v bs
	ofoldl' op !v = \case
		Empty -> v
		b :< bs -> ofoldl' op (v `op` b) bs
	ofoldr1Ex op = \case
		Empty -> error "bad"
		b :< Empty -> b
		b :< bs -> b `op` ofoldr1Ex op bs
	ofoldl1Ex' op = \case
		Empty -> error "bad"
		b :< bs -> ofoldl' op b bs

instance MonoTraversable ByteString where
	otraverse f = \case
		Empty -> pure Empty
		b :< bs -> (:<) <$> f b <*> f `otraverse` bs