Container.hs 2.82 KB
Newer Older
Iustin Pop's avatar
Iustin Pop committed
1
2
3
4
5
6
7
{-| Module abstracting the node and instance container implementation.

This is currently implemented on top of an 'IntMap', which seems to
give the best performance for our workload.

-}

8
module Ganeti.HTools.Container
Iustin Pop's avatar
Iustin Pop committed
9
10
11
    (
     -- * Types
     Container
12
    , Key
Iustin Pop's avatar
Iustin Pop committed
13
14
15
16
17
18
19
20
21
22
     -- * Creation
    , empty
    , fromAssocList
     -- * Query
    , size
    , find
     -- * Update
    , add
    , addTwo
    , remove
23
    , IntMap.map
24
    , IntMap.mapAccum
Iustin Pop's avatar
Iustin Pop committed
25
26
    -- * Conversion
    , elems
Iustin Pop's avatar
Iustin Pop committed
27
    , keys
28
29
30
31
    -- * Element functions
    , nameOf
    , maxNameLen
    , findByName
Iustin Pop's avatar
Iustin Pop committed
32
33
34
35
    ) where

import qualified Data.IntMap as IntMap

36
37
import qualified Ganeti.HTools.Types as T

Iustin Pop's avatar
Iustin Pop committed
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
type Key = IntMap.Key
type Container = IntMap.IntMap

-- | Create an empty container.
empty :: Container a
empty = IntMap.empty

-- | Returns the number of elements in the map.
size :: Container a -> Int
size = IntMap.size

-- | Locate a key in the map (must exist).
find :: Key -> Container a -> a
find k c = c IntMap.! k

-- | Locate a keyin the map returning a default value if not existing.
findWithDefault :: a -> Key -> Container a -> a
findWithDefault = IntMap.findWithDefault

-- | Add or update one element to the map.
add :: Key -> a -> Container a -> Container a
add k v c = IntMap.insert k v c

-- | Remove an element from the map.
remove :: Key -> Container a -> Container a
remove = IntMap.delete

-- | Return the list of values in the map.
elems :: Container a -> [a]
elems = IntMap.elems

Iustin Pop's avatar
Iustin Pop committed
69
70
71
72
-- | Return the list of keys in the map.
keys :: Container a -> [Key]
keys = IntMap.keys

Iustin Pop's avatar
Iustin Pop committed
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
-- | Create a map from an association list.
fromAssocList :: [(Key, a)] -> Container a
fromAssocList = IntMap.fromList

-- | Create a map from an association list with a combining function.
fromListWith :: (a -> a -> a) -> [(Key, a)] -> Container a
fromListWith = IntMap.fromListWith

-- | Fold over the values of the map.
fold :: (a -> b -> b) -> b -> Container a -> b
fold = IntMap.fold

-- | Add or update two elements of the map.
addTwo :: Key -> a -> Key -> a -> Container a -> Container a
addTwo k1 v1 k2 v2 c = add k1 v1 $ add k2 v2 c
88

Iustin Pop's avatar
Iustin Pop committed
89
-- | Compute the name of an element in a container.
90
91
92
nameOf :: (T.Element a) => Container a -> Key -> String
nameOf c k = T.nameOf $ find k c

Iustin Pop's avatar
Iustin Pop committed
93
-- | Compute the maximum name length in an Element Container.
94
95
96
maxNameLen :: (T.Element a) => Container a -> Int
maxNameLen = maximum . map (length . T.nameOf) . elems

Iustin Pop's avatar
Iustin Pop committed
97
-- | Find an element by name in a Container; this is a very slow function.
98
99
100
101
102
103
104
105
106
107
108
109
findByName :: (T.Element a, Monad m) =>
              Container a -> String -> m Key
findByName c n =
    let all_elems = elems c
        result = filter ((== n) . T.nameOf) all_elems
        nems = length result
    in
      if nems /= 1 then
          fail $ "Wrong number of elems (" ++ (show nems) ++
                   ") found with name " ++ n
      else
          return $ T.idxOf $ head result