Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
What's new
10
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Open sidebar
p2p
go-p2p-xor
Commits
ab48ec28
Commit
ab48ec28
authored
Mar 27, 2020
by
Petar Maymounkov
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Various fixes and test additions.
parent
2f64005b
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
136 additions
and
24 deletions
+136
-24
key/key.go
key/key.go
+1
-1
key/key_test.go
key/key_test.go
+19
-1
trie/add.go
trie/add.go
+17
-12
trie/add_test.go
trie/add_test.go
+27
-6
trie/check.go
trie/check.go
+72
-4
No files found.
key/key.go
View file @
ab48ec28
...
@@ -11,7 +11,7 @@ import (
...
@@ -11,7 +11,7 @@ import (
type
Key
[]
byte
type
Key
[]
byte
func
(
k
Key
)
BitAt
(
offset
int
)
byte
{
func
(
k
Key
)
BitAt
(
offset
int
)
byte
{
if
k
[
offset
/
8
]
&
(
1
<<
(
offset
%
8
))
==
0
{
if
k
[
offset
/
8
]
&
(
byte
(
1
)
<<
(
offset
%
8
))
==
0
{
return
0
return
0
}
else
{
}
else
{
return
1
return
1
...
...
key/key_test.go
View file @
ab48ec28
...
@@ -4,5 +4,23 @@ import "testing"
...
@@ -4,5 +4,23 @@ import "testing"
func
TestKeyString
(
t
*
testing
.
T
)
{
func
TestKeyString
(
t
*
testing
.
T
)
{
key
:=
Key
{
0x05
,
0xf0
}
key
:=
Key
{
0x05
,
0xf0
}
println
(
key
.
String
())
if
key
.
BitString
()
!=
"1111000000000101"
{
t
.
Errorf
(
"unexpected bit string: %s"
,
key
.
BitString
())
}
}
func
TestBitAt
(
t
*
testing
.
T
)
{
key
:=
Key
{
0x21
,
0x84
}
switch
{
case
key
.
BitAt
(
0
)
!=
1
:
t
.
Errorf
(
"bit 0 flipped"
)
case
key
.
BitAt
(
4
+
1
)
!=
1
:
t
.
Errorf
(
"bit 5 flipped"
)
case
key
.
BitAt
(
8
)
!=
0
:
t
.
Errorf
(
"bit 8 flipped"
)
case
key
.
BitAt
(
8
+
2
)
!=
1
:
t
.
Errorf
(
"bit 10 flipped"
)
case
key
.
BitAt
(
8
+
4
+
3
)
!=
1
:
t
.
Errorf
(
"bit 15 flipped"
)
}
}
}
trie/add.go
View file @
ab48ec28
...
@@ -22,7 +22,7 @@ func (trie *Trie) AddAtDepth(depth int, q key.Key) (insertedDepth int, insertedO
...
@@ -22,7 +22,7 @@ func (trie *Trie) AddAtDepth(depth int, q key.Key) (insertedDepth int, insertedO
trie
.
Key
=
nil
trie
.
Key
=
nil
// both branches are nil
// both branches are nil
trie
.
Branch
[
0
],
trie
.
Branch
[
1
]
=
&
Trie
{},
&
Trie
{}
trie
.
Branch
[
0
],
trie
.
Branch
[
1
]
=
&
Trie
{},
&
Trie
{}
trie
.
Branch
[
p
.
BitAt
(
depth
)]
.
AddAtDepth
(
depth
+
1
,
p
)
trie
.
Branch
[
p
.
BitAt
(
depth
)]
.
Key
=
p
return
trie
.
Branch
[
q
.
BitAt
(
depth
)]
.
AddAtDepth
(
depth
+
1
,
q
)
return
trie
.
Branch
[
q
.
BitAt
(
depth
)]
.
AddAtDepth
(
depth
+
1
,
q
)
}
}
default
:
default
:
...
@@ -44,17 +44,7 @@ func AddAtDepth(depth int, trie *Trie, q key.Key) *Trie {
...
@@ -44,17 +44,7 @@ func AddAtDepth(depth int, trie *Trie, q key.Key) *Trie {
if
key
.
Equal
(
trie
.
Key
,
q
)
{
if
key
.
Equal
(
trie
.
Key
,
q
)
{
return
trie
return
trie
}
else
{
}
else
{
dir
:=
q
.
BitAt
(
depth
)
return
trieForTwo
(
depth
,
trie
.
Key
,
q
)
s
:=
&
Trie
{}
if
q
.
BitAt
(
depth
)
==
trie
.
Key
.
BitAt
(
depth
)
{
s
.
Branch
[
dir
]
=
AddAtDepth
(
depth
+
1
,
&
Trie
{
Key
:
trie
.
Key
},
q
)
s
.
Branch
[
1
-
dir
]
=
&
Trie
{}
return
s
}
else
{
s
.
Branch
[
dir
]
=
AddAtDepth
(
depth
+
1
,
&
Trie
{
Key
:
trie
.
Key
},
q
)
s
.
Branch
[
1
-
dir
]
=
&
Trie
{}
}
return
s
}
}
default
:
default
:
dir
:=
q
.
BitAt
(
depth
)
dir
:=
q
.
BitAt
(
depth
)
...
@@ -64,3 +54,18 @@ func AddAtDepth(depth int, trie *Trie, q key.Key) *Trie {
...
@@ -64,3 +54,18 @@ func AddAtDepth(depth int, trie *Trie, q key.Key) *Trie {
return
s
return
s
}
}
}
}
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
}
}
trie/add_test.go
View file @
ab48ec28
...
@@ -9,7 +9,7 @@ import (
...
@@ -9,7 +9,7 @@ import (
// Verify mutable and immutable add do the same thing.
// Verify mutable and immutable add do the same thing.
func
TestMutableAndImmutableAddSame
(
t
*
testing
.
T
)
{
func
TestMutableAndImmutableAddSame
(
t
*
testing
.
T
)
{
for
_
,
s
:=
range
testAddSam
eSam
ples
{
for
_
,
s
:=
range
append
(
testAddSamples
,
randomTestAddSamples
(
100
)
...
)
{
mut
:=
New
()
mut
:=
New
()
immut
:=
New
()
immut
:=
New
()
for
_
,
k
:=
range
s
.
Keys
{
for
_
,
k
:=
range
s
.
Keys
{
...
@@ -25,10 +25,11 @@ func TestMutableAndImmutableAddSame(t *testing.T) {
...
@@ -25,10 +25,11 @@ func TestMutableAndImmutableAddSame(t *testing.T) {
}
}
func
TestAddIsOrderIndependent
(
t
*
testing
.
T
)
{
func
TestAddIsOrderIndependent
(
t
*
testing
.
T
)
{
for
_
,
s
:=
range
testAddSam
eSam
ples
{
for
_
,
s
:=
range
append
(
testAddSamples
,
randomTestAddSamples
(
100
)
...
)
{
base
:=
New
()
base
:=
New
()
for
_
,
k
:=
range
s
.
Keys
{
for
_
,
k
:=
range
s
.
Keys
{
base
.
Add
(
k
)
base
.
Add
(
k
)
base
.
CheckInvariant
()
}
}
base
.
CheckInvariant
()
base
.
CheckInvariant
()
for
j
:=
0
;
j
<
100
;
j
++
{
for
j
:=
0
;
j
<
100
;
j
++
{
...
@@ -45,11 +46,31 @@ func TestAddIsOrderIndependent(t *testing.T) {
...
@@ -45,11 +46,31 @@ func TestAddIsOrderIndependent(t *testing.T) {
}
}
}
}
type
testAddSam
eSam
ple
struct
{
type
testAddSample
struct
{
Keys
[]
key
.
Key
Keys
[]
key
.
Key
}
}
var
testAddSameSamples
=
[]
*
testAddSameSample
{
var
testAddSamples
=
[]
*
testAddSample
{
{
Keys
:
[]
key
.
Key
{{
1
,
3
,
5
,
7
,
11
,
13
}}},
{
Keys
:
[]
key
.
Key
{{
1
},
{
3
},
{
5
},
{
7
},
{
11
},
{
13
}}},
{
Keys
:
[]
key
.
Key
{{
11
,
22
,
23
,
25
,
27
,
28
,
31
,
32
,
33
}}},
{
Keys
:
[]
key
.
Key
{{
11
},
{
22
},
{
23
},
{
25
},
{
27
},
{
28
},
{
31
},
{
32
},
{
33
}}},
}
func
randomTestAddSamples
(
count
int
)
[]
*
testAddSample
{
s
:=
make
([]
*
testAddSample
,
count
)
for
i
:=
range
s
{
s
[
i
]
=
randomTestAddSample
(
31
,
2
)
}
return
s
}
func
randomTestAddSample
(
setSize
,
keySizeByte
int
)
*
testAddSample
{
keySet
:=
make
([]
key
.
Key
,
setSize
)
for
i
:=
range
keySet
{
k
:=
make
(
key
.
Key
,
keySizeByte
)
rand
.
Read
(
k
)
keySet
[
i
]
=
k
}
return
&
testAddSample
{
Keys
:
keySet
,
}
}
}
trie/check.go
View file @
ab48ec28
package
trie
package
trie
import
(
"github.com/libp2p/go-libp2p-xor/key"
)
// CheckInvariant panics of the trie does not meet its invariant.
// CheckInvariant panics of the trie does not meet its invariant.
func
(
trie
*
Trie
)
CheckInvariant
()
{
func
(
trie
*
Trie
)
CheckInvariant
()
{
trie
.
checkInvariant
(
0
,
nil
)
}
func
(
trie
*
Trie
)
checkInvariant
(
depth
int
,
pathSoFar
*
triePath
)
{
switch
{
switch
{
case
trie
.
IsLeaf
()
:
case
trie
.
IsEmptyLeaf
()
:
// ok
return
case
trie
.
IsNonEmptyLeaf
()
:
if
!
pathSoFar
.
matchesKey
(
trie
.
Key
)
{
panic
(
"key found at invalid location in trie"
)
}
default
:
default
:
if
trie
.
IsEmpty
()
{
if
trie
.
IsEmpty
()
{
b0
,
b1
:=
trie
.
Branch
[
0
],
trie
.
Branch
[
1
]
b0
,
b1
:=
trie
.
Branch
[
0
],
trie
.
Branch
[
1
]
b0
.
C
heckInvariant
()
b0
.
c
heckInvariant
(
depth
+
1
,
pathSoFar
.
Push
(
0
)
)
b1
.
C
heckInvariant
()
b1
.
c
heckInvariant
(
depth
+
1
,
pathSoFar
.
Push
(
1
)
)
switch
{
switch
{
case
b0
.
IsEmptyLeaf
()
&&
b1
.
IsEmptyLeaf
()
:
case
b0
.
IsEmptyLeaf
()
&&
b1
.
IsEmptyLeaf
()
:
panic
(
"intermediate node with two empty leaves"
)
panic
(
"intermediate node with two empty leaves"
)
...
@@ -23,3 +34,60 @@ func (trie *Trie) CheckInvariant() {
...
@@ -23,3 +34,60 @@ func (trie *Trie) CheckInvariant() {
}
}
}
}
}
}
type
triePath
struct
{
parent
*
triePath
bit
byte
}
func
(
p
*
triePath
)
Push
(
bit
byte
)
*
triePath
{
return
&
triePath
{
parent
:
p
,
bit
:
bit
}
}
func
(
p
*
triePath
)
RootPath
()
[]
byte
{
if
p
==
nil
{
return
nil
}
else
{
return
append
(
p
.
parent
.
RootPath
(),
p
.
bit
)
}
}
func
(
p
*
triePath
)
matchesKey
(
k
key
.
Key
)
bool
{
// Slower, but more explicit:
for
i
,
b
:=
range
p
.
RootPath
()
{
if
k
.
BitAt
(
i
)
!=
b
{
return
false
}
}
return
true
// ok, _ := p.matchesKeyWalk(k, 0)
// return ok
}
func
(
p
*
triePath
)
matchesKeyWalk
(
k
key
.
Key
,
depthToLeaf
int
)
(
ok
bool
,
depthToRoot
int
)
{
if
p
==
nil
{
return
true
,
0
}
else
{
parOk
,
parDepthToRoot
:=
p
.
parent
.
matchesKeyWalk
(
k
,
depthToLeaf
+
1
)
return
k
.
BitAt
(
parDepthToRoot
+
1
)
==
p
.
bit
&&
parOk
,
parDepthToRoot
+
1
}
}
func
(
p
*
triePath
)
String
()
string
{
return
p
.
string
(
0
)
}
func
(
p
*
triePath
)
string
(
depthToLeaf
int
)
string
{
if
p
==
nil
{
return
""
}
else
{
switch
{
case
p
.
bit
==
0
:
return
p
.
parent
.
string
(
depthToLeaf
+
1
)
+
"0"
case
p
.
bit
==
1
:
return
p
.
parent
.
string
(
depthToLeaf
+
1
)
+
"1"
default
:
panic
(
"bit digit > 1"
)
}
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment