{-# LANGUAGE DeriveAnyClass, DeriveGeneric, RankNTypes, NamedFieldPuns #-}
module Source.Range
( Range(..)
, point
, rangeLength
, subtractRange
  -- * Lenses
, start_
, end_
) where

import Control.DeepSeq (NFData)
import Data.Aeson (ToJSON(..))
import Data.Hashable (Hashable)
import Data.Semilattice.Lower (Lower(..))
import GHC.Generics (Generic)

-- | A 0-indexed, half-open interval of integers, defined by start & end indices.
data Range = Range
  { Range -> Int
start :: {-# UNPACK #-} !Int
  , Range -> Int
end   :: {-# UNPACK #-} !Int
  }
  deriving (Range -> Range -> Bool
(Range -> Range -> Bool) -> (Range -> Range -> Bool) -> Eq Range
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Range -> Range -> Bool
$c/= :: Range -> Range -> Bool
== :: Range -> Range -> Bool
$c== :: Range -> Range -> Bool
Eq, (forall x. Range -> Rep Range x)
-> (forall x. Rep Range x -> Range) -> Generic Range
forall x. Rep Range x -> Range
forall x. Range -> Rep Range x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep Range x -> Range
$cfrom :: forall x. Range -> Rep Range x
Generic, Eq Range
Eq Range =>
(Range -> Range -> Ordering)
-> (Range -> Range -> Bool)
-> (Range -> Range -> Bool)
-> (Range -> Range -> Bool)
-> (Range -> Range -> Bool)
-> (Range -> Range -> Range)
-> (Range -> Range -> Range)
-> Ord Range
Range -> Range -> Bool
Range -> Range -> Ordering
Range -> Range -> Range
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: Range -> Range -> Range
$cmin :: Range -> Range -> Range
max :: Range -> Range -> Range
$cmax :: Range -> Range -> Range
>= :: Range -> Range -> Bool
$c>= :: Range -> Range -> Bool
> :: Range -> Range -> Bool
$c> :: Range -> Range -> Bool
<= :: Range -> Range -> Bool
$c<= :: Range -> Range -> Bool
< :: Range -> Range -> Bool
$c< :: Range -> Range -> Bool
compare :: Range -> Range -> Ordering
$ccompare :: Range -> Range -> Ordering
$cp1Ord :: Eq Range
Ord, Int -> Range -> ShowS
[Range] -> ShowS
Range -> String
(Int -> Range -> ShowS)
-> (Range -> String) -> ([Range] -> ShowS) -> Show Range
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Range] -> ShowS
$cshowList :: [Range] -> ShowS
show :: Range -> String
$cshow :: Range -> String
showsPrec :: Int -> Range -> ShowS
$cshowsPrec :: Int -> Range -> ShowS
Show)

instance Hashable Range
instance NFData   Range



-- $
-- prop> a <> (b <> c) === (a <> b) <> (c :: Range)
instance Semigroup Range where
  Range start1 :: Int
start1 end1 :: Int
end1 <> :: Range -> Range -> Range
<> Range start2 :: Int
start2 end2 :: Int
end2 = Int -> Int -> Range
Range (Int -> Int -> Int
forall a. Ord a => a -> a -> a
min Int
start1 Int
start2) (Int -> Int -> Int
forall a. Ord a => a -> a -> a
max Int
end1 Int
end2)

instance Lower Range where
  lowerBound :: Range
lowerBound = Int -> Int -> Range
Range 0 0

instance ToJSON Range where
  toJSON :: Range -> Value
toJSON Range { Int
start :: Int
start :: Range -> Int
start, Int
end :: Int
end :: Range -> Int
end } = [Int] -> Value
forall a. ToJSON a => a -> Value
toJSON [ Int
start, Int
end ]

-- | Construct a 'Range' with a given value for both its start and end indices.
point :: Int -> Range
point :: Int -> Range
point i :: Int
i = Int -> Int -> Range
Range Int
i Int
i

-- | Return the length of the range.
rangeLength :: Range -> Int
rangeLength :: Range -> Int
rangeLength range :: Range
range = Range -> Int
end Range
range Int -> Int -> Int
forall a. Num a => a -> a -> a
- Range -> Int
start Range
range

subtractRange :: Range -> Range -> Range
subtractRange :: Range -> Range -> Range
subtractRange range1 :: Range
range1 range2 :: Range
range2 = Int -> Int -> Range
Range (Range -> Int
start Range
range1) (Range -> Int
end Range
range1 Int -> Int -> Int
forall a. Num a => a -> a -> a
- Range -> Int
rangeLength (Int -> Int -> Range
Range (Range -> Int
start Range
range2) (Int -> Int -> Int
forall a. Ord a => a -> a -> a
max (Range -> Int
end Range
range1) (Range -> Int
end Range
range2))))


start_, end_ :: Lens' Range Int
start_ :: (Int -> f Int) -> Range -> f Range
start_ = (Range -> Int) -> (Range -> Int -> Range) -> Lens' Range Int
forall s a. (s -> a) -> (s -> a -> s) -> Lens' s a
lens Range -> Int
start (\r :: Range
r s :: Int
s -> Range
r { start :: Int
start = Int
s })
end_ :: (Int -> f Int) -> Range -> f Range
end_   = (Range -> Int) -> (Range -> Int -> Range) -> Lens' Range Int
forall s a. (s -> a) -> (s -> a -> s) -> Lens' s a
lens Range -> Int
end   (\r :: Range
r e :: Int
e -> Range
r { end :: Int
end   = Int
e })


type Lens' s a = forall f . Functor f => (a -> f a) -> (s -> f s)

lens :: (s -> a) -> (s -> a -> s) -> Lens' s a
lens :: (s -> a) -> (s -> a -> s) -> Lens' s a
lens get :: s -> a
get put :: s -> a -> s
put afa :: a -> f a
afa s :: s
s = (a -> s) -> f a -> f s
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (s -> a -> s
put s
s) (a -> f a
afa (s -> a
get s
s))
{-# INLINE lens #-}


-- $setup
-- >>> import Test.QuickCheck
-- >>> instance Arbitrary Range where arbitrary = Range <$> arbitrary <*> arbitrary ; shrink (Range s e) = Range <$> shrink s <*> shrink e