-
Notifications
You must be signed in to change notification settings - Fork 5
/
util.go
109 lines (96 loc) · 2.76 KB
/
util.go
1
2
3
4
5
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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
package builder
import (
"fmt"
"io"
"math/bits"
"github.com/ipld/go-ipld-prime"
"github.com/ipld/go-ipld-prime/codec"
"github.com/ipld/go-ipld-prime/datamodel"
)
// Common code from go-unixfs/hamt/util.go
// hashBits is a helper for pulling out sections of a hash
type hashBits []byte
func mkmask(n int) byte {
return (1 << uint(n)) - 1
}
// Slice returns the 'width' bits of the hashBits value as an integer, or an
// error if there aren't enough bits.
func (hb hashBits) Slice(offset, width int) (int, error) {
if offset+width > len(hb)*8 {
return 0, fmt.Errorf("sharded directory too deep")
}
return hb.slice(offset, width), nil
}
func (hb hashBits) slice(offset, width int) int {
curbi := offset / 8
leftb := 8 - (offset % 8)
curb := hb[curbi]
if width == leftb {
out := int(mkmask(width) & curb)
return out
} else if width < leftb {
a := curb & mkmask(leftb) // mask out the high bits we don't want
b := a & ^mkmask(leftb-width) // mask out the low bits we don't want
c := b >> uint(leftb-width) // shift whats left down
return int(c)
} else {
out := int(mkmask(leftb) & curb)
out <<= uint(width - leftb)
out += hb.slice(offset+leftb, width-leftb)
return out
}
}
func logtwo(v int) (int, error) {
if v <= 0 {
return 0, fmt.Errorf("hamt size should be a power of two")
}
lg2 := bits.TrailingZeros(uint(v))
if 1<<uint(lg2) != v {
return 0, fmt.Errorf("hamt size should be a power of two")
}
return lg2, nil
}
func sizedStore(ls *ipld.LinkSystem, lp datamodel.LinkPrototype, n datamodel.Node) (datamodel.Link, uint64, error) {
var byteCount int
lnk, err := wrappedLinkSystem(ls, func(bc int) {
byteCount = bc
}).Store(ipld.LinkContext{}, lp, n)
return lnk, uint64(byteCount), err
}
type byteCounter struct {
w io.Writer
bc int
}
func (bc *byteCounter) Write(p []byte) (int, error) {
bc.bc += len(p)
return bc.w.Write(p)
}
func wrappedLinkSystem(ls *ipld.LinkSystem, byteCountCb func(byteCount int)) *ipld.LinkSystem {
wrappedEncoder := func(encoder codec.Encoder) codec.Encoder {
return func(node datamodel.Node, writer io.Writer) error {
bc := byteCounter{w: writer}
err := encoder(node, &bc)
if err == nil {
byteCountCb(bc.bc)
}
return err
}
}
wrappedEncoderChooser := func(lp datamodel.LinkPrototype) (codec.Encoder, error) {
encoder, err := ls.EncoderChooser(lp)
if err != nil {
return nil, err
}
return wrappedEncoder(encoder), nil
}
return &ipld.LinkSystem{
EncoderChooser: wrappedEncoderChooser,
DecoderChooser: ls.DecoderChooser,
HasherChooser: ls.HasherChooser,
StorageWriteOpener: ls.StorageWriteOpener,
StorageReadOpener: ls.StorageReadOpener,
TrustedStorage: ls.TrustedStorage,
NodeReifier: ls.NodeReifier,
KnownReifiers: ls.KnownReifiers,
}
}