Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

new exercise to encode/decode variable length quantity #322

Merged
merged 3 commits into from
Oct 2, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion config.json
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,8 @@
"word-search",
"connect",
"ledger",
"poker"
"poker",
"variable-length-quantity"
],
"deprecated": [
"accumulate",
Expand Down
56 changes: 56 additions & 0 deletions exercises/variable-length-quantity/example.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package variablelengthquantity
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The example.go should be a reference solution—something that passes the given test suite. It doesn't get delivered when people fetch the exercise, it's just used to make sure that the test suite makes sense.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh. Hah. I see that Ian said the same thing below.


// EncodeVarint returns the varint encoding of x.
func EncodeVarint(x uint32) []byte {
if x>>7 == 0 {
return []byte{
byte(x),
}
}

if x>>14 == 0 {
return []byte{
byte(0x80 | x>>7),
byte(127 & x),
}
}

if x>>21 == 0 {
return []byte{
byte(0x80 | x>>14),
byte(0x80 | x>>7),
byte(127 & x),
}
}

return []byte{
byte(0x80 | x>>21),
byte(0x80 | x>>14),
byte(0x80 | x>>7),
byte(127 & x),
}
}

// DecodeVarint reads a varint-encoded integer from the slice.
// It returns the integer and the number of bytes consumed, or
// zero if there is not enough.
func DecodeVarint(buf []byte) (x uint32, n int) {
if len(buf) < 1 {
return 0, 0
}

if buf[0] <= 0x80 {
return uint32(buf[0]), 1
}

var b byte
for n, b = range buf {
x = x << 7
x |= uint32(b) & 0x7F
if (b & 0x80) == 0 {
return x, n
}
}

return x, n
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package variablelengthquantity

import (
"bytes"
"testing"
)

func TestEncodeDecodeVarint(t *testing.T) {
testCases := []struct {
input []byte
output uint32
}{
0: {[]byte{0x7F}, 127},
1: {[]byte{0x81, 0x00}, 128},
2: {[]byte{0xC0, 0x00}, 8192},
3: {[]byte{0xFF, 0x7F}, 16383},
4: {[]byte{0x81, 0x80, 0x00}, 16384},
5: {[]byte{0xFF, 0xFF, 0x7F}, 2097151},
6: {[]byte{0x81, 0x80, 0x80, 0x00}, 2097152},
7: {[]byte{0xC0, 0x80, 0x80, 0x00}, 134217728},
8: {[]byte{0xFF, 0xFF, 0xFF, 0x7F}, 268435455},

9: {[]byte{0x82, 0x00}, 256},
10: {[]byte{0x81, 0x10}, 144},
}

for i, tc := range testCases {
t.Logf("test case %d - %#v\n", i, tc.input)
if o, _ := DecodeVarint(tc.input); o != tc.output {
Copy link
Member

@petertseng petertseng Apr 29, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, given that the second return value is being discarded, it could be anything.

Given that in the example implementation it's the number of bytes consumed, now I want to ponder a few things.

These tests expect a DecodeVarint that decodes a single number it finds in a buffer.

Should we specify (and therefore test) DecodeVarint's behavior:

  • If there are multiple numbers in the buffer? []byte{0x00, 0x00}
  • If there is not a complete number in the buffer? []byte{0x80, 0x80}
  • If the buffer is empty? (which may be a subcase of the "not a complete number in the buffer" case)

Also, as an extension of this funciton that decodes a single varint, should we ask for an implementation of a function that decodes as many numbers as possible from a buffer as well? It would expand the scope of the exercise, though!

t.Fatalf("expected %d\ngot\n%d\n", tc.output, o)
}
if encoded := EncodeVarint(tc.output); bytes.Compare(encoded, tc.input) != 0 {
t.Fatalf("%d - expected %#v\ngot\n%#v\n", tc.output, tc.input, encoded)
}
}
}