summaryrefslogtreecommitdiff
path: root/dht/src/Data/TableMethods.hs
blob: e4208a69bafcf51d2bf2491212547320090b893f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
{-# LANGUAGE CPP                   #-}
{-# LANGUAGE GADTs                 #-}
{-# LANGUAGE LambdaCase            #-}
{-# LANGUAGE PartialTypeSignatures #-}
{-# LANGUAGE RankNTypes            #-}
{-# LANGUAGE ScopedTypeVariables   #-}
{-# LANGUAGE TupleSections         #-}
module Data.TableMethods where

import Data.Functor.Contravariant
import Data.Time.Clock.POSIX
import Data.Word
import qualified Data.IntMap.Strict as IntMap
         ;import Data.IntMap.Strict (IntMap)
import qualified Data.Map.Strict    as Map
         ;import Data.Map.Strict    (Map)
import qualified Data.Word64Map     as W64Map
         ;import Data.Word64Map     (Word64Map)

import Data.Wrapper.PSQ as PSQ

type Priority = POSIXTime

data OptionalPriority t tid x
    = NoPriority
    | HasPriority (Priority -> t x -> ([(tid, Priority, x)], t x))

-- | The standard lookup table methods.
data TableMethods t tid = TableMethods
    { -- | Insert a new /tid/ entry into the transaction table.
      tblInsert :: forall a. tid -> a -> Priority -> t a -> t a
      -- | Delete transaction /tid/ from the transaction table.
    , tblDelete :: forall a. tid -> t a -> t a
       -- | Lookup the value associated with transaction /tid/.
    , tblLookup :: forall a. tid -> t a -> Maybe a
    }

data QMethods t tid x = QMethods
    { qTbl           :: TableMethods t tid
    , qAtMostView    :: OptionalPriority t tid x
    }

vanillaTable :: TableMethods t tid -> QMethods t tid x
vanillaTable tbl = QMethods tbl NoPriority

priorityTable :: TableMethods t tid
                 -> (Priority -> t x -> ([(k, Priority, x)], t x))
                 -> (k -> x -> tid)
                 -> QMethods t tid x
priorityTable tbl atmost f = QMethods
    { qTbl        = tbl
    , qAtMostView = HasPriority $ \p t -> case atmost p t of
        (es,t') -> (map (\(k,p,a) -> (f k a, p, a)) es, t')
    }

-- | Methods for using 'Data.IntMap'.
intMapMethods :: TableMethods IntMap Int
intMapMethods = TableMethods
    { tblInsert     = \tid a p -> IntMap.insert tid a
    , tblDelete     = IntMap.delete
    , tblLookup     = IntMap.lookup
    }

-- | Methods for using 'Data.Word64Map'.
w64MapMethods :: TableMethods Word64Map Word64
w64MapMethods = TableMethods
    { tblInsert     = \tid a p -> W64Map.insert tid a
    , tblDelete     = W64Map.delete
    , tblLookup     = W64Map.lookup
    }

-- | Methods for using 'Data.Map'
mapMethods :: Ord tid => TableMethods (Map tid) tid
mapMethods = TableMethods
    { tblInsert     = \tid a p -> Map.insert tid a
    , tblDelete     = Map.delete
    , tblLookup     = Map.lookup
    }

-- psqMethods :: PSQKey tid => QMethods (HashPSQ tid Priority) tid x
psqMethods :: PSQKey k => (tid -> k) -> (k -> x -> tid) -> QMethods (PSQ' k Priority) tid x
psqMethods g f = priorityTable (contramap g tbl) PSQ.atMostView f
 where
    tbl :: PSQKey tid => TableMethods (PSQ' tid Priority) tid
    tbl = TableMethods
        { tblInsert = PSQ.insert'
        , tblDelete = PSQ.delete
        , tblLookup = \tid t -> case PSQ.lookup tid t of
            Just (p,a) -> Just a
            Nothing    -> Nothing
        }


-- | Change the key type for a lookup table implementation.
--
-- This can be used with 'intMapMethods' or 'mapMethods' to restrict lookups to
-- only a part of the generated /tid/ value.  This is useful for /tid/ types
-- that are especially large due their use for other purposes, such as secure
-- nonces for encryption.
instance Contravariant (TableMethods t) where
    -- contramap :: (tid -> t1) -> TableMethods t t1 -> TableMethods t tid
    contramap f (TableMethods ins del lookup) =
        TableMethods (\k p v t -> ins (f k) p v t)
                     (\k t     -> del (f k) t)
                     (\k t     -> lookup (f k) t)