{-# LANGUAGE CPP #-}
module TimerWheel.Internal.Bucket
( Bucket,
empty,
isEmpty,
partition,
insert,
Pop (..),
pop,
deleteExpectingHit,
Pair (..),
)
where
import Data.Bits
import TimerWheel.Internal.Prelude
import TimerWheel.Internal.Timestamp (Timestamp)
#include "MachDeps.h"
data Bucket a
=
Bin {-# UNPACK #-} !AlarmId {-# UNPACK #-} !Timestamp !a {-# UNPACK #-} !Mask !(Bucket a) !(Bucket a)
| Tip {-# UNPACK #-} !AlarmId {-# UNPACK #-} !Timestamp !a
| Nil
type Mask = Word64
type AlarmId = Int
empty :: Bucket a
empty :: forall a. Bucket a
empty =
Bucket a
forall a. Bucket a
Nil
isEmpty :: Bucket a -> Bool
isEmpty :: forall a. Bucket a -> Bool
isEmpty = \case
Bucket a
Nil -> Bool
True
Bucket a
_ -> Bool
False
partition :: forall a. Timestamp -> Bucket a -> Pair (Bucket a) (Bucket a)
partition :: forall a. Timestamp -> Bucket a -> Pair (Bucket a) (Bucket a)
partition Timestamp
q =
Bucket a -> Bucket a -> Pair (Bucket a) (Bucket a)
go Bucket a
forall a. Bucket a
empty
where
go :: Bucket a -> Bucket a -> Pair (Bucket a) (Bucket a)
go :: Bucket a -> Bucket a -> Pair (Bucket a) (Bucket a)
go Bucket a
acc Bucket a
t =
case Bucket a
t of
Bucket a
Nil -> Bucket a -> Bucket a -> Pair (Bucket a) (Bucket a)
forall a b. a -> b -> Pair a b
Pair Bucket a
acc Bucket a
t
Tip AlarmId
i Timestamp
p a
x
| Timestamp
p Timestamp -> Timestamp -> Bool
forall a. Ord a => a -> a -> Bool
> Timestamp
q -> Bucket a -> Bucket a -> Pair (Bucket a) (Bucket a)
forall a b. a -> b -> Pair a b
Pair Bucket a
acc Bucket a
t
| Bool
otherwise -> Bucket a -> Bucket a -> Pair (Bucket a) (Bucket a)
forall a b. a -> b -> Pair a b
Pair (AlarmId -> Timestamp -> a -> Bucket a -> Bucket a
forall a. AlarmId -> Timestamp -> a -> Bucket a -> Bucket a
insert AlarmId
i Timestamp
p a
x Bucket a
acc) Bucket a
forall a. Bucket a
Nil
Bin AlarmId
i Timestamp
p a
x Word64
m Bucket a
l Bucket a
r
| Timestamp
p Timestamp -> Timestamp -> Bool
forall a. Ord a => a -> a -> Bool
> Timestamp
q -> Bucket a -> Bucket a -> Pair (Bucket a) (Bucket a)
forall a b. a -> b -> Pair a b
Pair Bucket a
acc Bucket a
t
| Bool
otherwise ->
case Bucket a -> Bucket a -> Pair (Bucket a) (Bucket a)
go Bucket a
acc Bucket a
l of
Pair Bucket a
acc1 Bucket a
l1 ->
case Bucket a -> Bucket a -> Pair (Bucket a) (Bucket a)
go Bucket a
acc1 Bucket a
r of
Pair Bucket a
acc2 Bucket a
r1 -> Bucket a -> Bucket a -> Pair (Bucket a) (Bucket a)
forall a b. a -> b -> Pair a b
Pair (AlarmId -> Timestamp -> a -> Bucket a -> Bucket a
forall a. AlarmId -> Timestamp -> a -> Bucket a -> Bucket a
insert AlarmId
i Timestamp
p a
x Bucket a
acc2) (Word64 -> Bucket a -> Bucket a -> Bucket a
forall v. Word64 -> Bucket v -> Bucket v -> Bucket v
merge Word64
m Bucket a
l1 Bucket a
r1)
insert :: forall a. AlarmId -> Timestamp -> a -> Bucket a -> Bucket a
insert :: forall a. AlarmId -> Timestamp -> a -> Bucket a -> Bucket a
insert AlarmId
i Timestamp
p a
x Bucket a
bucket =
case Bucket a
bucket of
Bucket a
Nil -> AlarmId -> Timestamp -> a -> Bucket a
forall a. AlarmId -> Timestamp -> a -> Bucket a
Tip AlarmId
i Timestamp
p a
x
Tip AlarmId
j Timestamp
q a
y
| Bool
betteri -> AlarmId -> Bucket a -> Bucket a -> Bucket a
linki AlarmId
j Bucket a
bucket Bucket a
forall a. Bucket a
Nil
| Bool
otherwise -> AlarmId -> Bucket a -> Bucket a -> Bucket a
linkj AlarmId
i (AlarmId -> Timestamp -> a -> Bucket a
forall a. AlarmId -> Timestamp -> a -> Bucket a
Tip AlarmId
i Timestamp
p a
x) Bucket a
forall a. Bucket a
Nil
where
betteri :: Bool
betteri = (Timestamp
p, AlarmId
i) (Timestamp, AlarmId) -> (Timestamp, AlarmId) -> Bool
forall a. Ord a => a -> a -> Bool
< (Timestamp
q, AlarmId
j)
linkj :: AlarmId -> Bucket a -> Bucket a -> Bucket a
linkj = AlarmId
-> Timestamp -> a -> AlarmId -> Bucket a -> Bucket a -> Bucket a
forall v.
AlarmId
-> Timestamp -> v -> AlarmId -> Bucket v -> Bucket v -> Bucket v
link AlarmId
j Timestamp
q a
y
Bin AlarmId
j Timestamp
q a
y Word64
m Bucket a
l Bucket a
r
| Bool
betteri ->
if
| Bool
outsider -> AlarmId -> Bucket a -> Bucket a -> Bucket a
linki AlarmId
j Bucket a
bucket Bucket a
forall a. Bucket a
Nil
| AlarmId -> Word64 -> Bool
goleft AlarmId
j Word64
m -> Bucket a -> Bucket a -> Bucket a
bini (Bucket a -> Bucket a
insertj Bucket a
l) Bucket a
r
| Bool
otherwise -> Bucket a -> Bucket a -> Bucket a
bini Bucket a
l (Bucket a -> Bucket a
insertj Bucket a
r)
| Bool
outsider -> AlarmId -> Bucket a -> Bucket a -> Bucket a
linkj AlarmId
i (AlarmId -> Timestamp -> a -> Bucket a
forall a. AlarmId -> Timestamp -> a -> Bucket a
Tip AlarmId
i Timestamp
p a
x) (Word64 -> Bucket a -> Bucket a -> Bucket a
forall v. Word64 -> Bucket v -> Bucket v -> Bucket v
merge Word64
m Bucket a
l Bucket a
r)
| AlarmId -> Word64 -> Bool
goleft AlarmId
i Word64
m -> Bucket a -> Bucket a -> Bucket a
binj (Bucket a -> Bucket a
inserti Bucket a
l) Bucket a
r
| Bool
otherwise -> Bucket a -> Bucket a -> Bucket a
binj Bucket a
l (Bucket a -> Bucket a
inserti Bucket a
r)
where
outsider :: Bool
outsider = Word64 -> AlarmId -> AlarmId -> Bool
prefixNotEqual Word64
m AlarmId
i AlarmId
j
betteri :: Bool
betteri = (Timestamp
p, AlarmId
i) (Timestamp, AlarmId) -> (Timestamp, AlarmId) -> Bool
forall a. Ord a => a -> a -> Bool
< (Timestamp
q, AlarmId
j)
bini :: Bucket a -> Bucket a -> Bucket a
bini = AlarmId
-> Timestamp -> a -> Word64 -> Bucket a -> Bucket a -> Bucket a
forall a.
AlarmId
-> Timestamp -> a -> Word64 -> Bucket a -> Bucket a -> Bucket a
Bin AlarmId
i Timestamp
p a
x Word64
m
binj :: Bucket a -> Bucket a -> Bucket a
binj = AlarmId
-> Timestamp -> a -> Word64 -> Bucket a -> Bucket a -> Bucket a
forall a.
AlarmId
-> Timestamp -> a -> Word64 -> Bucket a -> Bucket a -> Bucket a
Bin AlarmId
j Timestamp
q a
y Word64
m
inserti :: Bucket a -> Bucket a
inserti = AlarmId -> Timestamp -> a -> Bucket a -> Bucket a
forall a. AlarmId -> Timestamp -> a -> Bucket a -> Bucket a
insert AlarmId
i Timestamp
p a
x
insertj :: Bucket a -> Bucket a
insertj = AlarmId -> Timestamp -> a -> Bucket a -> Bucket a
forall a. AlarmId -> Timestamp -> a -> Bucket a -> Bucket a
insert AlarmId
j Timestamp
q a
y
linkj :: AlarmId -> Bucket a -> Bucket a -> Bucket a
linkj = AlarmId
-> Timestamp -> a -> AlarmId -> Bucket a -> Bucket a -> Bucket a
forall v.
AlarmId
-> Timestamp -> v -> AlarmId -> Bucket v -> Bucket v -> Bucket v
link AlarmId
j Timestamp
q a
y
where
linki :: AlarmId -> Bucket a -> Bucket a -> Bucket a
linki = AlarmId
-> Timestamp -> a -> AlarmId -> Bucket a -> Bucket a -> Bucket a
forall v.
AlarmId
-> Timestamp -> v -> AlarmId -> Bucket v -> Bucket v -> Bucket v
link AlarmId
i Timestamp
p a
x
data Pop a
= PopAlgo {-# UNPACK #-} !AlarmId {-# UNPACK #-} !Timestamp !a !(Bucket a)
| PopNada
pop :: Bucket a -> Pop a
pop :: forall a. Bucket a -> Pop a
pop = \case
Bucket a
Nil -> Pop a
forall a. Pop a
PopNada
Tip AlarmId
k Timestamp
p a
x -> AlarmId -> Timestamp -> a -> Bucket a -> Pop a
forall a. AlarmId -> Timestamp -> a -> Bucket a -> Pop a
PopAlgo AlarmId
k Timestamp
p a
x Bucket a
forall a. Bucket a
Nil
Bin AlarmId
k Timestamp
p a
x Word64
m Bucket a
l Bucket a
r -> AlarmId -> Timestamp -> a -> Bucket a -> Pop a
forall a. AlarmId -> Timestamp -> a -> Bucket a -> Pop a
PopAlgo AlarmId
k Timestamp
p a
x (Word64 -> Bucket a -> Bucket a -> Bucket a
forall v. Word64 -> Bucket v -> Bucket v -> Bucket v
merge Word64
m Bucket a
l Bucket a
r)
{-# INLINE pop #-}
deleteExpectingHit :: AlarmId -> Bucket v -> Maybe (Bucket v)
deleteExpectingHit :: forall v. AlarmId -> Bucket v -> Maybe (Bucket v)
deleteExpectingHit AlarmId
i =
Bucket v -> Maybe (Bucket v)
forall v. Bucket v -> Maybe (Bucket v)
go
where
go :: Bucket v -> Maybe (Bucket v)
go :: forall v. Bucket v -> Maybe (Bucket v)
go = \case
Bucket v
Nil -> Maybe (Bucket v)
forall a. Maybe a
Nothing
Tip AlarmId
j Timestamp
_ v
_
| AlarmId
i AlarmId -> AlarmId -> Bool
forall a. Eq a => a -> a -> Bool
== AlarmId
j -> Bucket v -> Maybe (Bucket v)
forall a. a -> Maybe a
Just Bucket v
forall a. Bucket a
Nil
| Bool
otherwise -> Maybe (Bucket v)
forall a. Maybe a
Nothing
Bin AlarmId
j Timestamp
p v
x Word64
m Bucket v
l Bucket v
r
| AlarmId
i AlarmId -> AlarmId -> Bool
forall a. Eq a => a -> a -> Bool
== AlarmId
j -> Bucket v -> Maybe (Bucket v)
forall a. a -> Maybe a
Just (Bucket v -> Maybe (Bucket v)) -> Bucket v -> Maybe (Bucket v)
forall a b. (a -> b) -> a -> b
$! Word64 -> Bucket v -> Bucket v -> Bucket v
forall v. Word64 -> Bucket v -> Bucket v -> Bucket v
merge Word64
m Bucket v
l Bucket v
r
| AlarmId -> Word64 -> Bool
goleft AlarmId
i Word64
m -> (\Bucket v
l1 -> AlarmId
-> Timestamp -> v -> Word64 -> Bucket v -> Bucket v -> Bucket v
forall a.
AlarmId
-> Timestamp -> a -> Word64 -> Bucket a -> Bucket a -> Bucket a
bin AlarmId
j Timestamp
p v
x Word64
m Bucket v
l1 Bucket v
r) (Bucket v -> Bucket v) -> Maybe (Bucket v) -> Maybe (Bucket v)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Bucket v -> Maybe (Bucket v)
forall v. Bucket v -> Maybe (Bucket v)
go Bucket v
l
| Bool
otherwise -> AlarmId
-> Timestamp -> v -> Word64 -> Bucket v -> Bucket v -> Bucket v
forall a.
AlarmId
-> Timestamp -> a -> Word64 -> Bucket a -> Bucket a -> Bucket a
bin AlarmId
j Timestamp
p v
x Word64
m Bucket v
l (Bucket v -> Bucket v) -> Maybe (Bucket v) -> Maybe (Bucket v)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Bucket v -> Maybe (Bucket v)
forall v. Bucket v -> Maybe (Bucket v)
go Bucket v
r
bin :: AlarmId -> Timestamp -> v -> Mask -> Bucket v -> Bucket v -> Bucket v
bin :: forall a.
AlarmId
-> Timestamp -> a -> Word64 -> Bucket a -> Bucket a -> Bucket a
bin AlarmId
i Timestamp
p v
x Word64
_ Bucket v
Nil Bucket v
Nil = AlarmId -> Timestamp -> v -> Bucket v
forall a. AlarmId -> Timestamp -> a -> Bucket a
Tip AlarmId
i Timestamp
p v
x
bin AlarmId
i Timestamp
p v
x Word64
m Bucket v
l Bucket v
r = AlarmId
-> Timestamp -> v -> Word64 -> Bucket v -> Bucket v -> Bucket v
forall a.
AlarmId
-> Timestamp -> a -> Word64 -> Bucket a -> Bucket a -> Bucket a
Bin AlarmId
i Timestamp
p v
x Word64
m Bucket v
l Bucket v
r
{-# INLINE bin #-}
link :: AlarmId -> Timestamp -> v -> AlarmId -> Bucket v -> Bucket v -> Bucket v
link :: forall v.
AlarmId
-> Timestamp -> v -> AlarmId -> Bucket v -> Bucket v -> Bucket v
link AlarmId
i Timestamp
p v
x AlarmId
j Bucket v
t Bucket v
u
| AlarmId -> Word64 -> Bool
goleft AlarmId
j Word64
m = AlarmId
-> Timestamp -> v -> Word64 -> Bucket v -> Bucket v -> Bucket v
forall a.
AlarmId
-> Timestamp -> a -> Word64 -> Bucket a -> Bucket a -> Bucket a
Bin AlarmId
i Timestamp
p v
x Word64
m Bucket v
t Bucket v
u
| Bool
otherwise = AlarmId
-> Timestamp -> v -> Word64 -> Bucket v -> Bucket v -> Bucket v
forall a.
AlarmId
-> Timestamp -> a -> Word64 -> Bucket a -> Bucket a -> Bucket a
Bin AlarmId
i Timestamp
p v
x Word64
m Bucket v
u Bucket v
t
where
m :: Word64
m = Word64 -> Word64
onlyHighestBit (AlarmId -> Word64
i2w AlarmId
i Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
`xor` AlarmId -> Word64
i2w AlarmId
j)
{-# INLINE link #-}
merge :: Mask -> Bucket v -> Bucket v -> Bucket v
merge :: forall v. Word64 -> Bucket v -> Bucket v -> Bucket v
merge Word64
m Bucket v
l Bucket v
r =
case (Bucket v
l, Bucket v
r) of
(Bucket v
Nil, Bucket v
_) -> Bucket v
r
(Bucket v
_, Bucket v
Nil) -> Bucket v
l
(Tip AlarmId
i Timestamp
p v
x, Tip AlarmId
j Timestamp
q v
y)
| (Timestamp
p, AlarmId
i) (Timestamp, AlarmId) -> (Timestamp, AlarmId) -> Bool
forall a. Ord a => a -> a -> Bool
< (Timestamp
q, AlarmId
j) -> AlarmId
-> Timestamp -> v -> Word64 -> Bucket v -> Bucket v -> Bucket v
forall a.
AlarmId
-> Timestamp -> a -> Word64 -> Bucket a -> Bucket a -> Bucket a
Bin AlarmId
i Timestamp
p v
x Word64
m Bucket v
forall a. Bucket a
Nil Bucket v
r
| Bool
otherwise -> AlarmId
-> Timestamp -> v -> Word64 -> Bucket v -> Bucket v -> Bucket v
forall a.
AlarmId
-> Timestamp -> a -> Word64 -> Bucket a -> Bucket a -> Bucket a
Bin AlarmId
j Timestamp
q v
y Word64
m Bucket v
l Bucket v
forall a. Bucket a
Nil
(Tip AlarmId
i Timestamp
p v
x, Bin AlarmId
j Timestamp
q v
y Word64
n Bucket v
rl Bucket v
rr)
| (Timestamp
p, AlarmId
i) (Timestamp, AlarmId) -> (Timestamp, AlarmId) -> Bool
forall a. Ord a => a -> a -> Bool
< (Timestamp
q, AlarmId
j) -> AlarmId
-> Timestamp -> v -> Word64 -> Bucket v -> Bucket v -> Bucket v
forall a.
AlarmId
-> Timestamp -> a -> Word64 -> Bucket a -> Bucket a -> Bucket a
Bin AlarmId
i Timestamp
p v
x Word64
m Bucket v
forall a. Bucket a
Nil Bucket v
r
| Bool
otherwise -> AlarmId
-> Timestamp -> v -> Word64 -> Bucket v -> Bucket v -> Bucket v
forall a.
AlarmId
-> Timestamp -> a -> Word64 -> Bucket a -> Bucket a -> Bucket a
Bin AlarmId
j Timestamp
q v
y Word64
m Bucket v
l (Word64 -> Bucket v -> Bucket v -> Bucket v
forall v. Word64 -> Bucket v -> Bucket v -> Bucket v
merge Word64
n Bucket v
rl Bucket v
rr)
(Bin AlarmId
i Timestamp
p v
x Word64
n Bucket v
ll Bucket v
lr, Tip AlarmId
j Timestamp
q v
y)
| (Timestamp
p, AlarmId
i) (Timestamp, AlarmId) -> (Timestamp, AlarmId) -> Bool
forall a. Ord a => a -> a -> Bool
< (Timestamp
q, AlarmId
j) -> AlarmId
-> Timestamp -> v -> Word64 -> Bucket v -> Bucket v -> Bucket v
forall a.
AlarmId
-> Timestamp -> a -> Word64 -> Bucket a -> Bucket a -> Bucket a
Bin AlarmId
i Timestamp
p v
x Word64
m (Word64 -> Bucket v -> Bucket v -> Bucket v
forall v. Word64 -> Bucket v -> Bucket v -> Bucket v
merge Word64
n Bucket v
ll Bucket v
lr) Bucket v
r
| Bool
otherwise -> AlarmId
-> Timestamp -> v -> Word64 -> Bucket v -> Bucket v -> Bucket v
forall a.
AlarmId
-> Timestamp -> a -> Word64 -> Bucket a -> Bucket a -> Bucket a
Bin AlarmId
j Timestamp
q v
y Word64
m Bucket v
l Bucket v
forall a. Bucket a
Nil
(Bin AlarmId
i Timestamp
p v
x Word64
n Bucket v
ll Bucket v
lr, Bin AlarmId
j Timestamp
q v
y Word64
o Bucket v
rl Bucket v
rr)
| (Timestamp
p, AlarmId
i) (Timestamp, AlarmId) -> (Timestamp, AlarmId) -> Bool
forall a. Ord a => a -> a -> Bool
< (Timestamp
q, AlarmId
j) -> AlarmId
-> Timestamp -> v -> Word64 -> Bucket v -> Bucket v -> Bucket v
forall a.
AlarmId
-> Timestamp -> a -> Word64 -> Bucket a -> Bucket a -> Bucket a
Bin AlarmId
i Timestamp
p v
x Word64
m (Word64 -> Bucket v -> Bucket v -> Bucket v
forall v. Word64 -> Bucket v -> Bucket v -> Bucket v
merge Word64
n Bucket v
ll Bucket v
lr) Bucket v
r
| Bool
otherwise -> AlarmId
-> Timestamp -> v -> Word64 -> Bucket v -> Bucket v -> Bucket v
forall a.
AlarmId
-> Timestamp -> a -> Word64 -> Bucket a -> Bucket a -> Bucket a
Bin AlarmId
j Timestamp
q v
y Word64
m Bucket v
l (Word64 -> Bucket v -> Bucket v -> Bucket v
forall v. Word64 -> Bucket v -> Bucket v -> Bucket v
merge Word64
o Bucket v
rl Bucket v
rr)
goleft :: AlarmId -> Mask -> Bool
goleft :: AlarmId -> Word64 -> Bool
goleft AlarmId
i Word64
m =
AlarmId -> Word64
i2w AlarmId
i Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.&. Word64
m Word64 -> Word64 -> Bool
forall a. Eq a => a -> a -> Bool
== Word64
0
{-# INLINE goleft #-}
prefixNotEqual :: Mask -> AlarmId -> AlarmId -> Bool
prefixNotEqual :: Word64 -> AlarmId -> AlarmId -> Bool
prefixNotEqual (Word64 -> Word64
prefixMask -> Word64
e) AlarmId
i AlarmId
j =
AlarmId -> Word64
i2w AlarmId
i Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.&. Word64
e Word64 -> Word64 -> Bool
forall a. Eq a => a -> a -> Bool
/= AlarmId -> Word64
i2w AlarmId
j Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.&. Word64
e
{-# INLINE prefixNotEqual #-}
prefixMask :: Word64 -> Word64
prefixMask :: Word64 -> Word64
prefixMask Word64
m = -Word64
m Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
`xor` Word64
m
{-# INLINE prefixMask #-}
onlyHighestBit :: Word64 -> Mask
onlyHighestBit :: Word64 -> Word64
onlyHighestBit Word64
w = Word64 -> AlarmId -> Word64
forall a. Bits a => a -> AlarmId -> a
unsafeShiftL Word64
1 (WORD_SIZE_IN_BITS - 1 - countLeadingZeros w)
{-# INLINE onlyHighestBit #-}
i2w :: AlarmId -> Word64
i2w :: AlarmId -> Word64
i2w = AlarmId -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral
{-# INLINE i2w #-}
data Pair a b
= Pair !a !b