module Data.Text.Internal.Fusion.Size
(
Size
, exactly
, exactSize
, maxSize
, unknownSize
, smaller
, larger
, upperBound
, isEmpty
) where
#if defined(ASSERTS)
import Control.Exception (assert)
#endif
data Size = Exact !Int
| Max !Int
| Unknown
deriving (Eq, Show)
exactly :: Size -> Maybe Int
exactly (Exact n) = Just n
exactly _ = Nothing
exactSize :: Int -> Size
exactSize n =
#if defined(ASSERTS)
assert (n >= 0)
#endif
Exact n
maxSize :: Int -> Size
maxSize n =
#if defined(ASSERTS)
assert (n >= 0)
#endif
Max n
unknownSize :: Size
unknownSize = Unknown
instance Num Size where
(+) = addSize
() = subtractSize
(*) = mulSize
fromInteger = f where f = Exact . fromInteger
add :: Int -> Int -> Int
add m n | mn >= 0 = mn
| otherwise = overflowError
where mn = m + n
addSize :: Size -> Size -> Size
addSize (Exact m) (Exact n) = Exact (add m n)
addSize (Exact m) (Max n) = Max (add m n)
addSize (Max m) (Exact n) = Max (add m n)
addSize (Max m) (Max n) = Max (add m n)
addSize _ _ = Unknown
subtractSize :: Size -> Size -> Size
subtractSize (Exact m) (Exact n) = Exact (max (mn) 0)
subtractSize (Exact m) (Max _) = Max m
subtractSize (Max m) (Exact n) = Max (max (mn) 0)
subtractSize a@(Max _) (Max _) = a
subtractSize a@(Max _) Unknown = a
subtractSize _ _ = Unknown
mul :: Int -> Int -> Int
mul m n
| m <= maxBound `quot` n = m * n
| otherwise = overflowError
mulSize :: Size -> Size -> Size
mulSize (Exact m) (Exact n) = Exact (mul m n)
mulSize (Exact m) (Max n) = Max (mul m n)
mulSize (Max m) (Exact n) = Max (mul m n)
mulSize (Max m) (Max n) = Max (mul m n)
mulSize _ _ = Unknown
smaller :: Size -> Size -> Size
smaller (Exact m) (Exact n) = Exact (m `min` n)
smaller (Exact m) (Max n) = Max (m `min` n)
smaller (Exact m) Unknown = Max m
smaller (Max m) (Exact n) = Max (m `min` n)
smaller (Max m) (Max n) = Max (m `min` n)
smaller a@(Max _) Unknown = a
smaller Unknown (Exact n) = Max n
smaller Unknown (Max n) = Max n
smaller Unknown Unknown = Unknown
larger :: Size -> Size -> Size
larger (Exact m) (Exact n) = Exact (m `max` n)
larger a@(Exact m) b@(Max n) | m >= n = a
| otherwise = b
larger a@(Max m) b@(Exact n) | n >= m = b
| otherwise = a
larger (Max m) (Max n) = Max (m `max` n)
larger _ _ = Unknown
upperBound :: Int -> Size -> Int
upperBound _ (Exact n) = n
upperBound _ (Max n) = n
upperBound k _ = k
isEmpty :: Size -> Bool
isEmpty (Exact n) = n <= 0
isEmpty (Max n) = n <= 0
isEmpty _ = False
overflowError :: Int
overflowError = error "Data.Text.Internal.Fusion.Size: size overflow"