intersect.go 1.1 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

// Intersect computes the intersection of the keys in p and q.
// p and q must be non-nil. The returned trie is never nil.
func Intersect(p, q *XorTrie) *XorTrie {
	return intersect(0, p, q)
}

func intersect(depth int, p, q *XorTrie) *XorTrie {
	switch {
	case p.isLeaf() && q.isLeaf():
		if p.isEmpty() || q.isEmpty() {
			return &XorTrie{} // empty set
		} else {
Petar Maymounkov's avatar
Petar Maymounkov committed
19 20
			if key.Equal(p.Key, q.Key) {
				return &XorTrie{Key: p.Key} // singleton
Petar Maymounkov's avatar
Petar Maymounkov committed
21 22 23 24 25 26 27 28
			} else {
				return &XorTrie{} // empty set
			}
		}
	case p.isLeaf() && !q.isLeaf():
		if p.isEmpty() {
			return &XorTrie{} // empty set
		} else {
Petar Maymounkov's avatar
Petar Maymounkov committed
29 30
			if _, found := q.find(depth, p.Key); found {
				return &XorTrie{Key: p.Key}
Petar Maymounkov's avatar
Petar Maymounkov committed
31 32 33 34 35 36 37 38
			} else {
				return &XorTrie{} // empty set
			}
		}
	case !p.isLeaf() && q.isLeaf():
		return Intersect(q, p)
	case !p.isLeaf() && !q.isLeaf():
		disjointUnion := &XorTrie{
Petar Maymounkov's avatar
Petar Maymounkov committed
39 40 41
			Branch: [2]*XorTrie{
				intersect(depth+1, p.Branch[0], q.Branch[0]),
				intersect(depth+1, p.Branch[1], q.Branch[1]),
Petar Maymounkov's avatar
Petar Maymounkov committed
42 43 44 45 46 47 48
			},
		}
		disjointUnion.shrink()
		return disjointUnion
	}
	panic("unreachable")
}