{-# LANGUAGE OverloadedStrings #-}
module Swarm.Util.WindowedCounter (
WindowedCounter,
Offsettable (..),
mkWindow,
getOccupancy,
insert,
discardGarbage,
) where
import Data.Aeson
import Data.Set (Set)
import Data.Set qualified as Set
import Swarm.Util.UnitInterval
import Prelude hiding (length)
class Offsettable a where
offsetBy :: Int -> a -> a
data WindowedCounter a = WindowedCounter
{ forall a. WindowedCounter a -> Set a
_members :: Set a
, forall a. WindowedCounter a -> Maybe a
_lastLargest :: Maybe a
, forall a. WindowedCounter a -> Int
_nominalSpan :: Int
}
deriving (WindowedCounter a -> WindowedCounter a -> Bool
(WindowedCounter a -> WindowedCounter a -> Bool)
-> (WindowedCounter a -> WindowedCounter a -> Bool)
-> Eq (WindowedCounter a)
forall a. Eq a => WindowedCounter a -> WindowedCounter a -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: forall a. Eq a => WindowedCounter a -> WindowedCounter a -> Bool
== :: WindowedCounter a -> WindowedCounter a -> Bool
$c/= :: forall a. Eq a => WindowedCounter a -> WindowedCounter a -> Bool
/= :: WindowedCounter a -> WindowedCounter a -> Bool
Eq, Int -> WindowedCounter a -> ShowS
[WindowedCounter a] -> ShowS
WindowedCounter a -> String
(Int -> WindowedCounter a -> ShowS)
-> (WindowedCounter a -> String)
-> ([WindowedCounter a] -> ShowS)
-> Show (WindowedCounter a)
forall a. Show a => Int -> WindowedCounter a -> ShowS
forall a. Show a => [WindowedCounter a] -> ShowS
forall a. Show a => WindowedCounter a -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: forall a. Show a => Int -> WindowedCounter a -> ShowS
showsPrec :: Int -> WindowedCounter a -> ShowS
$cshow :: forall a. Show a => WindowedCounter a -> String
show :: WindowedCounter a -> String
$cshowList :: forall a. Show a => [WindowedCounter a] -> ShowS
showList :: [WindowedCounter a] -> ShowS
Show)
instance (ToJSON a) => ToJSON (WindowedCounter a) where
toJSON :: WindowedCounter a -> Value
toJSON (WindowedCounter Set a
membersSet Maybe a
_lastLargest Int
nominalSpan) =
[Pair] -> Value
object
[ Key
"members" Key -> Value -> Pair
forall v. ToJSON v => Key -> v -> Pair
forall e kv v. (KeyValue e kv, ToJSON v) => Key -> v -> kv
.= Set a -> Value
forall a. ToJSON a => a -> Value
toJSON Set a
membersSet
, Key
"span" Key -> Int -> Pair
forall v. ToJSON v => Key -> v -> Pair
forall e kv v. (KeyValue e kv, ToJSON v) => Key -> v -> kv
.= Int
nominalSpan
]
instance FromJSON (WindowedCounter a) where
parseJSON :: Value -> Parser (WindowedCounter a)
parseJSON = String
-> (Object -> Parser (WindowedCounter a))
-> Value
-> Parser (WindowedCounter a)
forall a. String -> (Object -> Parser a) -> Value -> Parser a
withObject String
"WindowedCounter" ((Object -> Parser (WindowedCounter a))
-> Value -> Parser (WindowedCounter a))
-> (Object -> Parser (WindowedCounter a))
-> Value
-> Parser (WindowedCounter a)
forall a b. (a -> b) -> a -> b
$ \Object
v -> do
Int
s <- Object
v Object -> Key -> Parser Int
forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"span"
WindowedCounter a -> Parser (WindowedCounter a)
forall a. a -> Parser a
forall (m :: * -> *) a. Monad m => a -> m a
return (WindowedCounter a -> Parser (WindowedCounter a))
-> WindowedCounter a -> Parser (WindowedCounter a)
forall a b. (a -> b) -> a -> b
$ Int -> WindowedCounter a
forall a. Int -> WindowedCounter a
mkWindow Int
s
mkWindow ::
Int ->
WindowedCounter a
mkWindow :: forall a. Int -> WindowedCounter a
mkWindow = Set a -> Maybe a -> Int -> WindowedCounter a
forall a. Set a -> Maybe a -> Int -> WindowedCounter a
WindowedCounter Set a
forall a. Set a
Set.empty Maybe a
forall a. Maybe a
Nothing (Int -> WindowedCounter a)
-> (Int -> Int) -> Int -> WindowedCounter a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> Int
forall a. Num a => a -> a
abs
getOccupancy ::
(Ord a, Offsettable a) =>
a ->
WindowedCounter a ->
UnitInterval Double
getOccupancy :: forall a.
(Ord a, Offsettable a) =>
a -> WindowedCounter a -> UnitInterval Double
getOccupancy a
currentTime wc :: WindowedCounter a
wc@(WindowedCounter Set a
s Maybe a
lastLargest Int
nominalSpan) =
Double -> UnitInterval Double
forall a. (Ord a, Num a) => a -> UnitInterval a
mkInterval (Double -> UnitInterval Double) -> Double -> UnitInterval Double
forall a b. (a -> b) -> a -> b
$
if Set a -> Bool
forall a. Set a -> Bool
Set.null Set a
s Bool -> Bool -> Bool
|| Bool -> (a -> Bool) -> Maybe a -> Bool
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Bool
False (a -> a -> Bool
forall a. Ord a => a -> a -> Bool
< a
referenceTick) Maybe a
lastLargest
then Double
0
else Int -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Set a -> Int
forall a. Set a -> Int
Set.size Set a
culledSet) Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ Int -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
nominalSpan
where
referenceTick :: a
referenceTick = Int -> a -> a
forall a. Offsettable a => Int -> a -> a
offsetBy (Int -> Int
forall a. Num a => a -> a
negate Int
nominalSpan) a
currentTime
WindowedCounter Set a
culledSet Maybe a
_ Int
_ = a -> WindowedCounter a -> WindowedCounter a
forall a.
(Ord a, Offsettable a) =>
a -> WindowedCounter a -> WindowedCounter a
discardGarbage a
currentTime WindowedCounter a
wc
insert ::
(Ord a, Offsettable a) =>
a ->
WindowedCounter a ->
WindowedCounter a
insert :: forall a.
(Ord a, Offsettable a) =>
a -> WindowedCounter a -> WindowedCounter a
insert a
x (WindowedCounter Set a
s Maybe a
lastLargest Int
nominalSpan) =
a -> WindowedCounter a -> WindowedCounter a
forall a.
(Ord a, Offsettable a) =>
a -> WindowedCounter a -> WindowedCounter a
discardGarbage a
x (WindowedCounter a -> WindowedCounter a)
-> WindowedCounter a -> WindowedCounter a
forall a b. (a -> b) -> a -> b
$ Set a -> Maybe a -> Int -> WindowedCounter a
forall a. Set a -> Maybe a -> Int -> WindowedCounter a
WindowedCounter (a -> Set a -> Set a
forall a. Ord a => a -> Set a -> Set a
Set.insert a
x Set a
s) Maybe a
newLargest Int
nominalSpan
where
newLargest :: Maybe a
newLargest = a -> Maybe a
forall a. a -> Maybe a
Just (a -> Maybe a) -> a -> Maybe a
forall a b. (a -> b) -> a -> b
$ a -> (a -> a) -> Maybe a -> a
forall b a. b -> (a -> b) -> Maybe a -> b
maybe a
x (a -> a -> a
forall a. Ord a => a -> a -> a
max a
x) Maybe a
lastLargest
discardGarbage ::
(Ord a, Offsettable a) =>
a ->
WindowedCounter a ->
WindowedCounter a
discardGarbage :: forall a.
(Ord a, Offsettable a) =>
a -> WindowedCounter a -> WindowedCounter a
discardGarbage a
currentTime (WindowedCounter Set a
s Maybe a
lastLargest Int
nominalSpan) =
Set a -> Maybe a -> Int -> WindowedCounter a
forall a. Set a -> Maybe a -> Int -> WindowedCounter a
WindowedCounter Set a
larger Maybe a
lastLargest Int
nominalSpan
where
(Set a
_smaller, Set a
larger) = a -> Set a -> (Set a, Set a)
forall a. Ord a => a -> Set a -> (Set a, Set a)
Set.split (Int -> a -> a
forall a. Offsettable a => Int -> a -> a
offsetBy (Int -> Int
forall a. Num a => a -> a
negate Int
nominalSpan) a
currentTime) Set a
s