Skip to content

Commit c9dc182

Browse files
Add variable-length-quantity exercise (#48)
1 parent b2f7222 commit c9dc182

File tree

7 files changed

+378
-0
lines changed

7 files changed

+378
-0
lines changed

config.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,14 @@
326326
"prerequisites": [],
327327
"difficulty": 5
328328
},
329+
{
330+
"slug": "variable-length-quantity",
331+
"name": "Variable Length Quantity",
332+
"uuid": "72798afc-0408-4cac-ab99-b4952942bd2e",
333+
"practices": [],
334+
"prerequisites": [],
335+
"difficulty": 5
336+
},
329337
{
330338
"slug": "intergalactic-transmission",
331339
"name": "Intergalactic Transmission",
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# Instructions
2+
3+
Implement variable length quantity encoding and decoding.
4+
5+
The goal of this exercise is to implement [VLQ][vlq] encoding/decoding.
6+
7+
In short, the goal of this encoding is to encode integer values in a way that would save bytes.
8+
Only the first 7 bits of each byte are significant (right-justified; sort of like an ASCII byte).
9+
So, if you have a 32-bit value, you have to unpack it into a series of 7-bit bytes.
10+
Of course, you will have a variable number of bytes depending upon your integer.
11+
To indicate which is the last byte of the series, you leave bit #7 clear.
12+
In all of the preceding bytes, you set bit #7.
13+
14+
So, if an integer is between `0-127`, it can be represented as one byte.
15+
Although VLQ can deal with numbers of arbitrary sizes, for this exercise we will restrict ourselves to only numbers that fit in a 32-bit unsigned integer.
16+
Here are examples of integers as 32-bit values, and the variable length quantities that they translate to:
17+
18+
```text
19+
NUMBER VARIABLE QUANTITY
20+
00000000 00
21+
00000040 40
22+
0000007F 7F
23+
00000080 81 00
24+
00002000 C0 00
25+
00003FFF FF 7F
26+
00004000 81 80 00
27+
00100000 C0 80 00
28+
001FFFFF FF FF 7F
29+
00200000 81 80 80 00
30+
08000000 C0 80 80 00
31+
0FFFFFFF FF FF FF 7F
32+
```
33+
34+
[vlq]: https://en.wikipedia.org/wiki/Variable-length_quantity
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"authors": [
3+
"keiravillekode"
4+
],
5+
"files": {
6+
"solution": [
7+
"variable_length_quantity.fut"
8+
],
9+
"test": [
10+
"test.fut"
11+
],
12+
"example": [
13+
".meta/example.fut"
14+
]
15+
},
16+
"blurb": "Implement variable length quantity encoding and decoding.",
17+
"source": "A poor Splice developer having to implement MIDI encoding/decoding.",
18+
"source_url": "https://splice.com"
19+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
def encode [n] (integers: [n]u32): []i32 =
2+
let capacity = n * 5
3+
let (a, i) = loop (a, i) = (replicate capacity 0i32, capacity) for integer in reverse integers do
4+
let (a2, i2, _) = loop (a2, i2, current) = (a with [i - 1] = 0x7f & i32.u32 integer, i - 1, integer >> 7) while current != 0 do
5+
(a2 with [i2 - 1] = 0x80 | (0x7f & i32.u32 current), i2 - 1, current >> 7)
6+
in
7+
(a2, i2)
8+
in
9+
a[i:]
10+
11+
def decode [n] (integers: [n]i32): []u32 =
12+
let (a, i, _, complete) = loop (a, i, current, _) = (replicate n 0u32, 0, 0u32, true) for integer in integers do
13+
let current2 = current | (0x7f & u32.i32 integer)
14+
in
15+
if (integer & 0x80) != 0 then (a, i, current2 << 7, false) else
16+
(a with [i] = current2, i + 1, 0u32, true)
17+
in
18+
assert (complete) a[0:i]
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
# This is an auto-generated file.
2+
#
3+
# Regenerating this file via `configlet sync` will:
4+
# - Recreate every `description` key/value pair
5+
# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications
6+
# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion)
7+
# - Preserve any other key/value pair
8+
#
9+
# As user-added comments (using the # character) will be removed when this file
10+
# is regenerated, comments can be added via a `comment` key.
11+
12+
[35c9db2e-f781-4c52-b73b-8e76427defd0]
13+
description = "Encode a series of integers, producing a series of bytes. -> zero"
14+
15+
[be44d299-a151-4604-a10e-d4b867f41540]
16+
description = "Encode a series of integers, producing a series of bytes. -> arbitrary single byte"
17+
18+
[890bc344-cb80-45af-b316-6806a6971e81]
19+
description = "Encode a series of integers, producing a series of bytes. -> asymmetric single byte"
20+
21+
[ea399615-d274-4af6-bbef-a1c23c9e1346]
22+
description = "Encode a series of integers, producing a series of bytes. -> largest single byte"
23+
24+
[77b07086-bd3f-4882-8476-8dcafee79b1c]
25+
description = "Encode a series of integers, producing a series of bytes. -> smallest double byte"
26+
27+
[63955a49-2690-4e22-a556-0040648d6b2d]
28+
description = "Encode a series of integers, producing a series of bytes. -> arbitrary double byte"
29+
30+
[4977d113-251b-4d10-a3ad-2f5a7756bb58]
31+
description = "Encode a series of integers, producing a series of bytes. -> asymmetric double byte"
32+
33+
[29da7031-0067-43d3-83a7-4f14b29ed97a]
34+
description = "Encode a series of integers, producing a series of bytes. -> largest double byte"
35+
36+
[3345d2e3-79a9-4999-869e-d4856e3a8e01]
37+
description = "Encode a series of integers, producing a series of bytes. -> smallest triple byte"
38+
39+
[5df0bc2d-2a57-4300-a653-a75ee4bd0bee]
40+
description = "Encode a series of integers, producing a series of bytes. -> arbitrary triple byte"
41+
42+
[6731045f-1e00-4192-b5ae-98b22e17e9f7]
43+
description = "Encode a series of integers, producing a series of bytes. -> asymmetric triple byte"
44+
45+
[f51d8539-312d-4db1-945c-250222c6aa22]
46+
description = "Encode a series of integers, producing a series of bytes. -> largest triple byte"
47+
48+
[da78228b-544f-47b7-8bfe-d16b35bbe570]
49+
description = "Encode a series of integers, producing a series of bytes. -> smallest quadruple byte"
50+
51+
[11ed3469-a933-46f1-996f-2231e05d7bb6]
52+
description = "Encode a series of integers, producing a series of bytes. -> arbitrary quadruple byte"
53+
54+
[b45ef770-cbba-48c2-bd3c-c6362679516e]
55+
description = "Encode a series of integers, producing a series of bytes. -> asymmetric quadruple byte"
56+
57+
[d5f3f3c3-e0f1-4e7f-aad0-18a44f223d1c]
58+
description = "Encode a series of integers, producing a series of bytes. -> largest quadruple byte"
59+
60+
[91a18b33-24e7-4bfb-bbca-eca78ff4fc47]
61+
description = "Encode a series of integers, producing a series of bytes. -> smallest quintuple byte"
62+
63+
[5f34ff12-2952-4669-95fe-2d11b693d331]
64+
description = "Encode a series of integers, producing a series of bytes. -> arbitrary quintuple byte"
65+
66+
[9be46731-7cd5-415c-b960-48061cbc1154]
67+
description = "Encode a series of integers, producing a series of bytes. -> asymmetric quintuple byte"
68+
69+
[7489694b-88c3-4078-9864-6fe802411009]
70+
description = "Encode a series of integers, producing a series of bytes. -> maximum 32-bit integer input"
71+
72+
[f9b91821-cada-4a73-9421-3c81d6ff3661]
73+
description = "Encode a series of integers, producing a series of bytes. -> two single-byte values"
74+
75+
[68694449-25d2-4974-ba75-fa7bb36db212]
76+
description = "Encode a series of integers, producing a series of bytes. -> two multi-byte values"
77+
78+
[51a06b5c-de1b-4487-9a50-9db1b8930d85]
79+
description = "Encode a series of integers, producing a series of bytes. -> many multi-byte values"
80+
81+
[baa73993-4514-4915-bac0-f7f585e0e59a]
82+
description = "Decode a series of bytes, producing a series of integers. -> one byte"
83+
84+
[72e94369-29f9-46f2-8c95-6c5b7a595aee]
85+
description = "Decode a series of bytes, producing a series of integers. -> two bytes"
86+
87+
[df5a44c4-56f7-464e-a997-1db5f63ce691]
88+
description = "Decode a series of bytes, producing a series of integers. -> three bytes"
89+
90+
[1bb58684-f2dc-450a-8406-1f3452aa1947]
91+
description = "Decode a series of bytes, producing a series of integers. -> four bytes"
92+
93+
[cecd5233-49f1-4dd1-a41a-9840a40f09cd]
94+
description = "Decode a series of bytes, producing a series of integers. -> maximum 32-bit integer"
95+
96+
[e7d74ba3-8b8e-4bcb-858d-d08302e15695]
97+
description = "Decode a series of bytes, producing a series of integers. -> incomplete sequence causes error"
98+
99+
[aa378291-9043-4724-bc53-aca1b4a3fcb6]
100+
description = "Decode a series of bytes, producing a series of integers. -> incomplete sequence causes error, even if value is zero"
101+
102+
[a91e6f5a-c64a-48e3-8a75-ce1a81e0ebee]
103+
description = "Decode a series of bytes, producing a series of integers. -> multiple values"
Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
import "variable_length_quantity"
2+
3+
-- zero
4+
-- ==
5+
-- entry: test_encode
6+
-- input { [0u32] }
7+
-- output { [0] }
8+
9+
-- arbitrary single byte
10+
-- ==
11+
-- entry: test_encode
12+
-- input { [64u32] }
13+
-- output { [64] }
14+
15+
-- asymmetric single byte
16+
-- ==
17+
-- entry: test_encode
18+
-- input { [83u32] }
19+
-- output { [83] }
20+
21+
-- largest single byte
22+
-- ==
23+
-- entry: test_encode
24+
-- input { [127u32] }
25+
-- output { [127] }
26+
27+
-- smallest double byte
28+
-- ==
29+
-- entry: test_encode
30+
-- input { [128u32] }
31+
-- output { [129, 0] }
32+
33+
-- arbitrary double byte
34+
-- ==
35+
-- entry: test_encode
36+
-- input { [8192u32] }
37+
-- output { [192, 0] }
38+
39+
-- asymmetric double byte
40+
-- ==
41+
-- entry: test_encode
42+
-- input { [173u32] }
43+
-- output { [129, 45] }
44+
45+
-- largest double byte
46+
-- ==
47+
-- entry: test_encode
48+
-- input { [16383u32] }
49+
-- output { [255, 127] }
50+
51+
-- smallest triple byte
52+
-- ==
53+
-- entry: test_encode
54+
-- input { [16384u32] }
55+
-- output { [129, 128, 0] }
56+
57+
-- arbitrary triple byte
58+
-- ==
59+
-- entry: test_encode
60+
-- input { [1048576u32] }
61+
-- output { [192, 128, 0] }
62+
63+
-- asymmetric triple byte
64+
-- ==
65+
-- entry: test_encode
66+
-- input { [120220u32] }
67+
-- output { [135, 171, 28] }
68+
69+
-- largest triple byte
70+
-- ==
71+
-- entry: test_encode
72+
-- input { [2097151u32] }
73+
-- output { [255, 255, 127] }
74+
75+
-- smallest quadruple byte
76+
-- ==
77+
-- entry: test_encode
78+
-- input { [2097152u32] }
79+
-- output { [129, 128, 128, 0] }
80+
81+
-- arbitrary quadruple byte
82+
-- ==
83+
-- entry: test_encode
84+
-- input { [134217728u32] }
85+
-- output { [192, 128, 128, 0] }
86+
87+
-- asymmetric quadruple byte
88+
-- ==
89+
-- entry: test_encode
90+
-- input { [3503876u32] }
91+
-- output { [129, 213, 238, 4] }
92+
93+
-- largest quadruple byte
94+
-- ==
95+
-- entry: test_encode
96+
-- input { [268435455u32] }
97+
-- output { [255, 255, 255, 127] }
98+
99+
-- smallest quintuple byte
100+
-- ==
101+
-- entry: test_encode
102+
-- input { [268435456u32] }
103+
-- output { [129, 128, 128, 128, 0] }
104+
105+
-- arbitrary quintuple byte
106+
-- ==
107+
-- entry: test_encode
108+
-- input { [4278190080u32] }
109+
-- output { [143, 248, 128, 128, 0] }
110+
111+
-- asymmetric quintuple byte
112+
-- ==
113+
-- entry: test_encode
114+
-- input { [2254790917u32] }
115+
-- output { [136, 179, 149, 194, 5] }
116+
117+
-- maximum 32-bit integer input
118+
-- ==
119+
-- entry: test_encode
120+
-- input { [4294967295u32] }
121+
-- output { [143, 255, 255, 255, 127] }
122+
123+
-- two single-byte values
124+
-- ==
125+
-- entry: test_encode
126+
-- input { [64u32, 127u32] }
127+
-- output { [64, 127] }
128+
129+
-- two multi-byte values
130+
-- ==
131+
-- entry: test_encode
132+
-- input { [16384u32, 1193046u32] }
133+
-- output { [129, 128, 0, 200, 232, 86] }
134+
135+
-- many multi-byte values
136+
-- ==
137+
-- entry: test_encode
138+
-- input { [8192u32, 1193046u32, 268435455u32, 0u32, 16383u32, 16384u32] }
139+
-- output { [192, 0, 200, 232, 86, 255, 255, 255, 127, 0, 255, 127, 129, 128, 0] }
140+
141+
-- one byte
142+
-- ==
143+
-- entry: test_decode
144+
-- input { [127] }
145+
-- output { [127u32] }
146+
147+
-- two bytes
148+
-- ==
149+
-- entry: test_decode
150+
-- input { [192, 0] }
151+
-- output { [8192u32] }
152+
153+
-- three bytes
154+
-- ==
155+
-- entry: test_decode
156+
-- input { [255, 255, 127] }
157+
-- output { [2097151u32] }
158+
159+
-- four bytes
160+
-- ==
161+
-- entry: test_decode
162+
-- input { [129, 128, 128, 0] }
163+
-- output { [2097152u32] }
164+
165+
-- maximum 32-bit integer
166+
-- ==
167+
-- entry: test_decode
168+
-- input { [143, 255, 255, 255, 127] }
169+
-- output { [4294967295u32] }
170+
171+
-- incomplete sequence causes error
172+
-- ==
173+
-- entry: test_decode
174+
-- input { [255] }
175+
-- error: Error*
176+
177+
-- incomplete sequence causes error, even if value is zero
178+
-- ==
179+
-- entry: test_decode
180+
-- input { [128] }
181+
-- error: Error*
182+
183+
-- multiple values
184+
-- ==
185+
-- entry: test_decode
186+
-- input { [192, 0, 200, 232, 86, 255, 255, 255, 127, 0, 255, 127, 129, 128, 0] }
187+
-- output { [8192u32, 1193046u32, 268435455u32, 0u32, 16383u32, 16384u32] }
188+
189+
entry test_encode (integers: []u32): []i32 =
190+
encode integers
191+
192+
entry test_decode (integers: []i32): []u32 =
193+
decode integers
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
def encode (integers: []u32): []i32 = ???
2+
3+
def decode (integers: []i32): []u32 = ???

0 commit comments

Comments
 (0)