v2 / vlib / v / gen / js / sourcemap / vlq / vlq.v
113 lines · 97 sloc · 2.74 KB · 008aaad99981918c51194d7aaaaaccb4c258f244
Raw
1module vlq
2
3import io
4
5const shift = u8(5)
6const mask = u8((1 << shift) - 1)
7const continued = u8(1 << shift)
8const max_i64 = u64(9223372036854775807)
9
10// index start is: byte - vlq.enc_char_special_plus
11const enc_index = [62, 0, 0, 0, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0, 0, 0, 0, 0, 0, 0,
12 0, 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,
13 0, 0, 0, 0, 0, 0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
14 45, 46, 47, 48, 49, 50, 51]!
15
16const enc_table = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
17
18const enc_char_start_au = 65
19const enc_char_end_zu = 90
20const enc_char_start_al = 97
21const enc_char_end_zl = 122
22const enc_char_start_zero = 48
23const enc_char_end_nine = 57
24const enc_char_special_plus = 43
25const enc_char_special_slash = 47
26
27@[inline]
28fn abs64(x i64) u64 {
29 return if x < 0 { u64(-x) } else { u64(x) }
30}
31
32// Decode a single base64 digit.
33@[inline]
34fn decode64(input u8) u8 {
35 $if debug {
36 assert input >= enc_char_special_plus
37 assert input <= enc_char_end_zl
38 }
39 return u8(enc_index[input - enc_char_special_plus])
40}
41
42// Decode a single VLQ value from the input stream, returning the value.
43//
44// # Range
45//
46// Supports all numbers that can be represented by a sign bit and a 63 bit
47// absolute value: `[-(2^63 - 1), 2^63 - 1]`.
48//
49// Note that `i64::MIN = -(2^63)` cannot be represented in that form, and this
50// NOT IMPLEMENTED: function will return `Error::Overflowed` when attempting to decode it.
51pub fn decode(mut input io.Reader) !i64 {
52 mut buf := []u8{len: 1}
53
54 mut accum := u64(0)
55 mut shifter := 0
56 mut digit := u8(0)
57
58 mut keep_going := true
59 for keep_going {
60 len := input.read(mut buf) or { return error('Unexpected EOF') }
61 if len == 0 {
62 return error('no content')
63 }
64 digit = decode64(buf[0])
65 keep_going = (digit & continued) != 0
66
67 digit_value := u64(digit & mask) << u32(shifter) // TODO: check Overflow
68
69 accum += digit_value
70 shifter += shift
71 }
72
73 abs_value := accum / 2
74 if abs_value > max_i64 {
75 return error('Overflow')
76 }
77
78 // The low bit holds the sign.
79 return if (accum & 1) != 0 { (-i64(abs_value)) } else { i64(abs_value) }
80}
81
82@[inline]
83fn encode64(input u8) u8 {
84 $if debug {
85 assert input < 64
86 }
87 return enc_table[input]
88}
89
90// Encode a value as Base64 VLQ, sending it to the writer
91pub fn encode(value i64, mut output io.Writer) ! {
92 signed := value < 0
93 mut value_u64 := abs64(value) << 1
94 if signed {
95 if value_u64 == 0 {
96 // Wrapped
97 value_u64 = max_i64 + 1
98 }
99 value_u64 |= 1
100 }
101 for {
102 mut digit := u8(value_u64) & mask
103 value_u64 >>= shift
104 if value_u64 > 0 {
105 digit |= continued
106 }
107 bytes := [encode64(digit)]
108 output.write(bytes) or { return error('Write failed') }
109 if value_u64 == 0 {
110 break
111 }
112 }
113}
114