summaryrefslogtreecommitdiff
path: root/src/Data/Kademlia/Routing/Tree.hs
diff options
context:
space:
mode:
Diffstat (limited to 'src/Data/Kademlia/Routing/Tree.hs')
-rw-r--r--src/Data/Kademlia/Routing/Tree.hs57
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--
24module Data.Kademlia.Routing.Tree
25 ( empty
26 ,
27 ) where
28
29import Control.Applicative hiding (empty)
30import Data.Bits
31
32import Data.Kademlia.Routing.Bucket (Bucket, split, isFull)
33import qualified Data.Kademlia.Routing.Bucket as Bucket
34
35
36
37data Tree k v
38 = Tip (Bucket k v)
39 | Bin (Tree k v) (Bucket k v)
40
41empty :: Int -> Tree k v
42empty = Tip . Bucket.empty
43
44insert :: Applicative f
45 => Bits k
46 => (v -> f Bool)
47 -> (k, v) -> Tree k v -> f (Tree k v)
48insert 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