-
-
Notifications
You must be signed in to change notification settings - Fork 111
/
address.go
217 lines (180 loc) · 5.94 KB
/
address.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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
package capnp
import (
"strconv"
"capnproto.org/go/capnp/v3/internal/str"
)
// An address is an index inside a segment's data (in bytes).
// It is bounded to [0, maxSegmentSize).
type address uint32
// String returns the address in hex format.
func (a address) String() string {
return strconv.FormatUint(uint64(a), 16)
}
// GoString returns the address in hex format.
func (a address) GoString() string {
return "capnp.address(%" + a.String() + ")"
}
// addSize returns the address a+sz. ok is false if the result would
// be an invalid address.
func (a address) addSize(sz Size) (_ address, ok bool) {
x := int64(a) + int64(sz)
if x > int64(maxSegmentSize) {
return 0xffffffff, false
}
return address(x), true
}
// addSizeUnchecked returns a+sz without any overflow checking.
func (a address) addSizeUnchecked(sz Size) address {
return a + address(sz)
}
// element returns the address a+i*sz. ok is false if the result would
// be an invalid address.
func (a address) element(i int32, sz Size) (_ address, ok bool) {
x := int64(a) + int64(i)*int64(sz)
if x > int64(maxSegmentSize) || x < 0 {
return 0xffffffff, false
}
return address(x), true
}
// addOffset returns the address a+o. It panics if o is invalid.
func (a address) addOffset(o DataOffset) address {
if o >= 1<<19 {
panic("data offset overflow")
}
return a + address(o)
}
// A Size is a size (in bytes).
type Size uint32
// wordSize is the number of bytes in a Cap'n Proto word.
const wordSize Size = 8
// String returns the size in the format "X bytes".
func (sz Size) String() string {
if sz == 1 {
return "1 byte"
}
return str.Utod(sz) + " bytes"
}
// GoString returns the size as a Go expression.
func (sz Size) GoString() string {
return "capnp.Size(" + str.Utod(sz) + ")"
}
// times returns the size sz*n. ok is false if the result would be
// greater than maxSegmentSize.
func (sz Size) times(n int32) (_ Size, ok bool) {
x := int64(sz) * int64(n)
if x > int64(maxSegmentSize) || x < 0 {
return 0xffffffff, false
}
return Size(x), true
}
// timesUnchecked returns sz*n without any overflow or negative checking.
func (sz Size) timesUnchecked(n int32) Size {
return sz * Size(n)
}
// padToWord adds padding to sz to make it divisible by wordSize.
// The result is undefined if sz > maxSegmentSize.
func (sz Size) padToWord() Size {
n := Size(wordSize - 1)
return (sz + n) &^ n
}
// maxSegmentSize is the largest size representable in the Cap'n Proto
// encoding.
const maxSegmentSize Size = 1<<32 - 8
// maxAllocSize returns the largest permitted size of a single segment
// on this platform.
//
// Converting between a Size and an int can overflow both ways: on
// systems where int is 32 bits, Size to int overflows, and on systems
// where int is 64 bits, int to Size overflows. Quantities less than
// or equal to maxAllocSize() will not overflow.
//
// This is effectively a compile-time constant, but can't be represented
// as a constant because it requires a conditional. It is trivially
// inlinable and optimizable, so should act like one.
func maxAllocSize() Size {
if maxInt == 0x7fffffff {
return Size(0x7ffffff8)
}
return maxSegmentSize
}
// DataOffset is an offset in bytes from the beginning of a struct's
// data section. It is bounded to [0, 1<<19).
type DataOffset uint32
// String returns the offset in the format "+X bytes".
func (off DataOffset) String() string {
if off == 1 {
return "+1 byte"
}
return "+" + str.Utod(off) + " bytes"
}
// GoString returns the offset as a Go expression.
func (off DataOffset) GoString() string {
return "capnp.DataOffset(" + str.Utod(off) + ")"
}
// ObjectSize records section sizes for a struct or list.
type ObjectSize struct {
DataSize Size // must be <= 1<<19 - 8
PointerCount uint16
}
// isZero reports whether sz is the zero size.
func (sz ObjectSize) isZero() bool {
return sz.DataSize == 0 && sz.PointerCount == 0
}
// isOneByte reports whether the object size is one byte (for Text/Data element sizes).
func (sz ObjectSize) isOneByte() bool {
return sz.DataSize == 1 && sz.PointerCount == 0
}
// isValid reports whether sz's fields are in range.
func (sz ObjectSize) isValid() bool {
return sz.DataSize <= 0xffff*wordSize
}
// pointerSize returns the number of bytes the pointer section occupies.
func (sz ObjectSize) pointerSize() Size {
// Guaranteed not to overflow
return wordSize * Size(sz.PointerCount)
}
// totalSize returns the number of bytes that the object occupies.
// The range is [0, 0xffff0].
func (sz ObjectSize) totalSize() Size {
return sz.DataSize + sz.pointerSize()
}
// dataWordCount returns the number of words in the data section.
func (sz ObjectSize) dataWordCount() int32 {
if sz.DataSize%wordSize != 0 {
panic("data size not aligned by word")
}
return int32(sz.DataSize / wordSize)
}
// totalWordCount returns the number of words that the object occupies.
func (sz ObjectSize) totalWordCount() int32 {
return sz.dataWordCount() + int32(sz.PointerCount)
}
// String returns a short, human readable representation of the object
// size.
func (sz ObjectSize) String() string {
return "{datasz=" + str.Utod(sz.DataSize) + " ptrs=" + str.Utod(sz.PointerCount) + "}"
}
// GoString formats the ObjectSize as a keyed struct literal.
func (sz ObjectSize) GoString() string {
return "capnp.ObjectSize{DataSize: " + str.Utod(sz.DataSize) +
", PointerCount: " + str.Utod(sz.PointerCount) + "}"
}
// BitOffset is an offset in bits from the beginning of a struct's data
// section. It is bounded to [0, 1<<22).
type BitOffset uint32
// offset returns the equivalent byte offset.
func (bit BitOffset) offset() DataOffset {
return DataOffset(bit / 8)
}
// mask returns the bitmask for the bit.
func (bit BitOffset) mask() byte {
return byte(1 << (bit % 8))
}
// String returns the offset in the format "bit X".
func (bit BitOffset) String() string {
return "bit " + str.Utod(bit)
}
// GoString returns the offset as a Go expression.
func (bit BitOffset) GoString() string {
return "capnp.BitOffset(" + str.Utod(bit) + ")"
}