@@ -22,10 +22,12 @@ module Data.Text.Internal.Fusion.Size
2222 , exactly
2323 , exactSize
2424 , maxSize
25+ , betweenSize
2526 , unknownSize
2627 , smaller
2728 , larger
2829 , upperBound
30+ , lowerBound
2931 , isEmpty
3032 ) where
3133
@@ -33,14 +35,13 @@ module Data.Text.Internal.Fusion.Size
3335import Control.Exception (assert)
3436#endif
3537
36−data Size = Exact {-# UNPACK #-} !Int -- ^ Exact size.
37− | Max {-# UNPACK #-} !Int -- ^ Upper bound on size.
38− | Unknown -- ^ Unknown size.
38+data Size = Between {-# UNPACK #-} !Int {-# UNPACK #-} !Int -- ^ Lower and upper bounds on size.
39+ | Unknown -- ^ Unknown size.
3940 deriving (Eq, Show)
4041
4142exactly :: Size -> Maybe Int
42−exactly (Exact n) = Just n
43−exactly _ = Nothing
43+exactly (Between na nb) | na == nb = Just na
44+exactly _ = Nothing
4445{-# INLINE exactly #-}
4546
4647exactSize :: Int -> Size
@@ -48,7 +49,7 @@ exactSize n =
4849#if defined(ASSERTS)
4950 assert (n >= 0)
5051#endif
51− Exact n
52+ Between n n
5253{-# INLINE exactSize #-}
5354
5455maxSize :: Int -> Size
@@ -56,9 +57,18 @@ maxSize n =
5657#if defined(ASSERTS)
5758 assert (n >= 0)
5859#endif
59− Max n
60+ Between 0 n
6061{-# INLINE maxSize #-}
6162
63+betweenSize :: Int -> Int -> Size
64+betweenSize m n =
65+#if defined(ASSERTS)
66+ assset (m >= 0)
67+ assert (n >= m)
68+#endif
69+ Between m n
70+{-# INLINE betweenSize #-}
71+
6272unknownSize :: Size
6373unknownSize = Unknown
6474{-# INLINE unknownSize #-}
@@ -68,7 +78,7 @@ instance Num Size where
6878 (-) = subtractSize
6979 (*) = mulSize
7080
71− fromInteger = f where f = Exact . fromInteger
81+ fromInteger = f where f = exactSize . fromInteger
7282 {-# INLINE f #-}
7383
7484add :: Int -> Int -> Int
@@ -78,20 +88,15 @@ add m n | mn >= 0 = mn
7888{-# INLINE add #-}
7989
8090addSize :: Size -> Size -> Size
81−addSize (Exact m) (Exact n) = Exact (add m n)
82−addSize (Exact m) (Max n) = Max (add m n)
83−addSize (Max m) (Exact n) = Max (add m n)
84−addSize (Max m) (Max n) = Max (add m n)
85−addSize _ _ = Unknown
91+addSize (Between ma mb) (Between na nb) = Between (add ma na) (add mb nb)
92+addSize _ _ = Unknown
8693{-# INLINE addSize #-}
8794
8895subtractSize :: Size -> Size -> Size
89−subtractSize (Exact m) (Exact n) = Exact (max (m-n) 0)
90−subtractSize (Exact m) (Max _) = Max m
91−subtractSize (Max m) (Exact n) = Max (max (m-n) 0)
92−subtractSize a@(Max _) (Max _) = a
93−subtractSize a@(Max _) Unknown = a
94−subtractSize _ _ = Unknown
96+subtractSize (Between ma mb) (Between na nb) = Between (max (ma-nb) 0) (max (mb-na) 0)
97+subtractSize a@(Between 0 _) Unknown = a
98+subtractSize (Between _ mb) Unknown = Between 0 mb
99+subtractSize _ _ = Unknown
95100{-# INLINE subtractSize #-}
96101
97102mul :: Int -> Int -> Int
@@ -101,48 +106,47 @@ mul m n
101106{-# INLINE mul #-}
102107
103108mulSize :: Size -> Size -> Size
104−mulSize (Exact m) (Exact n) = Exact (mul m n)
105−mulSize (Exact m) (Max n) = Max (mul m n)
106−mulSize (Max m) (Exact n) = Max (mul m n)
107−mulSize (Max m) (Max n) = Max (mul m n)
108−mulSize _ _ = Unknown
109+mulSize (Between ma mb) (Between na nb) = Between (mul ma na) (mul mb nb)
110+mulSize _ _ = Unknown
109111{-# INLINE mulSize #-}
110112
111113-- | Minimum of two size hints.
112114smaller :: Size -> Size -> Size
113−smaller (Exact m) (Exact n) = Exact (m `min` n)
114−smaller (Exact m) (Max n) = Max (m `min` n)
115−smaller (Exact m) Unknown = Max m
116−smaller (Max m) (Exact n) = Max (m `min` n)
117−smaller (Max m) (Max n) = Max (m `min` n)
118−smaller a@(Max _) Unknown = a
119−smaller Unknown (Exact n) = Max n
120−smaller Unknown (Max n) = Max n
121−smaller Unknown Unknown = Unknown
115+smaller a@(Between ma mb) b@(Between na nb)
116+ | mb <= na = a
117+ | nb <= ma = b
118+ | otherwise = Between (ma `min` na) (mb `min` nb)
119+smaller a@(Between 0 _) Unknown = a
120+smaller (Between _ mb) Unknown = Between 0 mb
121+smaller Unknown b@(Between 0 _) = b
122+smaller Unknown (Between _ nb) = Between 0 nb
123+smaller Unknown Unknown = Unknown
122124{-# INLINE smaller #-}
123125
124126-- | Maximum of two size hints.
125127larger :: Size -> Size -> Size
126−larger (Exact m) (Exact n) = Exact (m `max` n)
127−larger a@(Exact m) b@(Max n) | m >= n = a
128− | otherwise = b
129−larger a@(Max m) b@(Exact n) | n >= m = b
130− | otherwise = a
131−larger (Max m) (Max n) = Max (m `max` n)
132−larger _ _ = Unknown
128+larger a@(Between ma mb) b@(Between na nb)
129+ | ma >= nb = a
130+ | na >= mb = b
131+ | otherwise = Between (ma `max` na) (mb `max` nb)
132+larger _ _ = Unknown
133133{-# INLINE larger #-}
134134
135135-- | Compute the maximum size from a size hint, if possible.
136136upperBound :: Int -> Size -> Int
137−upperBound _ (Exact n) = n
138−upperBound _ (Max n) = n
139−upperBound k _ = k
137+upperBound _ (Between n _) = n
138+upperBound k _ = k
140139{-# INLINE upperBound #-}
141140
141+-- | Compute the maximum size from a size hint, if possible.
142+lowerBound :: Int -> Size -> Int
143+lowerBound _ (Between n _) = n
144+lowerBound k _ = k
145+{-# INLINE lowerBound #-}
146+
142147isEmpty :: Size -> Bool
143−isEmpty (Exact n) = n <= 0
144−isEmpty (Max n) = n <= 0
145−isEmpty _ = False
148+isEmpty (Between _ n) = n <= 0
149+isEmpty _ = False
146150{-# INLINE isEmpty #-}
147151
148152overflowError :: Int