Skip to content

Commit 3caa1b7

Browse files
authored
encoding.binary: use unions for small speed increase and readability (#25867)
1 parent e07eb54 commit 3caa1b7

File tree

5 files changed

+440
-146
lines changed

5 files changed

+440
-146
lines changed

vlib/encoding/binary/big_endian.v

Lines changed: 146 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,31 @@ module binary
77
@[direct_array_access; inline]
88
pub fn big_endian_u16(b []u8) u16 {
99
_ = b[1] // bounds check
10-
return u16(b[1]) | (u16(b[0]) << u16(8))
10+
unsafe {
11+
mut u := U16{}
12+
$if big_endian {
13+
u.b[0], u.b[1] = b[0], b[1]
14+
} $else {
15+
u.b[0], u.b[1] = b[1], b[0]
16+
}
17+
return u.u
18+
}
1119
}
1220

1321
// big_endian_u16_at creates a u16 from two bytes in the array b at the specified offset in big endian order.
1422
@[direct_array_access; inline]
1523
pub fn big_endian_u16_at(b []u8, o int) u16 {
1624
_ = b[o] // bounds check
1725
_ = b[o + 1] // bounds check
18-
return u16(b[o + 1]) | (u16(b[o]) << u16(8))
26+
unsafe {
27+
mut u := U16{}
28+
$if big_endian {
29+
u.b[0], u.b[1] = b[o], b[o + 1]
30+
} $else {
31+
u.b[0], u.b[1] = b[o + 1], b[o]
32+
}
33+
return u.u
34+
}
1935
}
2036

2137
// big_endian_u16_end creates a u16 from two bytes in the array b at the specified offset in big endian order.
@@ -28,17 +44,33 @@ pub fn big_endian_u16_end(b []u8) u16 {
2844
@[direct_array_access; inline]
2945
pub fn big_endian_put_u16(mut b []u8, v u16) {
3046
_ = b[1] // bounds check
31-
b[0] = u8(v >> u16(8))
32-
b[1] = u8(v)
47+
unsafe {
48+
mut u := U16{
49+
u: v
50+
}
51+
$if big_endian {
52+
b[0], b[1] = u.b[0], u.b[1]
53+
} $else {
54+
b[0], b[1] = u.b[1], u.b[0]
55+
}
56+
}
3357
}
3458

3559
// big_endian_put_u16_at writes a u16 to the two bytes in the array b at the specified offset in big endian order.
3660
@[direct_array_access; inline]
3761
pub fn big_endian_put_u16_at(mut b []u8, v u16, o int) {
3862
_ = b[o] // bounds check
3963
_ = b[o + 1] // bounds check
40-
b[o] = u8(v >> u16(8))
41-
b[o + 1] = u8(v)
64+
unsafe {
65+
mut u := U16{
66+
u: v
67+
}
68+
$if big_endian {
69+
b[o], b[o + 1] = u.b[0], u.b[1]
70+
} $else {
71+
b[o], b[o + 1] = u.b[1], u.b[0]
72+
}
73+
}
4274
}
4375

4476
// big_endian_put_u16_end writes a u16 to the last two bytes in the array b in big endian order.
@@ -48,26 +80,48 @@ pub fn big_endian_put_u16_end(mut b []u8, v u16) {
4880
}
4981

5082
// big_endian_get_u16 creates u8 array from the unsigned 16-bit integer v in big endian order.
83+
@[direct_array_access; inline]
5184
pub fn big_endian_get_u16(v u16) []u8 {
52-
mut b := []u8{len: 2}
53-
b[0] = u8(v >> u16(8))
54-
b[1] = u8(v)
55-
return b
85+
unsafe {
86+
mut u := U16{
87+
u: v
88+
}
89+
$if little_endian {
90+
u.b[0], u.b[1] = u.b[1], u.b[0]
91+
}
92+
return u.b[..]
93+
}
5694
}
5795

5896
// big_endian_u32 creates a u32 from four bytes in the array b in big endian order.
5997
@[direct_array_access; inline]
6098
pub fn big_endian_u32(b []u8) u32 {
6199
_ = b[3] // bounds check
62-
return u32(b[3]) | (u32(b[2]) << u32(8)) | (u32(b[1]) << u32(16)) | (u32(b[0]) << u32(24))
100+
unsafe {
101+
mut u := U32{}
102+
$if big_endian {
103+
u.b[0], u.b[1], u.b[2], u.b[3] = b[0], b[1], b[2], b[3]
104+
} $else {
105+
u.b[0], u.b[1], u.b[2], u.b[3] = b[3], b[2], b[1], b[0]
106+
}
107+
return u.u
108+
}
63109
}
64110

65111
// big_endian_u32_at creates a u32 from four bytes in the array b at the specified offset in big endian order.
66112
@[direct_array_access; inline]
67113
pub fn big_endian_u32_at(b []u8, o int) u32 {
68114
_ = b[o] // bounds check
69115
_ = b[o + 3] // bounds check
70-
return u32(b[o + 3]) | (u32(b[o + 2]) << u32(8)) | (u32(b[o + 1]) << u32(16)) | (u32(b[o]) << u32(24))
116+
unsafe {
117+
mut u := U32{}
118+
$if big_endian {
119+
u.b[0], u.b[1], u.b[2], u.b[3] = b[o], b[o + 1], b[o + 2], b[o + 3]
120+
} $else {
121+
u.b[0], u.b[1], u.b[2], u.b[3] = b[o + 3], b[o + 2], b[o + 1], b[o]
122+
}
123+
return u.u
124+
}
71125
}
72126

73127
// big_endian_u32_end creates a u32 from the last four bytes in the array b in big endian order.
@@ -80,21 +134,33 @@ pub fn big_endian_u32_end(b []u8) u32 {
80134
@[direct_array_access; inline]
81135
pub fn big_endian_put_u32(mut b []u8, v u32) {
82136
_ = b[3] // bounds check
83-
b[0] = u8(v >> u32(24))
84-
b[1] = u8(v >> u32(16))
85-
b[2] = u8(v >> u32(8))
86-
b[3] = u8(v)
137+
unsafe {
138+
mut u := U32{
139+
u: v
140+
}
141+
$if big_endian {
142+
b[0], b[1], b[2], b[3] = u.b[0], u.b[1], u.b[2], u.b[3]
143+
} $else {
144+
b[0], b[1], b[2], b[3] = u.b[3], u.b[2], u.b[1], u.b[0]
145+
}
146+
}
87147
}
88148

89149
// big_endian_put_u32_at writes a u32 to four bytes in the array b at the specified offset in big endian order.
90150
@[direct_array_access; inline]
91151
pub fn big_endian_put_u32_at(mut b []u8, v u32, o int) {
92152
_ = b[o] // bounds check
93153
_ = b[o + 3] // bounds check
94-
b[o] = u8(v >> u32(24))
95-
b[o + 1] = u8(v >> u32(16))
96-
b[o + 2] = u8(v >> u32(8))
97-
b[o + 3] = u8(v)
154+
unsafe {
155+
mut u := U32{
156+
u: v
157+
}
158+
$if big_endian {
159+
b[o], b[o + 1], b[o + 2], b[o + 3] = u.b[0], u.b[1], u.b[2], u.b[3]
160+
} $else {
161+
b[o], b[o + 1], b[o + 2], b[o + 3] = u.b[3], u.b[2], u.b[1], u.b[0]
162+
}
163+
}
98164
}
99165

100166
// big_endian_put_u32_end writes a u32 to the last four bytes in the array b in big endian order.
@@ -104,29 +170,50 @@ pub fn big_endian_put_u32_end(mut b []u8, v u32) {
104170
}
105171

106172
// big_endian_get_u32 creates u8 array from the unsigned 32-bit integer v in big endian order.
173+
@[direct_array_access; inline]
107174
pub fn big_endian_get_u32(v u32) []u8 {
108-
mut b := []u8{len: 4}
109-
b[0] = u8(v >> u32(24))
110-
b[1] = u8(v >> u32(16))
111-
b[2] = u8(v >> u32(8))
112-
b[3] = u8(v)
113-
return b
175+
unsafe {
176+
mut u := U32{
177+
u: v
178+
}
179+
$if little_endian {
180+
u.b[0], u.b[1], u.b[2], u.b[3] = u.b[3], u.b[2], u.b[1], u.b[0]
181+
}
182+
return u.b[..]
183+
}
114184
}
115185

116186
// big_endian_u64 creates a u64 from the first eight bytes in the array b in big endian order.
117187
@[direct_array_access; inline]
118188
pub fn big_endian_u64(b []u8) u64 {
119189
_ = b[7] // bounds check
120-
return u64(b[7]) | (u64(b[6]) << u64(8)) | (u64(b[5]) << u64(16)) | (u64(b[4]) << u64(24)) | (u64(b[3]) << u64(32)) | (u64(b[2]) << u64(40)) | (u64(b[1]) << u64(48)) | (u64(b[0]) << u64(56))
190+
unsafe {
191+
mut u := U64{}
192+
$if big_endian {
193+
u.b[0], u.b[1], u.b[2], u.b[3], u.b[4], u.b[5], u.b[6], u.b[7] = b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]
194+
} $else {
195+
u.b[0], u.b[1], u.b[2], u.b[3], u.b[4], u.b[5], u.b[6], u.b[7] = b[7], b[6], b[5], b[4], b[3], b[2], b[1], b[0]
196+
}
197+
return u.u
198+
}
121199
}
122200

123201
// big_endian_u64_at creates a u64 from eight bytes in the array b at the specified offset in big endian order.
124202
@[direct_array_access; inline]
125203
pub fn big_endian_u64_at(b []u8, o int) u64 {
126204
_ = b[o] // bounds check
127205
_ = b[o + 7] // bounds check
128-
return u64(b[o + 7]) | (u64(b[o + 6]) << u64(8)) | (u64(b[o + 5]) << u64(16)) | (u64(b[o + 4]) << u64(24)) | (u64(b[
129-
o + 3]) << u64(32)) | (u64(b[o + 2]) << u64(40)) | (u64(b[o + 1]) << u64(48)) | (u64(b[o]) << u64(56))
206+
unsafe {
207+
mut u := U64{}
208+
$if big_endian {
209+
u.b[0], u.b[1], u.b[2], u.b[3], u.b[4], u.b[5], u.b[6], u.b[7] = b[o], b[o + 1], b[o + 2], b[
210+
o + 3], b[o + 4], b[o + 5], b[o + 6], b[o + 7]
211+
} $else {
212+
u.b[0], u.b[1], u.b[2], u.b[3], u.b[4], u.b[5], u.b[6], u.b[7] = b[o + 7], b[o + 6], b[
213+
o + 5], b[o + 4], b[o + 3], b[o + 2], b[o + 1], b[o]
214+
}
215+
return u.u
216+
}
130217
}
131218

132219
// big_endian_u64_end creates a u64 from the last eight bytes in the array b in big endian order.
@@ -139,29 +226,33 @@ pub fn big_endian_u64_end(b []u8) u64 {
139226
@[direct_array_access; inline]
140227
pub fn big_endian_put_u64(mut b []u8, v u64) {
141228
_ = b[7] // bounds check
142-
b[0] = u8(v >> u64(56))
143-
b[1] = u8(v >> u64(48))
144-
b[2] = u8(v >> u64(40))
145-
b[3] = u8(v >> u64(32))
146-
b[4] = u8(v >> u64(24))
147-
b[5] = u8(v >> u64(16))
148-
b[6] = u8(v >> u64(8))
149-
b[7] = u8(v)
229+
unsafe {
230+
mut u := U64{
231+
u: v
232+
}
233+
$if big_endian {
234+
b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7] = u.b[0], u.b[1], u.b[2], u.b[3], u.b[4], u.b[5], u.b[6], u.b[7]
235+
} $else {
236+
b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7] = u.b[7], u.b[6], u.b[5], u.b[4], u.b[3], u.b[2], u.b[1], u.b[0]
237+
}
238+
}
150239
}
151240

152241
// big_endian_put_u64_at writes a u64 to eight bytes in the array b at the specified offset in big endian order.
153242
@[direct_array_access; inline]
154243
pub fn big_endian_put_u64_at(mut b []u8, v u64, o int) {
155244
_ = b[o] // bounds check
156245
_ = b[o + 7] // bounds check
157-
b[o] = u8(v >> u64(56))
158-
b[o + 1] = u8(v >> u64(48))
159-
b[o + 2] = u8(v >> u64(40))
160-
b[o + 3] = u8(v >> u64(32))
161-
b[o + 4] = u8(v >> u64(24))
162-
b[o + 5] = u8(v >> u64(16))
163-
b[o + 6] = u8(v >> u64(8))
164-
b[o + 7] = u8(v)
246+
unsafe {
247+
mut u := U64{
248+
u: v
249+
}
250+
$if big_endian {
251+
b[o], b[o + 1], b[o + 2], b[o + 3], b[o + 4], b[o + 5], b[o + 6], b[o + 7] = u.b[0], u.b[1], u.b[2], u.b[3], u.b[4], u.b[5], u.b[6], u.b[7]
252+
} $else {
253+
b[o], b[o + 1], b[o + 2], b[o + 3], b[o + 4], b[o + 5], b[o + 6], b[o + 7] = u.b[7], u.b[6], u.b[5], u.b[4], u.b[3], u.b[2], u.b[1], u.b[0]
254+
}
255+
}
165256
}
166257

167258
// big_endian_put_u64_end writes a u64 to the last eight bytes in the array b at the specified offset in big endian order.
@@ -171,15 +262,15 @@ pub fn big_endian_put_u64_end(mut b []u8, v u64) {
171262
}
172263

173264
// big_endian_get_u64 creates u8 array from the unsigned 64-bit integer v in big endian order.
265+
@[direct_array_access; inline]
174266
pub fn big_endian_get_u64(v u64) []u8 {
175-
mut b := []u8{len: 8}
176-
b[0] = u8(v >> u64(56))
177-
b[1] = u8(v >> u64(48))
178-
b[2] = u8(v >> u64(40))
179-
b[3] = u8(v >> u64(32))
180-
b[4] = u8(v >> u64(24))
181-
b[5] = u8(v >> u64(16))
182-
b[6] = u8(v >> u64(8))
183-
b[7] = u8(v)
184-
return b
267+
unsafe {
268+
mut u := U64{
269+
u: v
270+
}
271+
$if little_endian {
272+
u.b[0], u.b[1], u.b[2], u.b[3], u.b[4], u.b[5], u.b[6], u.b[7] = u.b[7], u.b[6], u.b[5], u.b[4], u.b[3], u.b[2], u.b[1], u.b[0]
273+
}
274+
return u.b[..]
275+
}
185276
}

0 commit comments

Comments
 (0)