diff options
Diffstat (limited to 'src/Data/Kademlia/Routing/Tree.hs')
-rw-r--r-- | src/Data/Kademlia/Routing/Tree.hs | 57 |
1 files changed, 57 insertions, 0 deletions
diff --git a/src/Data/Kademlia/Routing/Tree.hs b/src/Data/Kademlia/Routing/Tree.hs new file mode 100644 index 00000000..f415d1e1 --- /dev/null +++ b/src/Data/Kademlia/Routing/Tree.hs | |||
@@ -0,0 +1,57 @@ | |||
1 | -- | | ||
2 | -- Copyright : (c) Sam T. 2013 | ||
3 | -- License : MIT | ||
4 | -- Maintainer : pxqr.sta@gmail.com | ||
5 | -- Stability : experimental | ||
6 | -- Portability : portable | ||
7 | -- | ||
8 | -- Routing tree should contain key -> value pairs in this way: | ||
9 | -- | ||
10 | -- * More keys that near to our node key, and less keys that far | ||
11 | -- from our node key. | ||
12 | -- | ||
13 | -- * Tree might be saturated. If this happen we can only update | ||
14 | -- buckets, but we can't add new buckets. | ||
15 | -- | ||
16 | -- Instead of using ordinary binary tree and keep track is it | ||
17 | -- following restrictions above (that's somewhat non-trivial) we | ||
18 | -- store distance -> value keys. This lead to simple data structure | ||
19 | -- that actually isomorphic to non-empty list. So we first map our | ||
20 | -- keys to distances using our node ID and store them in tree. When | ||
21 | -- we need to extract a pair we map distances to keys back, again | ||
22 | -- using our node ID. This normalization happen in routing table. | ||
23 | -- | ||
24 | module Data.Kademlia.Routing.Tree | ||
25 | ( empty | ||
26 | , | ||
27 | ) where | ||
28 | |||
29 | import Control.Applicative hiding (empty) | ||
30 | import Data.Bits | ||
31 | |||
32 | import Data.Kademlia.Routing.Bucket (Bucket, split, isFull) | ||
33 | import qualified Data.Kademlia.Routing.Bucket as Bucket | ||
34 | |||
35 | |||
36 | |||
37 | data Tree k v | ||
38 | = Tip (Bucket k v) | ||
39 | | Bin (Tree k v) (Bucket k v) | ||
40 | |||
41 | empty :: Int -> Tree k v | ||
42 | empty = Tip . Bucket.empty | ||
43 | |||
44 | insert :: Applicative f | ||
45 | => Bits k | ||
46 | => (v -> f Bool) | ||
47 | -> (k, v) -> Tree k v -> f (Tree k v) | ||
48 | insert ping (k, v) = go 0 | ||
49 | where | ||
50 | go n (Tip bucket) | ||
51 | | isFull bucket, (near, far) <- split n bucket | ||
52 | = pure (Tip near `Bin` far) | ||
53 | | otherwise = Tip <$> Bucket.insert ping (k, v) bucket | ||
54 | |||
55 | go n (Bin near far) | ||
56 | | k `testBit` n = Bin <$> pure near <*> Bucket.insert ping (k, v) far | ||
57 | | otherwise = Bin <$> go (succ n) near <*> pure far | ||