{-# OPTIONS_HADDOCK not-home #-}

-- | Utilities related to pages.
--
module Database.LSMTree.Internal.Page (
    PageNo (..)
  , nextPageNo
  , NumPages (..)
  , getNumPages
  , PageSpan (..)
  , singlePage
  , multiPage
  , pageSpanSize
  ) where

import           Control.DeepSeq (NFData (..))

-- | A 0-based number identifying a disk page.
newtype PageNo = PageNo { PageNo -> Int
unPageNo :: Int }
  deriving stock (Int -> PageNo -> ShowS
[PageNo] -> ShowS
PageNo -> String
(Int -> PageNo -> ShowS)
-> (PageNo -> String) -> ([PageNo] -> ShowS) -> Show PageNo
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> PageNo -> ShowS
showsPrec :: Int -> PageNo -> ShowS
$cshow :: PageNo -> String
show :: PageNo -> String
$cshowList :: [PageNo] -> ShowS
showList :: [PageNo] -> ShowS
Show, PageNo -> PageNo -> Bool
(PageNo -> PageNo -> Bool)
-> (PageNo -> PageNo -> Bool) -> Eq PageNo
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: PageNo -> PageNo -> Bool
== :: PageNo -> PageNo -> Bool
$c/= :: PageNo -> PageNo -> Bool
/= :: PageNo -> PageNo -> Bool
Eq, Eq PageNo
Eq PageNo =>
(PageNo -> PageNo -> Ordering)
-> (PageNo -> PageNo -> Bool)
-> (PageNo -> PageNo -> Bool)
-> (PageNo -> PageNo -> Bool)
-> (PageNo -> PageNo -> Bool)
-> (PageNo -> PageNo -> PageNo)
-> (PageNo -> PageNo -> PageNo)
-> Ord PageNo
PageNo -> PageNo -> Bool
PageNo -> PageNo -> Ordering
PageNo -> PageNo -> PageNo
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
$ccompare :: PageNo -> PageNo -> Ordering
compare :: PageNo -> PageNo -> Ordering
$c< :: PageNo -> PageNo -> Bool
< :: PageNo -> PageNo -> Bool
$c<= :: PageNo -> PageNo -> Bool
<= :: PageNo -> PageNo -> Bool
$c> :: PageNo -> PageNo -> Bool
> :: PageNo -> PageNo -> Bool
$c>= :: PageNo -> PageNo -> Bool
>= :: PageNo -> PageNo -> Bool
$cmax :: PageNo -> PageNo -> PageNo
max :: PageNo -> PageNo -> PageNo
$cmin :: PageNo -> PageNo -> PageNo
min :: PageNo -> PageNo -> PageNo
Ord)
  deriving newtype PageNo -> ()
(PageNo -> ()) -> NFData PageNo
forall a. (a -> ()) -> NFData a
$crnf :: PageNo -> ()
rnf :: PageNo -> ()
NFData

-- | Increment the page number.
--
-- Note: This does not ensure that the incremented page number exists within a given page span.
{-# INLINE nextPageNo #-}
nextPageNo :: PageNo -> PageNo
nextPageNo :: PageNo -> PageNo
nextPageNo = Int -> PageNo
PageNo (Int -> PageNo) -> (PageNo -> Int) -> PageNo -> PageNo
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> Int
forall a. Enum a => a -> a
succ (Int -> Int) -> (PageNo -> Int) -> PageNo -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PageNo -> Int
unPageNo

-- | The number of pages contained by an index or other paging data-structure.
--
-- Note: This is a 0-based number; take care to ensure arithmetic underflow
-- does not occur during subtraction operations!
newtype NumPages = NumPages Word
  deriving stock (NumPages -> NumPages -> Bool
(NumPages -> NumPages -> Bool)
-> (NumPages -> NumPages -> Bool) -> Eq NumPages
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: NumPages -> NumPages -> Bool
== :: NumPages -> NumPages -> Bool
$c/= :: NumPages -> NumPages -> Bool
/= :: NumPages -> NumPages -> Bool
Eq, Eq NumPages
Eq NumPages =>
(NumPages -> NumPages -> Ordering)
-> (NumPages -> NumPages -> Bool)
-> (NumPages -> NumPages -> Bool)
-> (NumPages -> NumPages -> Bool)
-> (NumPages -> NumPages -> Bool)
-> (NumPages -> NumPages -> NumPages)
-> (NumPages -> NumPages -> NumPages)
-> Ord NumPages
NumPages -> NumPages -> Bool
NumPages -> NumPages -> Ordering
NumPages -> NumPages -> NumPages
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
$ccompare :: NumPages -> NumPages -> Ordering
compare :: NumPages -> NumPages -> Ordering
$c< :: NumPages -> NumPages -> Bool
< :: NumPages -> NumPages -> Bool
$c<= :: NumPages -> NumPages -> Bool
<= :: NumPages -> NumPages -> Bool
$c> :: NumPages -> NumPages -> Bool
> :: NumPages -> NumPages -> Bool
$c>= :: NumPages -> NumPages -> Bool
>= :: NumPages -> NumPages -> Bool
$cmax :: NumPages -> NumPages -> NumPages
max :: NumPages -> NumPages -> NumPages
$cmin :: NumPages -> NumPages -> NumPages
min :: NumPages -> NumPages -> NumPages
Ord, Int -> NumPages -> ShowS
[NumPages] -> ShowS
NumPages -> String
(Int -> NumPages -> ShowS)
-> (NumPages -> String) -> ([NumPages] -> ShowS) -> Show NumPages
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> NumPages -> ShowS
showsPrec :: Int -> NumPages -> ShowS
$cshow :: NumPages -> String
show :: NumPages -> String
$cshowList :: [NumPages] -> ShowS
showList :: [NumPages] -> ShowS
Show)
  deriving newtype (NumPages -> ()
(NumPages -> ()) -> NFData NumPages
forall a. (a -> ()) -> NFData a
$crnf :: NumPages -> ()
rnf :: NumPages -> ()
NFData)

-- | A type-safe "unwrapper" for 'NumPages'. Use this accessor whenever you want
-- to convert 'NumPages' to a more versatile number type.
{-# INLINE getNumPages #-}
getNumPages :: Integral i => NumPages -> i
getNumPages :: forall i. Integral i => NumPages -> i
getNumPages (NumPages Word
w) = Word -> i
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word
w

-- | A span of pages, representing an inclusive interval of page numbers.
--
-- Typlically used to denote the contiguous page span for a database entry.
data PageSpan = PageSpan {
    PageSpan -> PageNo
pageSpanStart :: {-# UNPACK #-} !PageNo
  , PageSpan -> PageNo
pageSpanEnd   :: {-# UNPACK #-} !PageNo
  }
  deriving stock (Int -> PageSpan -> ShowS
[PageSpan] -> ShowS
PageSpan -> String
(Int -> PageSpan -> ShowS)
-> (PageSpan -> String) -> ([PageSpan] -> ShowS) -> Show PageSpan
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> PageSpan -> ShowS
showsPrec :: Int -> PageSpan -> ShowS
$cshow :: PageSpan -> String
show :: PageSpan -> String
$cshowList :: [PageSpan] -> ShowS
showList :: [PageSpan] -> ShowS
Show, PageSpan -> PageSpan -> Bool
(PageSpan -> PageSpan -> Bool)
-> (PageSpan -> PageSpan -> Bool) -> Eq PageSpan
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: PageSpan -> PageSpan -> Bool
== :: PageSpan -> PageSpan -> Bool
$c/= :: PageSpan -> PageSpan -> Bool
/= :: PageSpan -> PageSpan -> Bool
Eq)

instance NFData PageSpan where
  rnf :: PageSpan -> ()
rnf (PageSpan PageNo
x PageNo
y) = PageNo -> ()
forall a. NFData a => a -> ()
rnf PageNo
x () -> () -> ()
forall a b. a -> b -> b
`seq` PageNo -> ()
forall a. NFData a => a -> ()
rnf PageNo
y

{-# INLINE singlePage #-}
singlePage :: PageNo -> PageSpan
singlePage :: PageNo -> PageSpan
singlePage PageNo
i = PageNo -> PageNo -> PageSpan
PageSpan PageNo
i PageNo
i

{-# INLINE multiPage #-}
multiPage :: PageNo -> PageNo -> PageSpan
multiPage :: PageNo -> PageNo -> PageSpan
multiPage PageNo
i PageNo
j = PageNo -> PageNo -> PageSpan
PageSpan PageNo
i PageNo
j

{-# INLINE pageSpanSize #-}
pageSpanSize :: PageSpan -> NumPages
pageSpanSize :: PageSpan -> NumPages
pageSpanSize PageSpan
pspan = Word -> NumPages
NumPages (Word -> NumPages) -> (Int -> Word) -> Int -> NumPages
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> Word
forall a. Enum a => Int -> a
toEnum (Int -> NumPages) -> Int -> NumPages
forall a b. (a -> b) -> a -> b
$
    PageNo -> Int
unPageNo (PageSpan -> PageNo
pageSpanEnd PageSpan
pspan) Int -> Int -> Int
forall a. Num a => a -> a -> a
- PageNo -> Int
unPageNo (PageSpan -> PageNo
pageSpanStart PageSpan
pspan) Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1