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

import (
	"github.com/libp2p/go-libp2p-xor/key"
)
Petar Maymounkov's avatar
Petar Maymounkov committed
6

7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
// Add adds the key q to the trie. Add mutates the trie.
// TODO: Also implement an immutable version of Add.
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) {
	if qb := trie.Branch[q.BitAt(depth)]; qb != nil {
		return qb.AddAtDepth(depth+1, q)
	} else {
		if trie.Key == nil {
			trie.Key = q
			return depth, true
		} else {
			if key.Equal(trie.Key, q) {
				return depth, false
			} else {
				p := trie.Key
				trie.Key = nil
				// both Branches are nil
				trie.Branch[0], trie.Branch[1] = &Trie{}, &Trie{}
				trie.Branch[p.BitAt(depth)].AddAtDepth(depth+1, p)
				return trie.Branch[q.BitAt(depth)].AddAtDepth(depth+1, q)
			}
		}
	}
}

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

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