{-# LANGUAGE CPP #-}
{-# OPTIONS_GHC -fno-warn-missing-methods #-}
module Data.Text.Internal.Fusion.Size
    (
      Size
      
    , exactSize
    , maxSize
    , betweenSize
    , unknownSize
    , unionSize
    , charSize
    , codePointsSize
      
    , exactly
    , smaller
    , larger
    , upperBound
    , lowerBound
    , compareSize
    , isEmpty
    ) where
import Data.Char (ord)
import Data.Text.Internal (mul)
#if defined(ASSERTS)
import Control.Exception (assert)
#endif
data Size = Between {-# UNPACK #-} !Int {-# UNPACK #-} !Int 
          | Unknown                                         
            deriving (Size -> Size -> Bool
(Size -> Size -> Bool) -> (Size -> Size -> Bool) -> Eq Size
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Size -> Size -> Bool
$c/= :: Size -> Size -> Bool
== :: Size -> Size -> Bool
$c== :: Size -> Size -> Bool
Eq, Int -> Size -> ShowS
[Size] -> ShowS
Size -> String
(Int -> Size -> ShowS)
-> (Size -> String) -> ([Size] -> ShowS) -> Show Size
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Size] -> ShowS
$cshowList :: [Size] -> ShowS
show :: Size -> String
$cshow :: Size -> String
showsPrec :: Int -> Size -> ShowS
$cshowsPrec :: Int -> Size -> ShowS
Show)
exactly :: Size -> Maybe Int
exactly :: Size -> Maybe Int
exactly (Between Int
na Int
nb) | Int
na Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
nb = Int -> Maybe Int
forall a. a -> Maybe a
Just Int
na
exactly Size
_ = Maybe Int
forall a. Maybe a
Nothing
{-# INLINE exactly #-}
charSize :: Char -> Size
charSize :: Char -> Size
charSize Char
c
  | Char -> Int
ord Char
c Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
0x10000 = Int -> Size
exactSize Int
1
  | Bool
otherwise       = Int -> Size
exactSize Int
2
codePointsSize :: Int -> Size
codePointsSize :: Int -> Size
codePointsSize Int
n =
#if defined(ASSERTS)
    assert (n >= 0)
#endif
    Int -> Int -> Size
Between Int
n (Int
2Int -> Int -> Int
forall a. Num a => a -> a -> a
*Int
n)
{-# INLINE codePointsSize #-}
exactSize :: Int -> Size
exactSize :: Int -> Size
exactSize Int
n =
#if defined(ASSERTS)
    assert (n >= 0)
#endif
    Int -> Int -> Size
Between Int
n Int
n
{-# INLINE exactSize #-}
maxSize :: Int -> Size
maxSize :: Int -> Size
maxSize Int
n =
#if defined(ASSERTS)
    assert (n >= 0)
#endif
    Int -> Int -> Size
Between Int
0 Int
n
{-# INLINE maxSize #-}
betweenSize :: Int -> Int -> Size
betweenSize :: Int -> Int -> Size
betweenSize Int
m Int
n =
#if defined(ASSERTS)
    assert (m >= 0)
    assert (n >= m)
#endif
    Int -> Int -> Size
Between Int
m Int
n
{-# INLINE betweenSize #-}
unionSize :: Size -> Size -> Size
unionSize :: Size -> Size -> Size
unionSize (Between Int
a Int
b) (Between Int
c Int
d) = Int -> Int -> Size
Between (Int -> Int -> Int
forall a. Ord a => a -> a -> a
min Int
a Int
c) (Int -> Int -> Int
forall a. Ord a => a -> a -> a
max Int
b Int
d)
unionSize Size
_ Size
_ = Size
Unknown
unknownSize :: Size
unknownSize :: Size
unknownSize = Size
Unknown
{-# INLINE unknownSize #-}
instance Num Size where
    + :: Size -> Size -> Size
(+) = Size -> Size -> Size
addSize
    (-) = Size -> Size -> Size
subtractSize
    * :: Size -> Size -> Size
(*) = Size -> Size -> Size
mulSize
    fromInteger :: Integer -> Size
fromInteger = Integer -> Size
f where f :: Integer -> Size
f = Int -> Size
exactSize (Int -> Size) -> (Integer -> Int) -> Integer -> Size
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Integer -> Int
forall a. Num a => Integer -> a
fromInteger
                          {-# INLINE f #-}
add :: Int -> Int -> Int
add :: Int -> Int -> Int
add Int
m Int
n | Int
mn Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>=   Int
0 = Int
mn
        | Bool
otherwise = Int
overflowError
  where mn :: Int
mn = Int
m Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
n
{-# INLINE add #-}
addSize :: Size -> Size -> Size
addSize :: Size -> Size -> Size
addSize (Between Int
ma Int
mb) (Between Int
na Int
nb) = Int -> Int -> Size
Between (Int -> Int -> Int
add Int
ma Int
na) (Int -> Int -> Int
add Int
mb Int
nb)
addSize Size
_               Size
_               = Size
Unknown
{-# INLINE addSize #-}
subtractSize :: Size -> Size -> Size
subtractSize :: Size -> Size -> Size
subtractSize (Between Int
ma Int
mb) (Between Int
na Int
nb) = Int -> Int -> Size
Between (Int -> Int -> Int
forall a. Ord a => a -> a -> a
max (Int
maInt -> Int -> Int
forall a. Num a => a -> a -> a
-Int
nb) Int
0) (Int -> Int -> Int
forall a. Ord a => a -> a -> a
max (Int
mbInt -> Int -> Int
forall a. Num a => a -> a -> a
-Int
na) Int
0)
subtractSize a :: Size
a@(Between Int
0 Int
_) Size
Unknown         = Size
a
subtractSize (Between Int
_ Int
mb)  Size
Unknown         = Int -> Int -> Size
Between Int
0 Int
mb
subtractSize Size
_               Size
_               = Size
Unknown
{-# INLINE subtractSize #-}
mulSize :: Size -> Size -> Size
mulSize :: Size -> Size -> Size
mulSize (Between Int
ma Int
mb) (Between Int
na Int
nb) = Int -> Int -> Size
Between (Int -> Int -> Int
mul Int
ma Int
na) (Int -> Int -> Int
mul Int
mb Int
nb)
mulSize Size
_               Size
_               = Size
Unknown
{-# INLINE mulSize #-}
smaller :: Size -> Size -> Size
smaller :: Size -> Size -> Size
smaller a :: Size
a@(Between Int
ma Int
mb) b :: Size
b@(Between Int
na Int
nb)
    | Int
mb Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
na  = Size
a
    | Int
nb Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
ma  = Size
b
    | Bool
otherwise = Int -> Int -> Size
Between (Int
ma Int -> Int -> Int
forall a. Ord a => a -> a -> a
`min` Int
na) (Int
mb Int -> Int -> Int
forall a. Ord a => a -> a -> a
`min` Int
nb)
smaller a :: Size
a@(Between Int
0 Int
_) Size
Unknown         = Size
a
smaller (Between Int
_ Int
mb)  Size
Unknown         = Int -> Int -> Size
Between Int
0 Int
mb
smaller Size
Unknown         b :: Size
b@(Between Int
0 Int
_) = Size
b
smaller Size
Unknown         (Between Int
_ Int
nb)  = Int -> Int -> Size
Between Int
0 Int
nb
smaller Size
Unknown         Size
Unknown         = Size
Unknown
{-# INLINE smaller #-}
larger :: Size -> Size -> Size
larger :: Size -> Size -> Size
larger a :: Size
a@(Between Int
ma Int
mb) b :: Size
b@(Between Int
na Int
nb)
    | Int
ma Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
nb  = Size
a
    | Int
na Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
mb  = Size
b
    | Bool
otherwise = Int -> Int -> Size
Between (Int
ma Int -> Int -> Int
forall a. Ord a => a -> a -> a
`max` Int
na) (Int
mb Int -> Int -> Int
forall a. Ord a => a -> a -> a
`max` Int
nb)
larger Size
_ Size
_ = Size
Unknown
{-# INLINE larger #-}
upperBound :: Int -> Size -> Int
upperBound :: Int -> Size -> Int
upperBound Int
_ (Between Int
_ Int
n) = Int
n
upperBound Int
k Size
_             = Int
k
{-# INLINE upperBound #-}
lowerBound :: Int -> Size -> Int
lowerBound :: Int -> Size -> Int
lowerBound Int
_ (Between Int
n Int
_) = Int
n
lowerBound Int
k Size
_             = Int
k
{-# INLINE lowerBound #-}
compareSize :: Size -> Size -> Maybe Ordering
compareSize :: Size -> Size -> Maybe Ordering
compareSize (Between Int
ma Int
mb) (Between Int
na Int
nb)
  | Int
mb Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
na            = Ordering -> Maybe Ordering
forall a. a -> Maybe a
Just Ordering
LT
  | Int
ma Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
nb            = Ordering -> Maybe Ordering
forall a. a -> Maybe a
Just Ordering
GT
  | Int
ma Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
mb
  , Int
ma Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
na
  , Int
ma Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
nb           = Ordering -> Maybe Ordering
forall a. a -> Maybe a
Just Ordering
EQ
compareSize Size
_ Size
_        = Maybe Ordering
forall a. Maybe a
Nothing
isEmpty :: Size -> Bool
isEmpty :: Size -> Bool
isEmpty (Between Int
_ Int
n) = Int
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
0
isEmpty Size
_             = Bool
False
{-# INLINE isEmpty #-}
overflowError :: Int
overflowError :: Int
overflowError = String -> Int
forall a. HasCallStack => String -> a
error String
"Data.Text.Internal.Fusion.Size: size overflow"