add.go 1.67 KB
Newer Older
Petar Maymounkov's avatar
Petar Maymounkov committed
1 2 3
package trie

import (
tavit ohanian's avatar
tavit ohanian committed
4
	"gitlab.dms3.io/p2p/go-p2p-xor/key"
Petar Maymounkov's avatar
Petar Maymounkov committed
5
)
Petar Maymounkov's avatar
Petar Maymounkov committed
6

7 8 9 10 11 12
// Add adds the key q to the trie. Add mutates the trie.
func (trie *Trie) Add(q key.Key) (insertedDepth int, insertedOK bool) {
	return trie.AddAtDepth(0, q)
}

func (trie *Trie) AddAtDepth(depth int, q key.Key) (insertedDepth int, insertedOK bool) {
13 14 15 16 17 18 19
	switch {
	case trie.IsEmptyLeaf():
		trie.Key = q
		return depth, true
	case trie.IsNonEmptyLeaf():
		if key.Equal(trie.Key, q) {
			return depth, false
20
		} else {
21 22 23 24
			p := trie.Key
			trie.Key = nil
			// both branches are nil
			trie.Branch[0], trie.Branch[1] = &Trie{}, &Trie{}
25
			trie.Branch[p.BitAt(depth)].Key = p
26
			return trie.Branch[q.BitAt(depth)].AddAtDepth(depth+1, q)
27
		}
28 29
	default:
		return trie.Branch[q.BitAt(depth)].AddAtDepth(depth+1, q)
30 31 32
	}
}

Petar Maymounkov's avatar
Petar Maymounkov committed
33 34
// Add adds the key q to trie, returning a new trie.
// Add is immutable/non-destructive: The original trie remains unchanged.
35 36
func Add(trie *Trie, q key.Key) *Trie {
	return AddAtDepth(0, trie, q)
Petar Maymounkov's avatar
Petar Maymounkov committed
37 38
}

39
func AddAtDepth(depth int, trie *Trie, q key.Key) *Trie {
40 41 42 43 44 45
	switch {
	case trie.IsEmptyLeaf():
		return &Trie{Key: q}
	case trie.IsNonEmptyLeaf():
		if key.Equal(trie.Key, q) {
			return trie
Petar Maymounkov's avatar
Petar Maymounkov committed
46
		} else {
47
			return trieForTwo(depth, trie.Key, q)
Petar Maymounkov's avatar
Petar Maymounkov committed
48
		}
49 50 51 52 53 54
	default:
		dir := q.BitAt(depth)
		s := &Trie{}
		s.Branch[dir] = AddAtDepth(depth+1, trie.Branch[dir], q)
		s.Branch[1-dir] = trie.Branch[1-dir]
		return s
Petar Maymounkov's avatar
Petar Maymounkov committed
55 56
	}
}
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71

func trieForTwo(depth int, p, q key.Key) *Trie {
	pDir, qDir := p.BitAt(depth), q.BitAt(depth)
	if qDir == pDir {
		s := &Trie{}
		s.Branch[pDir] = trieForTwo(depth+1, p, q)
		s.Branch[1-pDir] = &Trie{}
		return s
	} else {
		s := &Trie{}
		s.Branch[pDir] = &Trie{Key: p}
		s.Branch[qDir] = &Trie{Key: q}
		return s
	}
}