summaryrefslogtreecommitdiff
path: root/word64-map/src
diff options
context:
space:
mode:
authorJames Crayne <jim.crayne@gmail.com>2019-09-28 13:43:29 -0400
committerJoe Crayne <joe@jerkface.net>2020-01-01 19:27:53 -0500
commit11987749fc6e6d3e53ea737d46d5ab13a16faeb8 (patch)
tree5716463275c2d3e902889db619908ded2a73971c /word64-map/src
parentadd2c76bced51fde5e9917e7449ef52be70faf87 (diff)
Factor out some new libraries
word64-map: Data.Word64Map network-addr: Network.Address tox-crypto: Crypto.Tox lifted-concurrent: Control.Concurrent.Lifted.Instrument Control.Concurrent.Async.Lifted.Instrument psq-wrap: Data.Wrapper.PSQInt Data.Wrapper.PSQ minmax-psq: Data.MinMaxPSQ tasks: Control.Concurrent.Tasks kad: Network.Kademlia Network.Kademlia.Bootstrap Network.Kademlia.Routing Network.Kademlia.CommonAPI Network.Kademlia.Persistence Network.Kademlia.Search
Diffstat (limited to 'word64-map/src')
-rw-r--r--word64-map/src/Data/Word64Map.hs66
1 files changed, 66 insertions, 0 deletions
diff --git a/word64-map/src/Data/Word64Map.hs b/word64-map/src/Data/Word64Map.hs
new file mode 100644
index 00000000..adc9c27e
--- /dev/null
+++ b/word64-map/src/Data/Word64Map.hs
@@ -0,0 +1,66 @@
1{-# LANGUAGE RankNTypes #-}
2{-# LANGUAGE ScopedTypeVariables #-}
3{-# LANGUAGE UnboxedTuples #-}
4module Data.Word64Map where
5
6import Data.Bits
7import qualified Data.IntMap as IntMap
8 ;import Data.IntMap (IntMap)
9import Data.Monoid
10import Data.Typeable
11import Data.Word
12
13-- | Since 'Int' may be 32 or 64 bits, this function is provided as a
14-- convenience to test if an integral type, such as 'Data.Word.Word64', can be
15-- safely transformed into an 'Int' for use with 'IntMap'.
16--
17-- Returns 'True' if the proxied type can be losslessly converted to 'Int' using
18-- 'fromIntegral'.
19fitsInInt :: forall proxy word. (Bounded word, Integral word) => proxy word -> Bool
20fitsInInt proxy = (original == casted)
21 where
22 original = div maxBound 2 :: word
23 casted = fromIntegral (fromIntegral original :: Int) :: word
24
25newtype Word64Map a = Word64Map (IntMap (IntMap a))
26
27size :: Word64Map a -> Int
28size (Word64Map m) = getSum $ foldMap (\n -> Sum (IntMap.size n)) m
29
30empty :: Word64Map a
31empty = Word64Map IntMap.empty
32
33-- Warning: This function assumes an 'Int' is either 64 or 32 bits.
34keyFrom64 :: Word64 -> (# Int,Int #)
35keyFrom64 w8 =
36 if fitsInInt (Proxy :: Proxy Word64)
37 then (# fromIntegral w8 , 0 #)
38 else (# fromIntegral (w8 `shiftR` 32), fromIntegral w8 #)
39{-# INLINE keyFrom64 #-}
40
41lookup :: Word64 -> Word64Map b -> Maybe b
42lookup w8 (Word64Map m) | (# hi,lo #) <- keyFrom64 w8 = do
43 m' <- IntMap.lookup hi m
44 IntMap.lookup lo m'
45{-# INLINE lookup #-}
46
47insert :: Word64 -> b -> Word64Map b -> Word64Map b
48insert w8 b (Word64Map m) | (# hi,lo #) <- keyFrom64 w8
49 = Word64Map $ IntMap.alter (Just . maybe (IntMap.singleton lo b)
50 (IntMap.insert lo b))
51 hi
52 m
53{-# INLINE insert #-}
54
55delete :: Word64 -> Word64Map b -> Word64Map b
56delete w8 (Word64Map m) | (# hi,lo #) <- keyFrom64 w8
57 = Word64Map $ IntMap.alter (maybe Nothing
58 (\m' -> case IntMap.delete lo m' of
59 m'' | IntMap.null m'' -> Nothing
60 m'' -> Just m''))
61 hi
62 m
63{-# INLINE delete #-}
64
65
66